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 1fca26a7c..348a3468f 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -31,11 +31,8 @@ import javax.annotation.processing.Messager; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; @@ -818,19 +815,20 @@ public class MapperCreationProcessor implements ModelElementProcessor targetTypeConstructors = ElementFilter.constructorsIn( - targetType.getTypeElement() - .getEnclosedElements() - ); + private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) { + // note (issue #127): actually this should check for the presence of a matching constructor, with help of + // Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we + // just check whether the target type is parameterized in a way that it implicitly should have a constructor + // which accepts the source type - for ( ExecutableElement constructor : targetTypeConstructors ) { - if ( constructor.getParameters().size() != 1 ) { - continue; - } + TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty() ? + typeFactory.getType( Object.class ).getTypeMirror() : + sourceType.getTypeParameters().get( 0 ).getTypeMirror(); - //get the constructor resolved against the type arguments of specific target type - ExecutableType typedConstructor = (ExecutableType) typeUtils.asMemberOf( - (DeclaredType) targetType.getTypeMirror(), constructor - ); + TypeMirror targetElementType = targetType.getTypeParameters().isEmpty() ? + typeFactory.getType( Object.class ).getTypeMirror() : + targetType.getTypeParameters().get( 0 ).getTypeMirror(); - if ( typeUtils.isAssignable( - sourceType.getTypeMirror(), - typedConstructor.getParameterTypes().iterator().next() - ) ) { - return true; - } + return typeUtils.isAssignable( sourceElementType, targetElementType ); + } + + /** + * Whether the given target type has a single-argument constructor which accepts the given source type. + * + * @param sourceType the source type + * @param targetType the target type + * + * @return {@code true} if the target type has a constructor accepting the given source type, {@code false} + * otherwise. + */ + private boolean mapTypeHasCompatibleConstructor(Type sourceType, Type targetType) { + // note (issue #127): actually this should check for the presence of a matching constructor, with help of + // Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we + // just check whether the target type is parameterized in a way that it implicitly should have a constructor + // which accepts the source type + + TypeMirror sourceKeyType = null; + TypeMirror targetKeyType = null; + TypeMirror sourceValueType = null; + TypeMirror targetValueType = null; + + if ( sourceType.getTypeParameters().isEmpty() ) { + sourceKeyType = typeFactory.getType( Object.class ).getTypeMirror(); + sourceValueType = typeFactory.getType( Object.class ).getTypeMirror(); + } + else { + sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror(); + sourceValueType = sourceType.getTypeParameters().get( 1 ).getTypeMirror(); } - return false; + if ( targetType.getTypeParameters().isEmpty() ) { + targetKeyType = typeFactory.getType( Object.class ).getTypeMirror(); + targetValueType = typeFactory.getType( Object.class ).getTypeMirror(); + } + else { + targetKeyType = targetType.getTypeParameters().get( 0 ).getTypeMirror(); + targetValueType = targetType.getTypeParameters().get( 1 ).getTypeMirror(); + } + + return typeUtils.isAssignable( sourceKeyType, targetKeyType ) && + typeUtils.isAssignable( sourceValueType, targetValueType ); } /**