diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java index b683a26b8..c40128811 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java @@ -363,6 +363,24 @@ public class Type extends ModelElement implements Comparable { return 1 + minDistanceOfSuperToTargetType; } + /** + * Whether this type can access the given method declared on the given type. + */ + public boolean canAccess(Type type, ExecutableElement method) { + if ( method.getModifiers().contains( Modifier.PRIVATE ) ) { + return false; + } + else if ( method.getModifiers().contains( Modifier.PROTECTED ) ) { + return isAssignableTo( type ) || getPackageName().equals( type.getPackageName() ); + } + else if ( !method.getModifiers().contains( Modifier.PUBLIC ) ) { + // default + return getPackageName().equals( type.getPackageName() ); + } + // public + return true; + } + @Override public int hashCode() { final int prime = 31; diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java index 399c706a5..06c7eace7 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java @@ -18,13 +18,10 @@ */ package org.mapstruct.ap.processor; -import static javax.lang.model.util.ElementFilter.methodsIn; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.annotation.processing.Messager; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -50,6 +47,8 @@ import org.mapstruct.ap.prism.MappingsPrism; import org.mapstruct.ap.util.AnnotationProcessingException; import org.mapstruct.ap.util.MapperConfig; +import static javax.lang.model.util.ElementFilter.methodsIn; + /** * A {@link ModelElementProcessor} which retrieves a list of {@link SourceMethod}s * representing all the mapping methods of the given bean mapper type as well as @@ -131,6 +130,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessortrue, iff the type has a super-class that is not java.lang.Object */ private boolean hasNonObjectSuperclass(TypeElement element) { @@ -142,67 +142,78 @@ public class MethodRetrievalProcessor implements ModelElementProcessor parameters = typeFactory.getParameters( method ); - Type returnType = typeFactory.getReturnType( method ); - List exceptionTypes = typeFactory.getThrownTypes( method ); - //add method with property mappings if an implementation needs to be generated boolean methodRequiresImplementation = method.getModifiers().contains( Modifier.ABSTRACT ); boolean containsTargetTypeParameter = SourceMethod.containsTargetTypeParameter( parameters ); + //add method with property mappings if an implementation needs to be generated if ( ( usedMapper.equals( mapperToImplement ) ) && methodRequiresImplementation ) { - List sourceParameters = extractSourceParameters( parameters ); - Parameter targetParameter = extractTargetParameter( parameters ); - Type resultType = selectResultType( returnType, targetParameter ); - - boolean isValid = - checkParameterAndReturnType( - method, - sourceParameters, - targetParameter, - resultType, - returnType, - containsTargetTypeParameter ); - - if ( isValid ) { - return - SourceMethod.forMethodRequiringImplementation( - method, - parameters, - returnType, - exceptionTypes, - getMappings( method ), - IterableMapping.fromPrism( IterableMappingPrism.getInstanceOn( method ) ), - MapMapping.fromPrism( MapMappingPrism.getInstanceOn( method ) ), - typeUtils - ); - } - else { - return null; - } + return getMethodRequiringImplementation( method, parameters, containsTargetTypeParameter ); } //otherwise add reference to existing mapper method else if ( isValidReferencedMethod( parameters ) || isValidFactoryMethod( parameters ) ) { - Type usedMapperAsType = typeFactory.getType( usedMapper ); - Type mapperToImplementAsType = typeFactory.getType( mapperToImplement ); - if ( isAccessible( mapperToImplementAsType, usedMapperAsType, method ) ) { - return SourceMethod.forReferencedMethod( - usedMapper.equals( mapperToImplement ) ? null : usedMapperAsType, - method, - parameters, - returnType, - exceptionTypes, - typeUtils - ); - } - else { - return null; - } + return getReferencedMethod( usedMapper, method, mapperToImplement, parameters ); } else { return null; } } + private SourceMethod getMethodRequiringImplementation(ExecutableElement method, List parameters, + boolean containsTargetTypeParameter) { + Type returnType = typeFactory.getReturnType( method ); + List exceptionTypes = typeFactory.getThrownTypes( method ); + List sourceParameters = extractSourceParameters( parameters ); + Parameter targetParameter = extractTargetParameter( parameters ); + Type resultType = selectResultType( returnType, targetParameter ); + + boolean isValid = checkParameterAndReturnType( + method, + sourceParameters, + targetParameter, + resultType, + returnType, + containsTargetTypeParameter + ); + + if ( !isValid ) { + return null; + } + + return SourceMethod.forMethodRequiringImplementation( + method, + parameters, + returnType, + exceptionTypes, + getMappings( method ), + IterableMapping.fromPrism( IterableMappingPrism.getInstanceOn( method ) ), + MapMapping.fromPrism( MapMappingPrism.getInstanceOn( method ) ), + typeUtils + ); + } + + private SourceMethod getReferencedMethod(TypeElement usedMapper, ExecutableElement method, + TypeElement mapperToImplement, List parameters) { + Type returnType = typeFactory.getReturnType( method ); + List exceptionTypes = typeFactory.getThrownTypes( method ); + Type usedMapperAsType = typeFactory.getType( usedMapper ); + Type mapperToImplementAsType = typeFactory.getType( mapperToImplement ); + + if ( !mapperToImplementAsType.canAccess( usedMapperAsType, method ) ) { + return null; + } + + return SourceMethod.forReferencedMethod( + usedMapper.equals( mapperToImplement ) ? null : usedMapperAsType, + method, + parameters, + returnType, + exceptionTypes, + typeUtils + ); + } + + private boolean isValidReferencedMethod(List parameters) { return isValidReferencedOrFactoryMethod( 1, parameters ); } @@ -233,24 +244,6 @@ public class MethodRetrievalProcessor implements ModelElementProcessor parameters) { for ( Parameter param : parameters ) { if ( param.isMappingTarget() ) { @@ -328,7 +321,8 @@ public class MethodRetrievalProcessor implements ModelElementProcessor