diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl index 45825b4fd..c58f9e758 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl @@ -30,31 +30,26 @@ <#list sourceParametersExcludingPrimitives as sourceParam> <#if (constructorPropertyMappingsByParameter(sourceParam)?size > 0)> <#list constructorPropertyMappingsByParameter(sourceParam) as propertyMapping> - <@includeModel object=propertyMapping.targetType /> ${propertyMapping.targetWriteAccessorName}; + <@includeModel object=propertyMapping.targetType /> ${propertyMapping.targetWriteAccessorName} = ${propertyMapping.targetType.null}; if ( ${sourceParam.name} != null ) { <#list constructorPropertyMappingsByParameter(sourceParam) as propertyMapping> <@includeModel object=propertyMapping existingInstanceMapping=existingInstanceMapping defaultValueAssignment=propertyMapping.defaultValueAssignment/> } - else { - <#list constructorPropertyMappingsByParameter(sourceParam) as propertyMapping> - ${propertyMapping.targetWriteAccessorName} = ${propertyMapping.targetType.null}; - - } <#list sourcePrimitiveParameters as sourceParam> <#if (constructorPropertyMappingsByParameter(sourceParam)?size > 0)> <#list constructorPropertyMappingsByParameter(sourceParam) as propertyMapping> - <@includeModel object=propertyMapping.targetType /> ${propertyMapping.targetWriteAccessorName}; + <@includeModel object=propertyMapping.targetType /> ${propertyMapping.targetWriteAccessorName} = ${propertyMapping.targetType.null}; <@includeModel object=propertyMapping existingInstanceMapping=existingInstanceMapping defaultValueAssignment=propertyMapping.defaultValueAssignment/> <#else> <#list constructorPropertyMappingsByParameter(sourceParameters[0]) as propertyMapping> - <@includeModel object=propertyMapping.targetType /> ${propertyMapping.targetWriteAccessorName}; + <@includeModel object=propertyMapping.targetType /> ${propertyMapping.targetWriteAccessorName} = ${propertyMapping.targetType.null}; <#if mapNullToDefault>if ( ${sourceParameters[0].name} != null ) { <#list constructorPropertyMappingsByParameter(sourceParameters[0]) as propertyMapping> @@ -62,11 +57,6 @@ <#if mapNullToDefault> } - else { - <#list constructorPropertyMappingsByParameter(sourceParameters[0]) as propertyMapping> - ${propertyMapping.targetWriteAccessorName} = ${propertyMapping.targetType.null}; - - } <#list constructorConstantMappings as constantMapping> diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMapsWithNullCheck.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMapsWithNullCheck.ftl index 92e2e9d09..3d6172b49 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMapsWithNullCheck.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMapsWithNullCheck.ftl @@ -18,10 +18,6 @@ <@lib.handleLocalVarNullCheck needs_explicit_local_var=directAssignment> <#if ext.targetBeanName?has_content>${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><#if directAssignment><@wrapLocalVarInCollectionInitializer/><#else><@lib.handleWithAssignmentOrNullCheckVar/>; - <#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !ext.targetBeanName?has_content>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleLocalVarNullCheck --> - ${ext.targetWriteAccessorName}<@lib.handleWrite>null; - } - <#-- wraps the local variable in a collection initializer (new collection, or EnumSet.copyOf) diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Issue2109Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Issue2109Mapper.java new file mode 100644 index 000000000..7542c2c0c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Issue2109Mapper.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.bugs._2109; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface Issue2109Mapper { + + Issue2109Mapper INSTANCE = Mappers.getMapper( Issue2109Mapper.class ); + + Target map(Source source); + + @Mapping(target = "data", defaultExpression = "java(new byte[0])") + Target mapWithEmptyData(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Issue2109Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Issue2109Test.java new file mode 100644 index 000000000..6ee44acb9 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Issue2109Test.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.test.bugs._2109; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2109") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + Issue2109Mapper.class, + Source.class, + Target.class, +}) +public class Issue2109Test { + + @Test + public void shouldCorrectlyMapArrayInConstructorMapping() { + Target target = Issue2109Mapper.INSTANCE.map( new Source( 100L, new byte[] { 100, 120, 40, 40 } ) ); + + assertThat( target ).isNotNull(); + assertThat( target.getId() ).isEqualTo( 100L ); + assertThat( target.getData() ).containsExactly( 100, 120, 40, 40 ); + + target = Issue2109Mapper.INSTANCE.map( new Source( 50L, null ) ); + + assertThat( target ).isNotNull(); + assertThat( target.getId() ).isEqualTo( 50L ); + assertThat( target.getData() ).isNull(); + + target = Issue2109Mapper.INSTANCE.mapWithEmptyData( new Source( 100L, new byte[] { 100, 120, 40, 40 } ) ); + + assertThat( target ).isNotNull(); + assertThat( target.getId() ).isEqualTo( 100L ); + assertThat( target.getData() ).containsExactly( 100, 120, 40, 40 ); + + target = Issue2109Mapper.INSTANCE.mapWithEmptyData( new Source( 50L, null ) ); + + assertThat( target ).isNotNull(); + assertThat( target.getId() ).isEqualTo( 50L ); + assertThat( target.getData() ).isEmpty(); + + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Source.java new file mode 100644 index 000000000..a0aba8ce8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Source.java @@ -0,0 +1,28 @@ +/* + * 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.bugs._2109; + +/** + * @author Filip Hrisafov + */ +public class Source { + + private final Long id; + private final byte[] data; + + public Source(Long id, byte[] data) { + this.id = id; + this.data = data; + } + + public Long getId() { + return id; + } + + public byte[] getData() { + return data; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Target.java new file mode 100644 index 000000000..2e44bc21b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2109/Target.java @@ -0,0 +1,28 @@ +/* + * 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.bugs._2109; + +/** + * @author Filip Hrisafov + */ +public class Target { + + private final Long id; + private final byte[] data; + + public Target(Long id, byte[] data) { + this.id = id; + this.data = data; + } + + public Long getId() { + return id; + } + + public byte[] getData() { + return data; + } +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedsource/ArtistToChartEntryImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedsource/ArtistToChartEntryImpl.java index bd8c81a5d..09f96b4b3 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedsource/ArtistToChartEntryImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedsource/ArtistToChartEntryImpl.java @@ -26,36 +26,24 @@ public class ArtistToChartEntryImpl implements ArtistToChartEntry { return null; } - String chartName; + String chartName = null; if ( chart != null ) { chartName = chart.getName(); } - else { - chartName = null; - } - String songTitle; - String artistName; - String recordedAt; - String city; + String songTitle = null; + String artistName = null; + String recordedAt = null; + String city = null; if ( song != null ) { songTitle = song.getTitle(); artistName = songArtistName( song ); recordedAt = songArtistLabelStudioName( song ); city = songArtistLabelStudioCity( song ); } - else { - songTitle = null; - artistName = null; - recordedAt = null; - city = null; - } - int position1; + int position1 = 0; if ( position != null ) { position1 = position; } - else { - position1 = 0; - } ChartEntry chartEntry = new ChartEntry( chartName, songTitle, artistName, recordedAt, city, position1 ); @@ -68,10 +56,10 @@ public class ArtistToChartEntryImpl implements ArtistToChartEntry { return null; } - String songTitle; - String artistName; - String recordedAt; - String city; + String songTitle = null; + String artistName = null; + String recordedAt = null; + String city = null; songTitle = song.getTitle(); artistName = songArtistName( song ); @@ -92,7 +80,7 @@ public class ArtistToChartEntryImpl implements ArtistToChartEntry { return null; } - String chartName; + String chartName = null; chartName = name.getName(); diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedtarget/ChartEntryToArtistImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedtarget/ChartEntryToArtistImpl.java index f5deb649b..0413ef5b7 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedtarget/ChartEntryToArtistImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/constructor/nestedtarget/ChartEntryToArtistImpl.java @@ -27,8 +27,8 @@ public class ChartEntryToArtistImpl extends ChartEntryToArtist { return null; } - Song song; - String name; + Song song = null; + String name = null; song = chartEntryToSong( chartEntry ); name = chartEntry.getChartName(); @@ -46,12 +46,12 @@ public class ChartEntryToArtistImpl extends ChartEntryToArtist { return null; } - String chartName; - String songTitle; - String artistName; - String recordedAt; - String city; - int position; + String chartName = null; + String songTitle = null; + String artistName = null; + String recordedAt = null; + String city = null; + int position = 0; chartName = chart.getName(); songTitle = chartSongTitle( chart ); @@ -70,8 +70,8 @@ public class ChartEntryToArtistImpl extends ChartEntryToArtist { return null; } - String name; - String city; + String name = null; + String city = null; name = chartEntry.getRecordedAt(); city = chartEntry.getCity(); @@ -86,7 +86,7 @@ public class ChartEntryToArtistImpl extends ChartEntryToArtist { return null; } - Studio studio; + Studio studio = null; studio = chartEntryToStudio( chartEntry ); @@ -102,8 +102,8 @@ public class ChartEntryToArtistImpl extends ChartEntryToArtist { return null; } - Label label; - String name; + Label label = null; + String name = null; label = chartEntryToLabel( chartEntry ); name = chartEntry.getArtistName(); @@ -118,9 +118,9 @@ public class ChartEntryToArtistImpl extends ChartEntryToArtist { return null; } - Artist artist; - String title; - List positions; + Artist artist = null; + String title = null; + List positions = null; artist = chartEntryToArtist( chartEntry ); title = chartEntry.getSongTitle();