mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#206 Moving canAccess() method to Type; Splitting up MethodRetrievalProcessor#getMethod()
This commit is contained in:
parent
a77a693d9d
commit
fc2bd954c6
@ -363,6 +363,24 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
return 1 + minDistanceOfSuperToTargetType;
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
|
@ -18,13 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.processor;
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
import static javax.lang.model.util.ElementFilter.methodsIn;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.processing.Messager;
|
import javax.annotation.processing.Messager;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
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.AnnotationProcessingException;
|
||||||
import org.mapstruct.ap.util.MapperConfig;
|
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
|
* 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
|
* representing all the mapping methods of the given bean mapper type as well as
|
||||||
@ -131,6 +130,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param element the type element to check
|
* @param element the type element to check
|
||||||
|
*
|
||||||
* @return <code>true</code>, iff the type has a super-class that is not java.lang.Object
|
* @return <code>true</code>, iff the type has a super-class that is not java.lang.Object
|
||||||
*/
|
*/
|
||||||
private boolean hasNonObjectSuperclass(TypeElement element) {
|
private boolean hasNonObjectSuperclass(TypeElement element) {
|
||||||
@ -142,67 +142,78 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
ExecutableElement method,
|
ExecutableElement method,
|
||||||
TypeElement mapperToImplement) {
|
TypeElement mapperToImplement) {
|
||||||
List<Parameter> parameters = typeFactory.getParameters( method );
|
List<Parameter> parameters = typeFactory.getParameters( method );
|
||||||
Type returnType = typeFactory.getReturnType( method );
|
|
||||||
List<Type> exceptionTypes = typeFactory.getThrownTypes( method );
|
|
||||||
|
|
||||||
//add method with property mappings if an implementation needs to be generated
|
|
||||||
boolean methodRequiresImplementation = method.getModifiers().contains( Modifier.ABSTRACT );
|
boolean methodRequiresImplementation = method.getModifiers().contains( Modifier.ABSTRACT );
|
||||||
boolean containsTargetTypeParameter = SourceMethod.containsTargetTypeParameter( parameters );
|
boolean containsTargetTypeParameter = SourceMethod.containsTargetTypeParameter( parameters );
|
||||||
|
|
||||||
|
//add method with property mappings if an implementation needs to be generated
|
||||||
if ( ( usedMapper.equals( mapperToImplement ) ) && methodRequiresImplementation ) {
|
if ( ( usedMapper.equals( mapperToImplement ) ) && methodRequiresImplementation ) {
|
||||||
List<Parameter> sourceParameters = extractSourceParameters( parameters );
|
return getMethodRequiringImplementation( method, parameters, containsTargetTypeParameter );
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//otherwise add reference to existing mapper method
|
//otherwise add reference to existing mapper method
|
||||||
else if ( isValidReferencedMethod( parameters ) || isValidFactoryMethod( parameters ) ) {
|
else if ( isValidReferencedMethod( parameters ) || isValidFactoryMethod( parameters ) ) {
|
||||||
Type usedMapperAsType = typeFactory.getType( usedMapper );
|
return getReferencedMethod( usedMapper, method, mapperToImplement, parameters );
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SourceMethod getMethodRequiringImplementation(ExecutableElement method, List<Parameter> parameters,
|
||||||
|
boolean containsTargetTypeParameter) {
|
||||||
|
Type returnType = typeFactory.getReturnType( method );
|
||||||
|
List<Type> exceptionTypes = typeFactory.getThrownTypes( method );
|
||||||
|
List<Parameter> 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<Parameter> parameters) {
|
||||||
|
Type returnType = typeFactory.getReturnType( method );
|
||||||
|
List<Type> 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<Parameter> parameters) {
|
private boolean isValidReferencedMethod(List<Parameter> parameters) {
|
||||||
return isValidReferencedOrFactoryMethod( 1, parameters );
|
return isValidReferencedOrFactoryMethod( 1, parameters );
|
||||||
}
|
}
|
||||||
@ -233,24 +244,6 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
&& parameters.size() == validSourceParameters + targetParameters + targetTypeParameters;
|
&& parameters.size() == validSourceParameters + targetParameters + targetTypeParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isAccessible( Type mapperToImplement, Type usedMapper, ExecutableElement method ) {
|
|
||||||
|
|
||||||
if ( method.getModifiers().contains( Modifier.PRIVATE ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if ( method.getModifiers().contains( Modifier.PROTECTED ) ) {
|
|
||||||
return mapperToImplement.isAssignableTo( usedMapper ) ||
|
|
||||||
mapperToImplement.getPackageName().equals( usedMapper.getPackageName() );
|
|
||||||
}
|
|
||||||
else if ( !method.getModifiers().contains( Modifier.PUBLIC ) ) {
|
|
||||||
// default
|
|
||||||
return mapperToImplement.getPackageName().equals( usedMapper.getPackageName() );
|
|
||||||
}
|
|
||||||
// public
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Parameter extractTargetParameter(List<Parameter> parameters) {
|
private Parameter extractTargetParameter(List<Parameter> parameters) {
|
||||||
for ( Parameter param : parameters ) {
|
for ( Parameter param : parameters ) {
|
||||||
if ( param.isMappingTarget() ) {
|
if ( param.isMappingTarget() ) {
|
||||||
@ -328,7 +321,8 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
Kind.ERROR,
|
Kind.ERROR,
|
||||||
"Can't generate mapping method that has a parameter annotated with @TargetType.",
|
"Can't generate mapping method that has a parameter annotated with @TargetType.",
|
||||||
method );
|
method
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,6 @@ public class ReferencedAccessibilityTest {
|
|||||||
@WithClasses( { AbstractSourceTargetMapperProtected.class, SourceTargetmapperProtectedBase.class } )
|
@WithClasses( { AbstractSourceTargetMapperProtected.class, SourceTargetmapperProtectedBase.class } )
|
||||||
public void shouldBeAbleToAccessProtectedMethodInBase() throws Exception { }
|
public void shouldBeAbleToAccessProtectedMethodInBase() throws Exception { }
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@IssueKey( "206" )
|
@IssueKey( "206" )
|
||||||
@WithClasses( { AbstractSourceTargetMapperPrivate.class, SourceTargetmapperPrivateBase.class } )
|
@WithClasses( { AbstractSourceTargetMapperPrivate.class, SourceTargetmapperPrivateBase.class } )
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
package org.mapstruct.ap.test.accessibility.referenced;
|
package org.mapstruct.ap.test.accessibility.referenced;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public class ReferencedMapperPrivate {
|
public class ReferencedMapperPrivate {
|
||||||
|
|
||||||
private ReferencedTarget sourceToTarget( ReferencedSource source ) {
|
@SuppressWarnings("unused")
|
||||||
|
private ReferencedTarget sourceToTarget(ReferencedSource source) {
|
||||||
ReferencedTarget target = new ReferencedTarget();
|
ReferencedTarget target = new ReferencedTarget();
|
||||||
target.setFoo( source.getFoo() );
|
target.setFoo( source.getFoo() );
|
||||||
return target;
|
return target;
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
package org.mapstruct.ap.test.accessibility.referenced;
|
package org.mapstruct.ap.test.accessibility.referenced;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public class SourceTargetmapperPrivateBase {
|
public class SourceTargetmapperPrivateBase {
|
||||||
|
|
||||||
private ReferencedTarget sourceToTarget( ReferencedSource source ) {
|
@SuppressWarnings("unused")
|
||||||
|
private ReferencedTarget sourceToTarget(ReferencedSource source) {
|
||||||
ReferencedTarget target = new ReferencedTarget();
|
ReferencedTarget target = new ReferencedTarget();
|
||||||
target.setFoo( source.getFoo() );
|
target.setFoo( source.getFoo() );
|
||||||
return target;
|
return target;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user