From 5cead7ae5e09ecc07739265e263dd366b3c8d0cf Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sun, 27 Aug 2017 18:59:17 +0200 Subject: [PATCH] #1269 use update methods for different sources for nested targets --- .../controlling-nested-bean-mappings.asciidoc | 6 ++ .../NestedTargetPropertyMappingHolder.java | 32 ++++++-- .../ap/test/bugs/_1269/Issue1269Test.java | 78 +++++++++++++++++++ .../ap/test/bugs/_1269/dto/VehicleDto.java | 36 +++++++++ .../test/bugs/_1269/dto/VehicleImageDto.java | 45 +++++++++++ .../test/bugs/_1269/dto/VehicleInfoDto.java | 68 ++++++++++++++++ .../test/bugs/_1269/mapper/VehicleMapper.java | 40 ++++++++++ .../ap/test/bugs/_1269/model/Vehicle.java | 44 +++++++++++ .../test/bugs/_1269/model/VehicleImage.java | 42 ++++++++++ .../bugs/_1269/model/VehicleTypeInfo.java | 49 ++++++++++++ 10 files changed, 435 insertions(+), 5 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/Issue1269Test.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleDto.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleImageDto.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleInfoDto.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/mapper/VehicleMapper.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/Vehicle.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleImage.java create mode 100755 processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleTypeInfo.java diff --git a/documentation/src/main/asciidoc/controlling-nested-bean-mappings.asciidoc b/documentation/src/main/asciidoc/controlling-nested-bean-mappings.asciidoc index 4fdcdf557..113d39bdc 100644 --- a/documentation/src/main/asciidoc/controlling-nested-bean-mappings.asciidoc +++ b/documentation/src/main/asciidoc/controlling-nested-bean-mappings.asciidoc @@ -85,3 +85,9 @@ Instead of configuring everything via the parent method we encourage users to ex This puts the configuration of the nested mapping into one place (method) where it can be reused from several methods in the upper level, instead of re-configuring the same things on all of those upper methods. ==== + +[NOTE] +==== +In some cases the `ReportingPolicy` that is going to be used for the generated nested method would be `IGNORE`. +This means that it is possible for MapStruct not to report unmapped target properties in nested mappings. +==== 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 730b91c1e..7dd3ca680 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 @@ -155,7 +155,8 @@ public class NestedTargetPropertyMappingHolder { entryByTP.getValue(), groupedByTP.singleTargetReferences.get( targetProperty ) ); - boolean forceUpdateMethod = groupedBySourceParam.groupedBySourceParameter.keySet().size() > 1; + boolean multipleSourceParametersForTP = + groupedBySourceParam.groupedBySourceParameter.keySet().size() > 1; // All not processed mappings that should have been applied to all are part of the unprocessed // defined targets @@ -180,9 +181,21 @@ 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) + // MappingOptions for forged methods is also created if we have something like this: + //@Mappings({ + // @Mapping(target = "vehicleInfo", source = "vehicleTypeInfo"), + // @Mapping(target = "vehicleInfo.images", source = "images") + //}) + // See Issue1269Test, Issue1247Test, AutomappingAndNestedTest for more info as well MappingOptions sourceMappingOptions = MappingOptions.forMappingsOnly( groupByTargetName( entryBySP.getValue() ), - forceUpdateMethod + multipleSourceParametersForTP, + forceUpdateMethodOrNonNestedReferencesPresent ); SourceReference sourceRef = new SourceReference.BuilderFromProperty() .sourceParameter( sourceParameter ) @@ -192,11 +205,14 @@ public class NestedTargetPropertyMappingHolder { .name( targetProperty.getName() ) .build(); + // If we have multiple source parameters that are mapped to the target reference, or + // parts of the nested properties are mapped to different sources (see comment above as well) + // we would force an update method PropertyMapping propertyMapping = createPropertyMappingForNestedTarget( sourceMappingOptions, targetProperty, sourceRef, - forceUpdateMethod + forceUpdateMethodOrNonNestedReferencesPresent ); if ( propertyMapping != null ) { @@ -219,11 +235,17 @@ public class NestedTargetPropertyMappingHolder { .name( targetProperty.getName() ) .build(); + boolean forceUpdateMethodForNonNested = + multipleSourceParametersForTP || + !groupedSourceReferences.groupedBySourceReferences.isEmpty(); + // If an update method is forced or there are groupedBySourceReferences then we must create + // an update method. The reason is that they might be for the same reference and we should + // use update for it PropertyMapping propertyMapping = createPropertyMappingForNestedTarget( nonNestedOptions, targetProperty, reference, - forceUpdateMethod + forceUpdateMethodForNonNested ); if ( propertyMapping != null ) { @@ -237,7 +259,7 @@ public class NestedTargetPropertyMappingHolder { groupedSourceReferences.sourceParameterMappings, targetProperty, sourceParameter, - forceUpdateMethod + multipleSourceParametersForTP ); unprocessedDefinedTarget.put( targetProperty, groupedSourceReferences.notProcessedAppliesToAll ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/Issue1269Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/Issue1269Test.java new file mode 100644 index 000000000..9329eddab --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/Issue1269Test.java @@ -0,0 +1,78 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.bugs._1269.dto.VehicleDto; +import org.mapstruct.ap.test.bugs._1269.dto.VehicleImageDto; +import org.mapstruct.ap.test.bugs._1269.dto.VehicleInfoDto; +import org.mapstruct.ap.test.bugs._1269.mapper.VehicleMapper; +import org.mapstruct.ap.test.bugs._1269.model.Vehicle; +import org.mapstruct.ap.test.bugs._1269.model.VehicleImage; +import org.mapstruct.ap.test.bugs._1269.model.VehicleTypeInfo; +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( "1269" ) +@RunWith( AnnotationProcessorTestRunner.class ) +@WithClasses( { + VehicleDto.class, + VehicleImageDto.class, + VehicleInfoDto.class, + Vehicle.class, + VehicleImage.class, + VehicleTypeInfo.class, + VehicleMapper.class +} ) +public class Issue1269Test { + + @Test + public void shouldMapNestedPropertiesCorrectly() { + + VehicleTypeInfo sourceTypeInfo = new VehicleTypeInfo( "Opel", "Corsa", 3 ); + + List sourceImages = Arrays.asList( + new VehicleImage( 100, "something" ), + new VehicleImage( 150, "somethingElse" ) + ); + Vehicle source = new Vehicle( sourceTypeInfo, sourceImages ); + + VehicleDto target = VehicleMapper.INSTANCE.map( source ); + + assertThat( target.getVehicleInfo() ).isNotNull(); + assertThat( target.getVehicleInfo().getDoors() ).isEqualTo( 3 ); + assertThat( target.getVehicleInfo().getType() ).isEqualTo( "Opel" ); + assertThat( target.getVehicleInfo().getName() ).isEqualTo( "Corsa" ); + assertThat( target.getVehicleInfo().getImages() ).hasSize( 2 ); + assertThat( target.getVehicleInfo().getImages().get( 0 ) ) + .isEqualToComparingFieldByField( sourceImages.get( 0 ) ); + assertThat( target.getVehicleInfo().getImages().get( 1 ) ) + .isEqualToComparingFieldByField( sourceImages.get( 1 ) ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleDto.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleDto.java new file mode 100755 index 000000000..046972b5f --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleDto.java @@ -0,0 +1,36 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.dto; + +/** + * @author Filip Hrisafov + */ +public class VehicleDto { + + private VehicleInfoDto vehicleInfo; + + public VehicleInfoDto getVehicleInfo() { + return vehicleInfo; + } + + public void setVehicleInfo(VehicleInfoDto vehicleInfo) { + this.vehicleInfo = vehicleInfo; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleImageDto.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleImageDto.java new file mode 100755 index 000000000..50de755f7 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleImageDto.java @@ -0,0 +1,45 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.dto; + +/** + * @author Filip Hrisafov + */ +public class VehicleImageDto { + + private Integer pictureSize; + + private String src; + + public Integer getPictureSize() { + return pictureSize; + } + + public void setPictureSize(Integer pictureSize) { + this.pictureSize = pictureSize; + } + + public String getSrc() { + return src; + } + + public void setSrc(String src) { + this.src = src; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleInfoDto.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleInfoDto.java new file mode 100755 index 000000000..55f6ef7dd --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/dto/VehicleInfoDto.java @@ -0,0 +1,68 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.dto; + +import java.util.List; + +/** + * @author Filip Hrisafov + */ +public class VehicleInfoDto { + + private String type; + + private String name; + + private Integer doors; + + // make sure that mapping on images does not happen based on images mapping + private List images; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDoors() { + return doors; + } + + public void setDoors(Integer doors) { + this.doors = doors; + } + + public List getImages() { + return images; + } + + public void setImages(List images) { + this.images = images; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/mapper/VehicleMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/mapper/VehicleMapper.java new file mode 100755 index 000000000..9db3fdfb0 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/mapper/VehicleMapper.java @@ -0,0 +1,40 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.ap.test.bugs._1269.dto.VehicleDto; +import org.mapstruct.ap.test.bugs._1269.model.Vehicle; +import org.mapstruct.factory.Mappers; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface VehicleMapper { + VehicleMapper INSTANCE = Mappers.getMapper( VehicleMapper.class ); + + @Mappings({ + @Mapping(target = "vehicleInfo", source = "vehicleTypeInfo"), + @Mapping(target = "vehicleInfo.images", source = "images") + }) + VehicleDto map(Vehicle in); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/Vehicle.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/Vehicle.java new file mode 100755 index 000000000..ba19f8d16 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/Vehicle.java @@ -0,0 +1,44 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.model; + +import java.util.List; + +/** + * @author Filip Hrisafov + */ +public class Vehicle { + + private final VehicleTypeInfo vehicleTypeInfo; + + private final List images; + + public Vehicle(VehicleTypeInfo vehicleTypeInfo, List images) { + this.vehicleTypeInfo = vehicleTypeInfo; + this.images = images; + } + + public VehicleTypeInfo getVehicleTypeInfo() { + return vehicleTypeInfo; + } + + public List getImages() { + return images; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleImage.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleImage.java new file mode 100755 index 000000000..f9ff4fed4 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleImage.java @@ -0,0 +1,42 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.model; + +/** + * @author Filip Hrisafov + */ +public class VehicleImage { + + private final Integer pictureSize; + + private final String src; + + public VehicleImage(Integer pictureSize, String src) { + this.pictureSize = pictureSize; + this.src = src; + } + + public Integer getPictureSize() { + return pictureSize; + } + + public String getSrc() { + return src; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleTypeInfo.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleTypeInfo.java new file mode 100755 index 000000000..dc803dc52 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1269/model/VehicleTypeInfo.java @@ -0,0 +1,49 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1269.model; + +/** + * @author Filip Hrisafov + */ +public class VehicleTypeInfo { + + private final String type; + + private final String name; + + private final Integer doors; + + public VehicleTypeInfo(String type, String name, Integer doors) { + this.type = type; + this.name = name; + this.doors = doors; + } + + public String getType() { + return type; + } + + public String getName() { + return name; + } + + public Integer getDoors() { + return doors; + } +}