From cf19a6b637e2570580b32a94b357e0f31559c1de Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 28 Apr 2018 09:09:44 +0200 Subject: [PATCH] #1423 Updating types that have a builder should be allowed It is possible that a type has both a builder and accessors. In such case doing an update to this type should be allowed --- .../ap/internal/model/BeanMappingMethod.java | 13 +++- .../ap/internal/model/PropertyMapping.java | 6 +- .../model/source/TargetReference.java | 22 +++++- .../processor/MethodRetrievalProcessor.java | 5 -- .../mapstruct/ap/internal/util/Message.java | 1 - .../simple/BuilderInfoTargetTest.java | 55 +++++++++---- .../simple/ErroneousSimpleBuilderMapper.java | 27 ------- .../mappingTarget/simple/MutableTarget.java | 78 +++++++++++++++++++ .../simple/SimpleBuilderMapper.java | 9 +++ 9 files changed, 162 insertions(+), 54 deletions(-) delete mode 100644 processor/src/test/java/org/mapstruct/ap/test/builder/mappingTarget/simple/ErroneousSimpleBuilderMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/builder/mappingTarget/simple/MutableTarget.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index 4886e475e..059a1c7ba 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -115,8 +115,12 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { this.method = sourceMethod; this.methodMappings = sourceMethod.getMappingOptions().getMappings(); CollectionMappingStrategyPrism cms = sourceMethod.getMapperConfiguration().getCollectionMappingStrategy(); - Map accessors = method.getResultType() - .getEffectiveType() + Type mappingType = method.getResultType(); + if ( !method.isUpdateMethod() ) { + mappingType = mappingType.getEffectiveType(); + } + + Map accessors = mappingType .getPropertyWriteAccessors( cms ); this.targetProperties = accessors.keySet(); @@ -885,7 +889,10 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { types.addAll( propertyMapping.getImportTypes() ); } - types.add( getResultType().getEffectiveType() ); + if ( !isExistingInstanceMapping() ) { + types.addAll( getResultType().getEffectiveType().getImportTypes() ); + } + return types; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java index 3ed0abaf6..cb48c23d5 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java @@ -155,7 +155,11 @@ public class PropertyMapping extends ModelElement { private Type determineTargetType() { // This is a bean mapping method, so we know the result is a declared type - DeclaredType resultType = (DeclaredType) method.getResultType().getEffectiveType().getTypeMirror(); + Type mappingType = method.getResultType(); + if ( !method.isUpdateMethod() ) { + mappingType = mappingType.getEffectiveType(); + } + DeclaredType resultType = (DeclaredType) mappingType.getTypeMirror(); switch ( targetWriteAccessorType ) { case ADDER: diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java index fc9da4869..5b48d54cc 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/TargetReference.java @@ -153,7 +153,7 @@ public class TargetReference { boolean foundEntryMatch; Type resultType = method.getResultType(); - resultType = resultType.getEffectiveType(); + resultType = typeBasedOnMethod( resultType ); // there can be 4 situations // 1. Return type @@ -191,7 +191,7 @@ public class TargetReference { // last entry for ( int i = 0; i < entryNames.length; i++ ) { - Type mappingType = nextType.getEffectiveType(); + Type mappingType = typeBasedOnMethod( nextType ); Accessor targetReadAccessor = mappingType.getPropertyReadAccessors().get( entryNames[i] ); Accessor targetWriteAccessor = mappingType.getPropertyWriteAccessors( cms ).get( entryNames[i] ); boolean isLast = i == entryNames.length - 1; @@ -237,13 +237,13 @@ public class TargetReference { if ( Executables.isGetterMethod( toUse ) || Executables.isFieldAccessor( toUse ) ) { nextType = typeFactory.getReturnType( - (DeclaredType) initial.getEffectiveType().getTypeMirror(), + (DeclaredType) typeBasedOnMethod( initial ).getTypeMirror(), toUse ); } else { nextType = typeFactory.getSingleParameter( - (DeclaredType) initial.getEffectiveType().getTypeMirror(), + (DeclaredType) typeBasedOnMethod( initial ).getTypeMirror(), toUse ).getType(); } @@ -264,6 +264,20 @@ public class TargetReference { } } + /** + * When we are in an update method, i.e. source parameter with {@code @MappingTarget} then the type should + * be itself, otherwise, we always get the effective type. The reason is that when doing updates we always + * search for setters and getters within the updating type. + */ + private Type typeBasedOnMethod(Type type) { + if ( method.isUpdateMethod() ) { + return type; + } + else { + return type.getEffectiveType(); + } + } + /** * A write accessor is not valid if it is {@code null} and it is not last. i.e. for nested target mappings * there must be a write accessor for all entries except the last one. diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java index 6dfed43c5..19e3d538f 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java @@ -403,11 +403,6 @@ public class MethodRetrievalProcessor implements ModelElementProcessor