diff --git a/processor/src/main/java/org/mapstruct/ap/model/Type.java b/processor/src/main/java/org/mapstruct/ap/model/Type.java index 666a0a361..afa9d6deb 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Type.java @@ -53,7 +53,6 @@ public class Type extends AbstractModelElement implements Comparable { private final boolean isEnumType; private final boolean isIterableType; private final boolean isCollectionType; - private final boolean isListType; private final boolean isMapType; private final Type implementationType; private final TypeMirror typeMirror; @@ -61,14 +60,13 @@ public class Type extends AbstractModelElement implements Comparable { private final TypeElement typeElement; public Type(TypeMirror typeMirror, List typeParameters, Type implementationType, boolean isIterableType, - boolean isCollectionType, boolean isListType, boolean isMapType, Types typeUtils, + boolean isCollectionType, boolean isMapType, Types typeUtils, Elements elementUtils) { this.typeMirror = typeMirror; this.implementationType = implementationType; this.typeParameters = typeParameters; this.isIterableType = isIterableType; this.isCollectionType = isCollectionType; - this.isListType = isListType; this.isMapType = isMapType; this.typeUtils = typeUtils; @@ -152,10 +150,6 @@ public class Type extends AbstractModelElement implements Comparable { return isCollectionType; } - public boolean isListType() { - return isListType; - } - public boolean isMapType() { return isMapType; } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java index 6764863d1..3de17ee9e 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -284,19 +284,22 @@ public class MapperCreationProcessor implements ModelElementProcessor targetSetters = filters.setterMethodsIn( + List targetAccessors = filters.setterMethodsIn( elementUtils.getAllMembers( resultTypeElement ) ); + targetAccessors.addAll( filters.alternativeTargetAccessorMethodsIn( + elementUtils.getAllMembers( resultTypeElement ) ) + ); - for ( ExecutableElement setterMethod : targetSetters ) { - String targetPropertyName = executables.getPropertyName( setterMethod ); + for ( ExecutableElement targetAccessor : targetAccessors ) { + String targetPropertyName = executables.getPropertyName( targetAccessor ); Mapping mapping = method.getMapping( targetPropertyName ); PropertyMapping propertyMapping = null; if ( mapping != null && mapping.getSourceParameterName() != null ) { Parameter parameter = method.getSourceParameter( mapping.getSourceParameterName() ); - propertyMapping = getPropertyMapping( methods, method, setterMethod, parameter ); + propertyMapping = getPropertyMapping( methods, method, targetAccessor, parameter ); } if ( propertyMapping == null ) { @@ -304,7 +307,7 @@ public class MapperCreationProcessor implements ModelElementProcessor targetProperties = executables.getPropertyNames( targetSetters ); + Set targetProperties = executables.getPropertyNames( targetAccessors ); reportErrorForUnmappedTargetPropertiesIfRequired( method, @@ -380,20 +383,24 @@ public class MapperCreationProcessor implements ModelElementProcessor getters = filters.setterMethodsIn( + List targetAccessors = filters.setterMethodsIn( elementUtils.getAllMembers( parameterTypeElement ) ); - - return executables.getPropertyNames( getters ).contains( propertyName ); + targetAccessors.addAll( filters.alternativeTargetAccessorMethodsIn( + elementUtils.getAllMembers( parameterTypeElement ) ) + ); + return executables.getPropertyNames( targetAccessors ).contains( propertyName ); } private boolean reportErrorIfMappedPropertiesDontExist(Method method) { TypeElement resultTypeElement = method.getResultType().getTypeElement(); - List targetSetters = filters.setterMethodsIn( + List targetAccessors = filters.setterMethodsIn( elementUtils.getAllMembers( resultTypeElement ) ); - - Set targetProperties = executables.getPropertyNames( targetSetters ); + targetAccessors.addAll( filters.alternativeTargetAccessorMethodsIn( + elementUtils.getAllMembers( resultTypeElement ) ) + ); + Set targetProperties = executables.getPropertyNames( targetAccessors ); boolean foundUnmappedProperty = false; diff --git a/processor/src/main/java/org/mapstruct/ap/util/Filters.java b/processor/src/main/java/org/mapstruct/ap/util/Filters.java index 7d19f460c..b8f271e19 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/Filters.java +++ b/processor/src/main/java/org/mapstruct/ap/util/Filters.java @@ -52,16 +52,28 @@ public class Filters { public List setterMethodsIn(Iterable elements) { List setterMethods = new LinkedList(); - List getterMethods = new LinkedList(); for ( ExecutableElement method : methodsIn( elements ) ) { if ( executables.isSetterMethod( method ) ) { setterMethods.add( method ); } - else if ( executables.isGetterMethod( method ) ) { - getterMethods.add( method ); - } } + return setterMethods; + } + + /** + * A getter could be an alternative target-accessor if a setter is not available, and the + * target is a collection. + * + * Provided such a getter is initialized lazy by the target class, e.g. in generated JAXB beans. + * + * @param elements + * @return + */ + public List alternativeTargetAccessorMethodsIn(Iterable elements) { + List setterMethods = setterMethodsIn( elements ); + List getterMethods = getterMethodsIn( elements ); + List alternativeTargetAccessorsMethods = new LinkedList(); if (getterMethods.size() > setterMethods.size()) { // there could be a getter method for a list that is not present as setter. @@ -77,12 +89,12 @@ public class Filters { break; } } - if ( !matchFound && executables.retrieveReturnType( getterMethod ).isListType() ) { - setterMethods.add( getterMethod ); + if ( !matchFound && executables.retrieveReturnType( getterMethod ).isCollectionType() ) { + alternativeTargetAccessorsMethods.add( getterMethod ); } } } - return setterMethods; + return alternativeTargetAccessorsMethods; } } diff --git a/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java index 64bfe6c0b..590f9c620 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java @@ -117,10 +117,6 @@ public class TypeFactory { mirror, collectionType ); - boolean isListType = typeUtils.isSubtype( - mirror, - listType - ); boolean isMapType = typeUtils.isSubtype( mirror, mapType @@ -132,7 +128,6 @@ public class TypeFactory { implementationType, isIterableType, isCollectionType, - isListType, isMapType, typeUtils, elementUtils @@ -188,7 +183,6 @@ public class TypeFactory { null, implementationType.isIterableType(), implementationType.isCollectionType(), - implementationType.isListType(), implementationType.isMapType(), typeUtils, elementUtils diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/CollectionMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/CollectionMappingTest.java index a616a192e..b634f245a 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/CollectionMappingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/CollectionMappingTest.java @@ -71,7 +71,7 @@ public class CollectionMappingTest extends MapperTestBase { } @Test - @IssueKey("6") + @IssueKey("92") public void shouldMapListWithoutSetter() { Source source = new Source(); source.setStringList2( Arrays.asList( "Bob", "Alice" ) ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java index 0d2750b97..3c0f3170d 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java @@ -171,7 +171,7 @@ public class DefaultCollectionImplementationTest extends MapperTestBase { } @Test - @IssueKey("6") + @IssueKey("92") public void shouldUseDefaultImplementationForListWithoutSetter() { Source source = new Source(); source.setFooList( createSourceFooList() );