diff --git a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc index 26e8c083d..45c97b3da 100644 --- a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc +++ b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc @@ -90,6 +90,8 @@ public interface CarMapper { * Between Jodas `org.joda.time.LocalDateTime`, `org.joda.time.LocalDate` and `javax.xml.datatype.XMLGregorianCalendar`, `java.util.Date`. +* Between `java.time.LocalDate`, `java.time.LocalDateTime` and `javax.xml.datatype.XMLGregorianCalendar`. + * Between `java.time.ZonedDateTime`, `java.time.LocalDateTime`, `java.time.LocalDate`, `java.time.LocalTime` from Java 8 Date-Time package and `String`. A format string as understood by `java.text.SimpleDateFormat` can be specified via the `dateFormat` option (see above). * Between `java.time.Instant`, `java.time.Duration`, `java.time.Period` from Java 8 Date-Time package and `String` using the `parse` method in each class to map from `String` and using `toString` to map into `String`. diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMappingMethods.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMappingMethods.java index 5332651ab..4b096f803 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMappingMethods.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMappingMethods.java @@ -33,6 +33,10 @@ public class BuiltInMappingMethods { builtInMethods.add( new CalendarToXmlGregorianCalendar( typeFactory ) ); builtInMethods.add( new XmlGregorianCalendarToCalendar( typeFactory ) ); builtInMethods.add( new ZonedDateTimeToXmlGregorianCalendar( typeFactory ) ); + builtInMethods.add( new XmlGregorianCalendarToLocalDate( typeFactory ) ); + builtInMethods.add( new LocalDateToXmlGregorianCalendar( typeFactory ) ); + builtInMethods.add( new LocalDateTimeToXmlGregorianCalendar( typeFactory ) ); + builtInMethods.add( new XmlGregorianCalendarToLocalDateTime( typeFactory ) ); } if ( isJaxbAvailable( typeFactory ) ) { @@ -41,10 +45,6 @@ public class BuiltInMappingMethods { builtInMethods.add( new ZonedDateTimeToCalendar( typeFactory ) ); builtInMethods.add( new CalendarToZonedDateTime( typeFactory ) ); - if ( isXmlGregorianCalendarPresent ) { - builtInMethods.add( new XmlGregorianCalendarToLocalDate( typeFactory ) ); - builtInMethods.add( new LocalDateToXmlGregorianCalendar( typeFactory ) ); - } if ( isJodaTimeAvailable( typeFactory ) && isXmlGregorianCalendarPresent ) { builtInMethods.add( new JodaDateTimeToXmlGregorianCalendar( typeFactory ) ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMethod.java index 783ea43a5..bbfafcbfb 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/BuiltInMethod.java @@ -51,7 +51,7 @@ public abstract class BuiltInMethod implements Method { * @return the types used by this method for which import statements need to be generated */ public Set getImportTypes() { - return Collections.emptySet(); + return Collections.emptySet(); } /** diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/LocalDateTimeToXmlGregorianCalendar.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/LocalDateTimeToXmlGregorianCalendar.java new file mode 100644 index 000000000..8853c1aae --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/LocalDateTimeToXmlGregorianCalendar.java @@ -0,0 +1,49 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.internal.model.source.builtin; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoField; +import java.util.Set; + +import javax.xml.datatype.DatatypeConstants; + +import org.mapstruct.ap.internal.model.common.Parameter; +import org.mapstruct.ap.internal.model.common.Type; +import org.mapstruct.ap.internal.model.common.TypeFactory; + +import static org.mapstruct.ap.internal.util.Collections.asSet; + +/** + * @author Andrei Arlou + */ +public class LocalDateTimeToXmlGregorianCalendar extends AbstractToXmlGregorianCalendar { + + private final Parameter parameter; + private final Set importTypes; + + public LocalDateTimeToXmlGregorianCalendar(TypeFactory typeFactory) { + super( typeFactory ); + this.parameter = new Parameter( "localDateTime", typeFactory.getType( LocalDateTime.class ) ); + this.importTypes = asSet( + parameter.getType(), + typeFactory.getType( DatatypeConstants.class ), + typeFactory.getType( ChronoField.class ) + ); + } + + @Override + public Set getImportTypes() { + Set result = super.getImportTypes(); + result.addAll( importTypes ); + return result; + } + + @Override + public Parameter getParameter() { + return parameter; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/XmlGregorianCalendarToLocalDateTime.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/XmlGregorianCalendarToLocalDateTime.java new file mode 100644 index 000000000..5d2989244 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/builtin/XmlGregorianCalendarToLocalDateTime.java @@ -0,0 +1,55 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.internal.model.source.builtin; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Set; + +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.mapstruct.ap.internal.model.common.Parameter; +import org.mapstruct.ap.internal.model.common.Type; +import org.mapstruct.ap.internal.model.common.TypeFactory; + +import static org.mapstruct.ap.internal.util.Collections.asSet; + +/** + * @author Andrei Arlou + */ +public class XmlGregorianCalendarToLocalDateTime extends BuiltInMethod { + + private final Parameter parameter; + private final Type returnType; + private final Set importTypes; + + public XmlGregorianCalendarToLocalDateTime(TypeFactory typeFactory) { + this.parameter = new Parameter( "xcal", typeFactory.getType( XMLGregorianCalendar.class ) ); + this.returnType = typeFactory.getType( LocalDateTime.class ); + this.importTypes = asSet( + returnType, + parameter.getType(), + typeFactory.getType( DatatypeConstants.class ), + typeFactory.getType( Duration.class ) + ); + } + + @Override + public Parameter getParameter() { + return parameter; + } + + @Override + public Type getReturnType() { + return returnType; + } + + @Override + public Set getImportTypes() { + return importTypes; + } +} diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/source/builtin/LocalDateTimeToXmlGregorianCalendar.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/source/builtin/LocalDateTimeToXmlGregorianCalendar.ftl new file mode 100644 index 000000000..fb7706b39 --- /dev/null +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/source/builtin/LocalDateTimeToXmlGregorianCalendar.ftl @@ -0,0 +1,23 @@ +<#-- + + Copyright MapStruct Authors. + + Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + +--> +<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.SupportingMappingMethod" --> +private <@includeModel object=findType("XMLGregorianCalendar")/> ${name}( <@includeModel object=findType("java.time.LocalDateTime")/> localDateTime ) { + if ( localDateTime == null ) { + return null; + } + + return ${supportingField.variableName}.newXMLGregorianCalendar( + localDateTime.getYear(), + localDateTime.getMonthValue(), + localDateTime.getDayOfMonth(), + localDateTime.getHour(), + localDateTime.getMinute(), + localDateTime.getSecond(), + localDateTime.get( ChronoField.MILLI_OF_SECOND ), + <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED ); +} diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/source/builtin/XmlGregorianCalendarToLocalDateTime.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/source/builtin/XmlGregorianCalendarToLocalDateTime.ftl new file mode 100644 index 000000000..6eef5513a --- /dev/null +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/source/builtin/XmlGregorianCalendarToLocalDateTime.ftl @@ -0,0 +1,53 @@ +<#-- + + Copyright MapStruct Authors. + + Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + +--> +<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.SupportingMappingMethod" --> +private static <@includeModel object=findType("java.time.LocalDateTime")/> ${name}( <@includeModel object=findType("XMLGregorianCalendar")/> xcal ) { + if ( xcal == null ) { + return null; + } + + if ( xcal.getYear() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED + && xcal.getMonth() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED + && xcal.getDay() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED + && xcal.getHour() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED + && xcal.getMinute() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED + ) { + if ( xcal.getSecond() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED + && xcal.getMillisecond() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED ) { + return <@includeModel object=findType("java.time.LocalDateTime")/>.of( + xcal.getYear(), + xcal.getMonth(), + xcal.getDay(), + xcal.getHour(), + xcal.getMinute(), + xcal.getSecond(), + Duration.ofMillis( xcal.getMillisecond() ).getNano() + ); + } + else if ( xcal.getSecond() != <@includeModel object=findType("DatatypeConstants")/>.FIELD_UNDEFINED ) { + return <@includeModel object=findType("java.time.LocalDateTime")/>.of( + xcal.getYear(), + xcal.getMonth(), + xcal.getDay(), + xcal.getHour(), + xcal.getMinute(), + xcal.getSecond() + ); + } + else { + return <@includeModel object=findType("java.time.LocalDateTime")/>.of( + xcal.getYear(), + xcal.getMonth(), + xcal.getDay(), + xcal.getHour(), + xcal.getMinute() + ); + } + } + return null; +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/LocalDateTimeToXMLGregorianCalendarConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/LocalDateTimeToXMLGregorianCalendarConversionTest.java new file mode 100644 index 000000000..ebaa271d0 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/LocalDateTimeToXMLGregorianCalendarConversionTest.java @@ -0,0 +1,120 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.conversion.java8time; + +import java.time.LocalDateTime; +import java.util.Calendar; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.conversion.java8time.localdatetimetoxmlgregoriancalendarconversion.SourceTargetMapper; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; +import org.mapstruct.ap.test.conversion.java8time.localdatetimetoxmlgregoriancalendarconversion.Source; +import org.mapstruct.ap.test.conversion.java8time.localdatetimetoxmlgregoriancalendarconversion.Target; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Andrei Arlou + */ +@WithClasses({ Source.class, Target.class, SourceTargetMapper.class }) +@RunWith(AnnotationProcessorTestRunner.class) +public class LocalDateTimeToXMLGregorianCalendarConversionTest { + + @Test + public void shouldNullCheckOnConversionToTarget() { + Target target = SourceTargetMapper.INSTANCE.toTarget( new Source() ); + + assertThat( target ).isNotNull(); + assertThat( target.getLocalDateTime() ).isNull(); + } + + @Test + public void shouldNullCheckOnConversionToSource() { + Source source = SourceTargetMapper.INSTANCE.toSource( new Target() ); + + assertThat( source ).isNotNull(); + assertThat( source.getXmlGregorianCalendar() ).isNull(); + } + + @Test + public void shouldMapLocalDateTimeToXmlGregorianCalendarCorrectlyWithNanoseconds() + throws DatatypeConfigurationException { + LocalDateTime localDateTime = LocalDateTime.of( 1994, Calendar.MARCH, 5, 11, 30, 50, 9000000 ); + Target target = new Target(); + target.setLocalDateTime( localDateTime ); + + Source source = SourceTargetMapper.INSTANCE.toSource( target ); + + XMLGregorianCalendar expectedCalendar = DatatypeFactory.newInstance() + .newXMLGregorianCalendar( 1994, Calendar.MARCH, 5, 11, 30, 50, 9, + DatatypeConstants.FIELD_UNDEFINED + ); + + assertThat( source ).isNotNull(); + assertThat( source.getXmlGregorianCalendar() ).isEqualTo( expectedCalendar ); + } + + @Test + public void shouldMapLocalDateTimeToXmlGregorianCalendarCorrectlyWithSeconds() + throws DatatypeConfigurationException { + LocalDateTime localDateTime = LocalDateTime.of( 1994, Calendar.MARCH, 5, 11, 30, 50 ); + Target target = new Target(); + target.setLocalDateTime( localDateTime ); + + Source source = SourceTargetMapper.INSTANCE.toSource( target ); + + XMLGregorianCalendar expectedCalendar = DatatypeFactory.newInstance() + .newXMLGregorianCalendar( 1994, Calendar.MARCH, 5, 11, 30, 50, 0, + DatatypeConstants.FIELD_UNDEFINED + ); + + assertThat( source ).isNotNull(); + assertThat( source.getXmlGregorianCalendar() ).isEqualTo( expectedCalendar ); + } + + @Test + public void shouldMapLocalDateTimeToXmlGregorianCalendarCorrectlyWithMinutes() + throws DatatypeConfigurationException { + LocalDateTime localDateTime = LocalDateTime.of( 1994, Calendar.MARCH, 5, 11, 30 ); + Target target = new Target(); + target.setLocalDateTime( localDateTime ); + + Source source = SourceTargetMapper.INSTANCE.toSource( target ); + + XMLGregorianCalendar expectedCalendar = DatatypeFactory.newInstance() + .newXMLGregorianCalendar( 1994, Calendar.MARCH, 5, 11, 30, 0, 0, + DatatypeConstants.FIELD_UNDEFINED + ); + + assertThat( source ).isNotNull(); + assertThat( source.getXmlGregorianCalendar() ).isEqualTo( expectedCalendar ); + } + + @Test + public void shouldMapXmlGregorianCalendarToLocalDateTimeCorrectly() throws DatatypeConfigurationException { + XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance() + .newXMLGregorianCalendar( 1994, Calendar.MARCH, 5, 11, 30, 50, 500, + DatatypeConstants.FIELD_UNDEFINED + ); + + Source source = new Source(); + source.setXmlGregorianCalendar( xmlGregorianCalendar ); + + Target target = SourceTargetMapper.INSTANCE.toTarget( source ); + + LocalDateTime expectedLocalDateTime = LocalDateTime.of( 1994, Calendar.MARCH, 5, 11, 30, 50, 500000000 ); + + assertThat( target ).isNotNull(); + assertThat( target.getLocalDateTime() ).isEqualTo( expectedLocalDateTime ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/Source.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/Source.java new file mode 100644 index 000000000..d79ad6072 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/Source.java @@ -0,0 +1,24 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.conversion.java8time.localdatetimetoxmlgregoriancalendarconversion; + +import javax.xml.datatype.XMLGregorianCalendar; + +/** + * @author Andrei Arlou + */ +public class Source { + private XMLGregorianCalendar xmlGregorianCalendar; + + public XMLGregorianCalendar getXmlGregorianCalendar() { + return xmlGregorianCalendar; + } + + public void setXmlGregorianCalendar(XMLGregorianCalendar xmlGregorianCalendar) { + this.xmlGregorianCalendar = xmlGregorianCalendar; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/SourceTargetMapper.java new file mode 100644 index 000000000..cc456aa0a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/SourceTargetMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.conversion.java8time.localdatetimetoxmlgregoriancalendarconversion; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * @author Andrei Arlou + */ +@Mapper +public interface SourceTargetMapper { + + SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + @Mapping(source = "xmlGregorianCalendar", target = "localDateTime") + Target toTarget(Source source); + + @Mapping(source = "localDateTime", target = "xmlGregorianCalendar") + Source toSource(Target target); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/Target.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/Target.java new file mode 100644 index 000000000..b8fc51e6d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/localdatetimetoxmlgregoriancalendarconversion/Target.java @@ -0,0 +1,23 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.conversion.java8time.localdatetimetoxmlgregoriancalendarconversion; + +import java.time.LocalDateTime; + +/** + * @author Andrei Arlou + */ +public class Target { + private LocalDateTime localDateTime; + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } +}