From d3b4a168b7abef6c31fea4f3506996ffe23ad718 Mon Sep 17 00:00:00 2001 From: Bragolgirith Date: Mon, 1 May 2023 09:11:05 +0200 Subject: [PATCH] #3199 Add support for implicit conversion between java.time.LocalDate and java.time.LocalDateTime --- .../chapter-5-data-type-conversions.asciidoc | 2 + .../internal/conversion/ConversionUtils.java | 12 +++++ .../ap/internal/conversion/Conversions.java | 5 +- ...avaLocalDateTimeToLocalDateConversion.java | 46 +++++++++++++++++++ .../java8time/Java8TimeConversionTest.java | 15 ++++++ .../ap/test/conversion/java8time/Source.java | 10 ++++ .../ap/test/conversion/java8time/Target.java | 11 +++++ .../java8time/SourceTargetMapperImpl.java | 36 +++++++++++++++ 8 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/internal/conversion/JavaLocalDateTimeToLocalDateConversion.java 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 51ccb21a4..258c7085f 100644 --- a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc +++ b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc @@ -107,6 +107,8 @@ public interface CarMapper { * Between `java.time.Instant` from Java 8 Date-Time package and `java.util.Date`. +* Between `java.time.LocalDateTime` from Java 8 Date-Time package and `java.time.LocalDate` from the same package. + * Between `java.time.ZonedDateTime` from Java 8 Date-Time package and `java.util.Calendar`. * Between `java.sql.Date` and `java.util.Date` diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java index e88bb93b8..496d11676 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java @@ -12,6 +12,7 @@ import java.sql.Time; import java.sql.Timestamp; import java.text.DecimalFormat; import java.text.SimpleDateFormat; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; @@ -190,6 +191,17 @@ public final class ConversionUtils { return typeReferenceName( conversionContext, ZoneId.class ); } + /** + * Name for {@link java.time.LocalDate}. + * + * @param conversionContext Conversion context + * + * @return Name or fully-qualified name. + */ + public static String localDate(ConversionContext conversionContext) { + return typeReferenceName( conversionContext, LocalDate.class ); + } + /** * Name for {@link java.time.LocalDateTime}. * diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java index e947c7857..9a4085df8 100755 --- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java @@ -233,12 +233,15 @@ public class Conversions { register( Period.class, String.class, new StaticParseToStringConversion() ); register( Duration.class, String.class, new StaticParseToStringConversion() ); - // Java 8 to Date + // Java 8 time to Date register( ZonedDateTime.class, Date.class, new JavaZonedDateTimeToDateConversion() ); register( LocalDateTime.class, Date.class, new JavaLocalDateTimeToDateConversion() ); register( LocalDate.class, Date.class, new JavaLocalDateToDateConversion() ); register( Instant.class, Date.class, new JavaInstantToDateConversion() ); + // Java 8 time + register( LocalDateTime.class, LocalDate.class, new JavaLocalDateTimeToLocalDateConversion() ); + } private void registerJavaTimeSqlConversions() { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/JavaLocalDateTimeToLocalDateConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/JavaLocalDateTimeToLocalDateConversion.java new file mode 100644 index 000000000..ae571ad6b --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/JavaLocalDateTimeToLocalDateConversion.java @@ -0,0 +1,46 @@ +/* + * 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.conversion; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Set; + +import org.mapstruct.ap.internal.model.common.ConversionContext; +import org.mapstruct.ap.internal.model.common.Type; +import org.mapstruct.ap.internal.util.Collections; + +/** + * SimpleConversion for mapping {@link LocalDateTime} to + * {@link LocalDate} and vice versa. + */ + +public class JavaLocalDateTimeToLocalDateConversion extends SimpleConversion { + + @Override + protected String getToExpression(ConversionContext conversionContext) { + return ".toLocalDate()"; + } + + @Override + protected Set getToConversionImportTypes(ConversionContext conversionContext) { + return Collections.asSet( + conversionContext.getTypeFactory().getType( LocalDate.class ) + ); + } + + @Override + protected String getFromExpression(ConversionContext conversionContext) { + return ".atStartOfDay()"; + } + + @Override + protected Set getFromConversionImportTypes(ConversionContext conversionContext) { + return Collections.asSet( + conversionContext.getTypeFactory().getType( LocalDateTime.class ) + ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Java8TimeConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Java8TimeConversionTest.java index aa3086542..005963053 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Java8TimeConversionTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Java8TimeConversionTest.java @@ -252,6 +252,21 @@ public class Java8TimeConversionTest { assertThat( source.getForDateConversionWithInstant() ).isEqualTo( instant ); } + @ProcessorTest + public void testLocalDateTimeToLocalDateMapping() { + LocalDate localDate = LocalDate.of( 2014, 1, 1 ); + + Source source = new Source(); + source.setForLocalDateTimeConversionWithLocalDate( localDate ); + Target target = SourceTargetMapper.INSTANCE.sourceToTargetDefaultMapping( source ); + LocalDateTime localDateTime = target.getForLocalDateTimeConversionWithLocalDate(); + assertThat( localDateTime ).isNotNull(); + assertThat( localDateTime ).isEqualTo( LocalDateTime.of( 2014, 1, 1, 0, 0 ) ); + + source = SourceTargetMapper.INSTANCE.targetToSource( target ); + assertThat( source.getForLocalDateTimeConversionWithLocalDate() ).isEqualTo( localDate ); + } + @ProcessorTest @DefaultTimeZone("Australia/Melbourne") public void testLocalDateTimeToDateMapping() { diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Source.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Source.java index 91298617c..93479f8a8 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Source.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Source.java @@ -38,6 +38,8 @@ public class Source { private Instant forDateConversionWithInstant; + private LocalDate forLocalDateTimeConversionWithLocalDate; + private Instant forInstantConversionWithString; private Period forPeriodConversionWithString; @@ -124,6 +126,14 @@ public class Source { this.forDateConversionWithInstant = forDateConversionWithInstant; } + public LocalDate getForLocalDateTimeConversionWithLocalDate() { + return forLocalDateTimeConversionWithLocalDate; + } + + public void setForLocalDateTimeConversionWithLocalDate(LocalDate forLocalDateTimeConversionWithLocalDate) { + this.forLocalDateTimeConversionWithLocalDate = forLocalDateTimeConversionWithLocalDate; + } + public Instant getForInstantConversionWithString() { return forInstantConversionWithString; } diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Target.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Target.java index 188a6d0e2..d2a487873 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Target.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time/Target.java @@ -5,6 +5,7 @@ */ package org.mapstruct.ap.test.conversion.java8time; +import java.time.LocalDateTime; import java.util.Calendar; import java.util.Date; @@ -33,6 +34,8 @@ public class Target { private Date forDateConversionWithInstant; + private LocalDateTime forLocalDateTimeConversionWithLocalDate; + private String forInstantConversionWithString; private String forPeriodConversionWithString; @@ -119,6 +122,14 @@ public class Target { this.forDateConversionWithInstant = forDateConversionWithInstant; } + public LocalDateTime getForLocalDateTimeConversionWithLocalDate() { + return forLocalDateTimeConversionWithLocalDate; + } + + public void setForLocalDateTimeConversionWithLocalDate(LocalDateTime forLocalDateTimeConversionWithLocalDate) { + this.forLocalDateTimeConversionWithLocalDate = forLocalDateTimeConversionWithLocalDate; + } + public String getForInstantConversionWithString() { return forInstantConversionWithString; } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/java8time/SourceTargetMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/java8time/SourceTargetMapperImpl.java index 58beaa19d..3e0f5f84f 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/java8time/SourceTargetMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/java8time/SourceTargetMapperImpl.java @@ -68,6 +68,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( source.getForDateConversionWithInstant() != null ) { target.setForDateConversionWithInstant( Date.from( source.getForDateConversionWithInstant() ) ); } + if ( source.getForLocalDateTimeConversionWithLocalDate() != null ) { + target.setForLocalDateTimeConversionWithLocalDate( source.getForLocalDateTimeConversionWithLocalDate().atStartOfDay() ); + } if ( source.getForInstantConversionWithString() != null ) { target.setForInstantConversionWithString( source.getForInstantConversionWithString().toString() ); } @@ -117,6 +120,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( source.getForDateConversionWithInstant() != null ) { target.setForDateConversionWithInstant( Date.from( source.getForDateConversionWithInstant() ) ); } + if ( source.getForLocalDateTimeConversionWithLocalDate() != null ) { + target.setForLocalDateTimeConversionWithLocalDate( source.getForLocalDateTimeConversionWithLocalDate().atStartOfDay() ); + } if ( source.getForInstantConversionWithString() != null ) { target.setForInstantConversionWithString( source.getForInstantConversionWithString().toString() ); } @@ -166,6 +172,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( source.getForDateConversionWithInstant() != null ) { target.setForDateConversionWithInstant( Date.from( source.getForDateConversionWithInstant() ) ); } + if ( source.getForLocalDateTimeConversionWithLocalDate() != null ) { + target.setForLocalDateTimeConversionWithLocalDate( source.getForLocalDateTimeConversionWithLocalDate().atStartOfDay() ); + } if ( source.getForInstantConversionWithString() != null ) { target.setForInstantConversionWithString( source.getForInstantConversionWithString().toString() ); } @@ -215,6 +224,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( source.getForDateConversionWithInstant() != null ) { target.setForDateConversionWithInstant( Date.from( source.getForDateConversionWithInstant() ) ); } + if ( source.getForLocalDateTimeConversionWithLocalDate() != null ) { + target.setForLocalDateTimeConversionWithLocalDate( source.getForLocalDateTimeConversionWithLocalDate().atStartOfDay() ); + } if ( source.getForInstantConversionWithString() != null ) { target.setForInstantConversionWithString( source.getForInstantConversionWithString().toString() ); } @@ -264,6 +276,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( source.getForDateConversionWithInstant() != null ) { target.setForDateConversionWithInstant( Date.from( source.getForDateConversionWithInstant() ) ); } + if ( source.getForLocalDateTimeConversionWithLocalDate() != null ) { + target.setForLocalDateTimeConversionWithLocalDate( source.getForLocalDateTimeConversionWithLocalDate().atStartOfDay() ); + } if ( source.getForInstantConversionWithString() != null ) { target.setForInstantConversionWithString( source.getForInstantConversionWithString().toString() ); } @@ -313,6 +328,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( source.getForDateConversionWithInstant() != null ) { target.setForDateConversionWithInstant( Date.from( source.getForDateConversionWithInstant() ) ); } + if ( source.getForLocalDateTimeConversionWithLocalDate() != null ) { + target.setForLocalDateTimeConversionWithLocalDate( source.getForLocalDateTimeConversionWithLocalDate().atStartOfDay() ); + } if ( source.getForInstantConversionWithString() != null ) { target.setForInstantConversionWithString( source.getForInstantConversionWithString().toString() ); } @@ -362,6 +380,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( target.getForDateConversionWithInstant() != null ) { source.setForDateConversionWithInstant( target.getForDateConversionWithInstant().toInstant() ); } + if ( target.getForLocalDateTimeConversionWithLocalDate() != null ) { + source.setForLocalDateTimeConversionWithLocalDate( target.getForLocalDateTimeConversionWithLocalDate().toLocalDate() ); + } if ( target.getForInstantConversionWithString() != null ) { source.setForInstantConversionWithString( Instant.parse( target.getForInstantConversionWithString() ) ); } @@ -411,6 +432,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( target.getForDateConversionWithInstant() != null ) { source.setForDateConversionWithInstant( target.getForDateConversionWithInstant().toInstant() ); } + if ( target.getForLocalDateTimeConversionWithLocalDate() != null ) { + source.setForLocalDateTimeConversionWithLocalDate( target.getForLocalDateTimeConversionWithLocalDate().toLocalDate() ); + } if ( target.getForInstantConversionWithString() != null ) { source.setForInstantConversionWithString( Instant.parse( target.getForInstantConversionWithString() ) ); } @@ -460,6 +484,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( target.getForDateConversionWithInstant() != null ) { source.setForDateConversionWithInstant( target.getForDateConversionWithInstant().toInstant() ); } + if ( target.getForLocalDateTimeConversionWithLocalDate() != null ) { + source.setForLocalDateTimeConversionWithLocalDate( target.getForLocalDateTimeConversionWithLocalDate().toLocalDate() ); + } if ( target.getForInstantConversionWithString() != null ) { source.setForInstantConversionWithString( Instant.parse( target.getForInstantConversionWithString() ) ); } @@ -509,6 +536,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( target.getForDateConversionWithInstant() != null ) { source.setForDateConversionWithInstant( target.getForDateConversionWithInstant().toInstant() ); } + if ( target.getForLocalDateTimeConversionWithLocalDate() != null ) { + source.setForLocalDateTimeConversionWithLocalDate( target.getForLocalDateTimeConversionWithLocalDate().toLocalDate() ); + } if ( target.getForInstantConversionWithString() != null ) { source.setForInstantConversionWithString( Instant.parse( target.getForInstantConversionWithString() ) ); } @@ -558,6 +588,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( target.getForDateConversionWithInstant() != null ) { source.setForDateConversionWithInstant( target.getForDateConversionWithInstant().toInstant() ); } + if ( target.getForLocalDateTimeConversionWithLocalDate() != null ) { + source.setForLocalDateTimeConversionWithLocalDate( target.getForLocalDateTimeConversionWithLocalDate().toLocalDate() ); + } if ( target.getForInstantConversionWithString() != null ) { source.setForInstantConversionWithString( Instant.parse( target.getForInstantConversionWithString() ) ); } @@ -607,6 +640,9 @@ public class SourceTargetMapperImpl implements SourceTargetMapper { if ( target.getForDateConversionWithInstant() != null ) { source.setForDateConversionWithInstant( target.getForDateConversionWithInstant().toInstant() ); } + if ( target.getForLocalDateTimeConversionWithLocalDate() != null ) { + source.setForLocalDateTimeConversionWithLocalDate( target.getForLocalDateTimeConversionWithLocalDate().toLocalDate() ); + } if ( target.getForInstantConversionWithString() != null ) { source.setForInstantConversionWithString( Instant.parse( target.getForInstantConversionWithString() ) ); }