#1791 Support for conversion between java.time.LocalDateTime and javax.xml.datatype.XMLGregorianCalendar (#1894)

This commit is contained in:
Andrei Arlou 2019-09-21 22:27:45 +03:00 committed by GitHub
parent fcdf852a17
commit f4c9313972
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 379 additions and 5 deletions

View File

@ -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`.

View File

@ -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 ) );

View File

@ -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<Type> getImportTypes() {
return Collections.<Type>emptySet();
return Collections.emptySet();
}
/**

View File

@ -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<Type> 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<Type> getImportTypes() {
Set<Type> result = super.getImportTypes();
result.addAll( importTypes );
return result;
}
@Override
public Parameter getParameter() {
return parameter;
}
}

View File

@ -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<Type> 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<Type> getImportTypes() {
return importTypes;
}
}

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}