diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java b/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java index e9ce0b64f..10b3d4736 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java @@ -151,6 +151,16 @@ public class NestedTargetPropertyMappingHolder { groupedByTP.singleTargetReferences.get( targetProperty ) ); + // We need an update method in the when one of the following is satisfied: + // 1) Multiple source parameters for the target reference + // 2) Multiple source references for the target reference + // The reason for this is that multiple sources have effect on the target. + // See Issue1828Test for more info. + boolean forceUpdateMethod = + multipleSourceParametersForTP || groupedSourceReferences.groupedBySourceReferences.size() > 1; + + boolean forceUpdateMethodOrNonNestedReferencesPresent = + forceUpdateMethod || !groupedSourceReferences.nonNested.isEmpty(); // For all the groupedBySourceReferences we need to create property mappings // from the Mappings and not restrict on the defined mappings (allow to forge name based mapping) // if we have composite methods i.e. more then 2 parameters then we have to force a creation @@ -159,8 +169,6 @@ public class NestedTargetPropertyMappingHolder { .groupedBySourceReferences .entrySet() ) { PropertyEntry sourceEntry = entryBySP.getKey(); - boolean forceUpdateMethodOrNonNestedReferencesPresent = - multipleSourceParametersForTP || !groupedSourceReferences.nonNested.isEmpty(); // If there are multiple source parameters that are mapped to the target reference // then we restrict the mapping only to the defined mappings. And we create MappingOptions // for forged methods (which means that any unmapped target properties are ignored) diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/CompleteAddress.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/CompleteAddress.java new file mode 100644 index 000000000..7af21d26b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/CompleteAddress.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.test.bugs._1828; + +public class CompleteAddress { + + private String lineOne; + private String lineTwo; + private String city; + private String country; + + public String getLineOne() { + return lineOne; + } + + public void setLineOne(String lineOne) { + this.lineOne = lineOne; + } + + public String getLineTwo() { + return lineTwo; + } + + public void setLineTwo(String lineTwo) { + this.lineTwo = lineTwo; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Employee.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Employee.java new file mode 100644 index 000000000..e635cd16d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Employee.java @@ -0,0 +1,37 @@ +/* + * 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._1828; + +public class Employee { + + private String name; + private GeneralAddress generalAddress; + private SpecialAddress specialAddress; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public GeneralAddress getGeneralAddress() { + return generalAddress; + } + + public void setGeneralAddress(GeneralAddress generalAddress) { + this.generalAddress = generalAddress; + } + + public SpecialAddress getSpecialAddress() { + return specialAddress; + } + + public void setSpecialAddress(SpecialAddress specialAddress) { + this.specialAddress = specialAddress; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/FirstMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/FirstMapper.java new file mode 100644 index 000000000..9d4540c70 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/FirstMapper.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.bugs._1828; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface FirstMapper { + + FirstMapper INSTANCE = Mappers.getMapper( FirstMapper.class ); + + @Mapping(target = "completeAddress.lineOne", source = "specialAddress.line1") + @Mapping(target = "completeAddress.lineTwo", source = "specialAddress.line2") + @Mapping(target = "completeAddress.city", source = "generalAddress.city") + @Mapping(target = "completeAddress.country", source = "generalAddress.country") + Person mapPerson(Employee employee); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/GeneralAddress.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/GeneralAddress.java new file mode 100644 index 000000000..e15ddbb3e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/GeneralAddress.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._1828; + +public class GeneralAddress { + + private String city; + private String country; + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Issue1828Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Issue1828Test.java new file mode 100644 index 000000000..0d99cf903 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Issue1828Test.java @@ -0,0 +1,101 @@ +/* + * 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._1828; + +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("1828") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + CompleteAddress.class, + Employee.class, + FirstMapper.class, + GeneralAddress.class, + Person.class, + SpecialAddress.class, +}) +public class Issue1828Test { + + @Test + public void testMapSpecialAndGeneralAddressSet() { + + Employee employee = new Employee(); + employee.setName( "Mad King" ); + + SpecialAddress specialAddress = new SpecialAddress(); + specialAddress.setLine1( "Building One" ); + specialAddress.setLine2( "Street Two" ); + employee.setSpecialAddress( specialAddress ); + + GeneralAddress generalAddress = new GeneralAddress(); + generalAddress.setCity( "King's Landing" ); + generalAddress.setCountry( "Seven Kingdom" ); + employee.setGeneralAddress( generalAddress ); + + Person person = FirstMapper.INSTANCE.mapPerson( employee ); + assertThat( person.getName() ).isEqualTo( "Mad King" ); + + CompleteAddress completeAddress = person.getCompleteAddress(); + assertThat( completeAddress ).isNotNull(); + assertThat( completeAddress.getLineOne() ).isEqualTo( "Building One" ); + assertThat( completeAddress.getLineTwo() ).isEqualTo( "Street Two" ); + assertThat( completeAddress.getCity() ).isEqualTo( "King's Landing" ); + assertThat( completeAddress.getCountry() ).isEqualTo( "Seven Kingdom" ); + } + + @Test + public void testMapGeneralAddressNull() { + + Employee employee = new Employee(); + employee.setName( "Mad King" ); + + SpecialAddress specialAddress = new SpecialAddress(); + specialAddress.setLine1( "Building One" ); + specialAddress.setLine2( "Street Two" ); + employee.setSpecialAddress( specialAddress ); + + Person person = FirstMapper.INSTANCE.mapPerson( employee ); + assertThat( person.getName() ).isEqualTo( "Mad King" ); + + CompleteAddress completeAddress = person.getCompleteAddress(); + assertThat( completeAddress ).isNotNull(); + assertThat( completeAddress.getLineOne() ).isEqualTo( "Building One" ); + assertThat( completeAddress.getLineTwo() ).isEqualTo( "Street Two" ); + assertThat( completeAddress.getCity() ).isNull(); + assertThat( completeAddress.getCountry() ).isNull(); + } + + @Test + public void testMapSpecialAddressNull() { + + Employee employee = new Employee(); + employee.setName( "Mad King" ); + + GeneralAddress generalAddress = new GeneralAddress(); + generalAddress.setCity( "King's Landing" ); + generalAddress.setCountry( "Seven Kingdom" ); + employee.setGeneralAddress( generalAddress ); + + Person person = FirstMapper.INSTANCE.mapPerson( employee ); + assertThat( person.getName() ).isEqualTo( "Mad King" ); + + CompleteAddress completeAddress = person.getCompleteAddress(); + assertThat( completeAddress ).isNotNull(); + assertThat( completeAddress.getLineOne() ).isNull(); + assertThat( completeAddress.getLineTwo() ).isNull(); + assertThat( completeAddress.getCity() ).isEqualTo( "King's Landing" ); + assertThat( completeAddress.getCountry() ).isEqualTo( "Seven Kingdom" ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Person.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Person.java new file mode 100644 index 000000000..d23dc8642 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/Person.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._1828; + +public class Person { + + String name; + private CompleteAddress completeAddress; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public CompleteAddress getCompleteAddress() { + return completeAddress; + } + + public void setCompleteAddress(CompleteAddress completeAddress) { + this.completeAddress = completeAddress; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/SpecialAddress.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/SpecialAddress.java new file mode 100644 index 000000000..e7e806865 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1828/SpecialAddress.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._1828; + +public class SpecialAddress { + + private String line1; + private String line2; + + public String getLine1() { + return line1; + } + + public void setLine1(String line1) { + this.line1 = line1; + } + + public String getLine2() { + return line2; + } + + public void setLine2(String line2) { + this.line2 = line2; + } +}