#3280 Refactor method selection and use a context to be able to more easily access information

This commit is contained in:
Filip Hrisafov 2023-05-27 15:04:34 +02:00 committed by GitHub
parent c2eed45df1
commit 62d1bd3490
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 302 additions and 228 deletions

View File

@ -6,7 +6,6 @@
package org.mapstruct.ap.internal.model; package org.mapstruct.ap.internal.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -19,7 +18,7 @@ import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.model.source.SourceMethod; import org.mapstruct.ap.internal.model.source.SourceMethod;
import org.mapstruct.ap.internal.model.source.selector.MethodSelectors; import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod; import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.model.source.selector.SelectionContext;
/** /**
* Factory for creating lists of appropriate {@link LifecycleCallbackMethodReference}s * Factory for creating lists of appropriate {@link LifecycleCallbackMethodReference}s
@ -134,15 +133,12 @@ public final class LifecycleMethodResolver {
MappingBuilderContext ctx, Set<String> existingVariableNames) { MappingBuilderContext ctx, Set<String> existingVariableNames) {
MethodSelectors selectors = MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory(), ctx.getMessager() ); new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager() );
List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods( List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods(
method,
callbackMethods, callbackMethods,
Collections.emptyList(), SelectionContext.forLifecycleMethods( method, targetType, selectionParameters, ctx.getTypeFactory() )
targetType, );
method.getResultType(),
SelectionCriteria.forLifecycleMethods( selectionParameters ) );
return toLifecycleCallbackMethodRefs( return toLifecycleCallbackMethodRefs(
method, method,

View File

@ -23,7 +23,7 @@ import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.model.source.SourceMethod; import org.mapstruct.ap.internal.model.source.SourceMethod;
import org.mapstruct.ap.internal.model.source.selector.MethodSelectors; import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod; import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.model.source.selector.SelectionContext;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
/** /**
@ -126,15 +126,11 @@ public class ObjectFactoryMethodResolver {
MappingBuilderContext ctx) { MappingBuilderContext ctx) {
MethodSelectors selectors = MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory(), ctx.getMessager() ); new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager() );
return selectors.getMatchingMethods( return selectors.getMatchingMethods(
method,
getAllAvailableMethods( method, ctx.getSourceModel() ), getAllAvailableMethods( method, ctx.getSourceModel() ),
java.util.Collections.emptyList(), SelectionContext.forFactoryMethods( method, alternativeTarget, selectionParameters, ctx.getTypeFactory() )
alternativeTarget,
alternativeTarget,
SelectionCriteria.forFactoryMethods( selectionParameters )
); );
} }

View File

@ -6,20 +6,18 @@
package org.mapstruct.ap.internal.model; package org.mapstruct.ap.internal.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.PresenceCheck; import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods; import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods;
import org.mapstruct.ap.internal.model.source.SelectionParameters; import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.model.source.SourceMethod; import org.mapstruct.ap.internal.model.source.SourceMethod;
import org.mapstruct.ap.internal.model.source.selector.MethodSelectors; import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod; import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.model.source.selector.SelectionContext;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
/** /**
@ -60,18 +58,12 @@ public final class PresenceCheckMethodResolver {
MethodSelectors selectors = new MethodSelectors( MethodSelectors selectors = new MethodSelectors(
ctx.getTypeUtils(), ctx.getTypeUtils(),
ctx.getElementUtils(), ctx.getElementUtils(),
ctx.getTypeFactory(),
ctx.getMessager() ctx.getMessager()
); );
Type booleanType = ctx.getTypeFactory().getType( Boolean.class );
List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods( List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods(
method,
getAllAvailableMethods( method, ctx.getSourceModel() ), getAllAvailableMethods( method, ctx.getSourceModel() ),
Collections.emptyList(), SelectionContext.forPresenceCheckMethods( method, selectionParameters, ctx.getTypeFactory() )
booleanType,
booleanType,
SelectionCriteria.forPresenceCheckMethods( selectionParameters )
); );
if ( matchingMethods.isEmpty() ) { if ( matchingMethods.isEmpty() ) {

View File

@ -8,7 +8,6 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
/** /**
@ -29,13 +28,9 @@ import org.mapstruct.ap.internal.model.source.Method;
public class CreateOrUpdateSelector implements MethodSelector { public class CreateOrUpdateSelector implements MethodSelector {
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes, SelectionCriteria criteria = context.getSelectionCriteria();
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
if ( criteria.isLifecycleCallbackRequired() || criteria.isObjectFactoryRequired() if ( criteria.isLifecycleCallbackRequired() || criteria.isObjectFactoryRequired()
|| criteria.isPresenceCheckRequired() ) { || criteria.isPresenceCheckRequired() ) {
return methods; return methods;

View File

@ -8,7 +8,6 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
/** /**
@ -21,11 +20,9 @@ import org.mapstruct.ap.internal.model.source.Method;
public class FactoryParameterSelector implements MethodSelector { public class FactoryParameterSelector implements MethodSelector {
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes, SelectionCriteria criteria = context.getSelectionCriteria();
Type mappingTargetType, Type returnType,
SelectionCriteria criteria) {
if ( !criteria.isObjectFactoryRequired() || methods.size() <= 1 ) { if ( !criteria.isObjectFactoryRequired() || methods.size() <= 1 ) {
return methods; return methods;
} }

View File

@ -22,18 +22,14 @@ import org.mapstruct.ap.internal.model.source.Method;
public class InheritanceSelector implements MethodSelector { public class InheritanceSelector implements MethodSelector {
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes,
Type mappingTargetType, Type returnType,
SelectionCriteria criteria) {
if ( sourceTypes.size() != 1 ) { Type sourceType = context.getSourceType();
if ( sourceType == null ) {
return methods; return methods;
} }
Type singleSourceType = first( sourceTypes );
List<SelectedMethod<T>> candidatesWithBestMatchingSourceType = new ArrayList<>(); List<SelectedMethod<T>> candidatesWithBestMatchingSourceType = new ArrayList<>();
int bestMatchingSourceTypeDistance = Integer.MAX_VALUE; int bestMatchingSourceTypeDistance = Integer.MAX_VALUE;
@ -41,7 +37,7 @@ public class InheritanceSelector implements MethodSelector {
for ( SelectedMethod<T> method : methods ) { for ( SelectedMethod<T> method : methods ) {
Parameter singleSourceParam = first( method.getMethod().getSourceParameters() ); Parameter singleSourceParam = first( method.getMethod().getSourceParameters() );
int sourceTypeDistance = singleSourceType.distanceTo( singleSourceParam.getType() ); int sourceTypeDistance = sourceType.distanceTo( singleSourceParam.getType() );
bestMatchingSourceTypeDistance = bestMatchingSourceTypeDistance =
addToCandidateListIfMinimal( addToCandidateListIfMinimal(
candidatesWithBestMatchingSourceType, candidatesWithBestMatchingSourceType,

View File

@ -8,7 +8,6 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
/** /**
@ -20,12 +19,9 @@ import org.mapstruct.ap.internal.model.source.Method;
public class MethodFamilySelector implements MethodSelector { public class MethodFamilySelector implements MethodSelector {
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes, SelectionCriteria criteria = context.getSelectionCriteria();
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
List<SelectedMethod<T>> result = new ArrayList<>( methods.size() ); List<SelectedMethod<T>> result = new ArrayList<>( methods.size() );
for ( SelectedMethod<T> method : methods ) { for ( SelectedMethod<T> method : methods ) {

View File

@ -7,7 +7,6 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.List; import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
/** /**
@ -23,18 +22,10 @@ interface MethodSelector {
* Selects those methods which match the given types and other criteria * Selects those methods which match the given types and other criteria
* *
* @param <T> either SourceMethod or BuiltInMethod * @param <T> either SourceMethod or BuiltInMethod
* @param mappingMethod mapping method, defined in Mapper for which this selection is carried out
* @param candidates list of available methods * @param candidates list of available methods
* @param sourceTypes parameter type(s) that should be matched * @param context the context for the matching
* @param mappingTargetType mappingTargetType that should be matched
* @param returnType return type that should be matched
* @param criteria criteria used in the selection process
* @return list of methods that passes the matching process * @return list of methods that passes the matching process
*/ */
<T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> candidates,
List<SelectedMethod<T>> candidates, SelectionContext context);
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria);
} }

View File

@ -9,8 +9,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.util.ElementUtils; import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.FormattingMessager;
@ -25,11 +23,11 @@ public class MethodSelectors {
private final List<MethodSelector> selectors; private final List<MethodSelector> selectors;
public MethodSelectors(TypeUtils typeUtils, ElementUtils elementUtils, TypeFactory typeFactory, public MethodSelectors(TypeUtils typeUtils, ElementUtils elementUtils,
FormattingMessager messager) { FormattingMessager messager) {
selectors = Arrays.asList( selectors = Arrays.asList(
new MethodFamilySelector(), new MethodFamilySelector(),
new TypeSelector( typeFactory, messager ), new TypeSelector( messager ),
new QualifierSelector( typeUtils, elementUtils ), new QualifierSelector( typeUtils, elementUtils ),
new TargetTypeSelector( typeUtils ), new TargetTypeSelector( typeUtils ),
new JavaxXmlElementDeclSelector( typeUtils ), new JavaxXmlElementDeclSelector( typeUtils ),
@ -46,20 +44,12 @@ public class MethodSelectors {
* Selects those methods which match the given types and other criteria * Selects those methods which match the given types and other criteria
* *
* @param <T> either SourceMethod or BuiltInMethod * @param <T> either SourceMethod or BuiltInMethod
* @param mappingMethod mapping method, defined in Mapper for which this selection is carried out
* @param methods list of available methods * @param methods list of available methods
* @param sourceTypes parameter type(s) that should be matched * @param context the selection context that should be used in the matching process
* @param mappingTargetType the mapping target type that should be matched
* @param returnType return type that should be matched
* @param criteria criteria used in the selection process
* @return list of methods that passes the matching process * @return list of methods that passes the matching process
*/ */
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<T> methods,
List<T> methods, SelectionContext context) {
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
List<SelectedMethod<T>> candidates = new ArrayList<>( methods.size() ); List<SelectedMethod<T>> candidates = new ArrayList<>( methods.size() );
for ( T method : methods ) { for ( T method : methods ) {
@ -67,13 +57,7 @@ public class MethodSelectors {
} }
for ( MethodSelector selector : selectors ) { for ( MethodSelector selector : selectors ) {
candidates = selector.getMatchingMethods( candidates = selector.getMatchingMethods( candidates, context );
mappingMethod,
candidates,
sourceTypes,
mappingTargetType,
returnType,
criteria );
} }
return candidates; return candidates;
} }

View File

@ -17,10 +17,10 @@ import org.mapstruct.ap.internal.model.source.Method;
public class MostSpecificResultTypeSelector implements MethodSelector { public class MostSpecificResultTypeSelector implements MethodSelector {
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> candidates,
List<SelectedMethod<T>> candidates, SelectionContext context) {
List<Type> sourceTypes, Type mappingTargetType, SelectionCriteria criteria = context.getSelectionCriteria();
Type returnType, SelectionCriteria criteria) { Type mappingTargetType = context.getMappingTargetType();
if ( candidates.size() < 2 || !criteria.isForMapping() || criteria.getQualifyingResultType() != null) { if ( candidates.size() < 2 || !criteria.isForMapping() || criteria.getQualifyingResultType() != null) {
return candidates; return candidates;
} }

View File

@ -49,12 +49,9 @@ public class QualifierSelector implements MethodSelector {
} }
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes, SelectionCriteria criteria = context.getSelectionCriteria();
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
int numberOfQualifiersToMatch = 0; int numberOfQualifiersToMatch = 0;

View File

@ -0,0 +1,240 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.internal.model.source.selector;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
/**
* Context passed to the selectors to get the information they need.
*
* @author Filip Hrisafov
*/
public class SelectionContext {
private final Type sourceType;
private final SelectionCriteria selectionCriteria;
private final Method mappingMethod;
private final Type mappingTargetType;
private final Type returnType;
private final Supplier<List<ParameterBinding>> parameterBindingsProvider;
private List<ParameterBinding> parameterBindings;
private SelectionContext(Type sourceType, SelectionCriteria selectionCriteria, Method mappingMethod,
Type mappingTargetType, Type returnType,
Supplier<List<ParameterBinding>> parameterBindingsProvider) {
this.sourceType = sourceType;
this.selectionCriteria = selectionCriteria;
this.mappingMethod = mappingMethod;
this.mappingTargetType = mappingTargetType;
this.returnType = returnType;
this.parameterBindingsProvider = parameterBindingsProvider;
}
/**
* @return the source type that should be matched
*/
public Type getSourceType() {
return sourceType;
}
/**
* @return the criteria used in the selection process
*/
public SelectionCriteria getSelectionCriteria() {
return selectionCriteria;
}
/**
* @return the mapping target type that should be matched
*/
public Type getMappingTargetType() {
return mappingTargetType;
}
/**
* @return the return type that should be matched
*/
public Type getReturnType() {
return returnType;
}
/**
* @return the available parameter bindings for the matching
*/
public List<ParameterBinding> getAvailableParameterBindings() {
if ( this.parameterBindings == null ) {
this.parameterBindings = this.parameterBindingsProvider.get();
}
return parameterBindings;
}
/**
* @return the mapping method, defined in Mapper for which this selection is carried out
*/
public Method getMappingMethod() {
return mappingMethod;
}
public static SelectionContext forMappingMethods(Method mappingMethod, Type source, Type target,
SelectionCriteria criteria, TypeFactory typeFactory) {
return new SelectionContext(
source,
criteria,
mappingMethod,
target,
target,
() -> getAvailableParameterBindingsFromSourceType(
source,
target,
mappingMethod,
typeFactory
)
);
}
public static SelectionContext forLifecycleMethods(Method mappingMethod, Type targetType,
SelectionParameters selectionParameters,
TypeFactory typeFactory) {
SelectionCriteria criteria = SelectionCriteria.forLifecycleMethods( selectionParameters );
return new SelectionContext(
null,
criteria,
mappingMethod,
targetType,
mappingMethod.getResultType(),
() -> getAvailableParameterBindingsFromMethod(
mappingMethod,
targetType,
criteria.getSourceRHS(),
typeFactory
)
);
}
public static SelectionContext forFactoryMethods(Method mappingMethod, Type alternativeTarget,
SelectionParameters selectionParameters,
TypeFactory typeFactory) {
SelectionCriteria criteria = SelectionCriteria.forFactoryMethods( selectionParameters );
return new SelectionContext(
null,
criteria,
mappingMethod,
alternativeTarget,
alternativeTarget,
() -> getAvailableParameterBindingsFromMethod(
mappingMethod,
alternativeTarget,
criteria.getSourceRHS(),
typeFactory
)
);
}
public static SelectionContext forPresenceCheckMethods(Method mappingMethod,
SelectionParameters selectionParameters,
TypeFactory typeFactory) {
SelectionCriteria criteria = SelectionCriteria.forPresenceCheckMethods( selectionParameters );
Type booleanType = typeFactory.getType( Boolean.class );
return new SelectionContext(
null,
criteria,
mappingMethod,
booleanType,
booleanType,
() -> getAvailableParameterBindingsFromMethod(
mappingMethod,
booleanType,
criteria.getSourceRHS(),
typeFactory
)
);
}
private static List<ParameterBinding> getAvailableParameterBindingsFromMethod(Method method, Type targetType,
SourceRHS sourceRHS,
TypeFactory typeFactory) {
List<ParameterBinding> availableParams = new ArrayList<>( method.getParameters().size() + 3 );
if ( sourceRHS != null ) {
availableParams.addAll( ParameterBinding.fromParameters( method.getParameters() ) );
availableParams.add( ParameterBinding.fromSourceRHS( sourceRHS ) );
}
else {
availableParams.addAll( ParameterBinding.fromParameters( method.getParameters() ) );
}
addTargetRelevantBindings( availableParams, targetType, typeFactory );
return availableParams;
}
private static List<ParameterBinding> getAvailableParameterBindingsFromSourceType(Type sourceType,
Type targetType,
Method mappingMethod,
TypeFactory typeFactory) {
List<ParameterBinding> availableParams = new ArrayList<>();
availableParams.add( ParameterBinding.forSourceTypeBinding( sourceType ) );
for ( Parameter param : mappingMethod.getParameters() ) {
if ( param.isMappingContext() ) {
availableParams.add( ParameterBinding.fromParameter( param ) );
}
}
addTargetRelevantBindings( availableParams, targetType, typeFactory );
return availableParams;
}
/**
* Adds default parameter bindings for the mapping-target and target-type if not already available.
*
* @param availableParams Already available params, new entries will be added to this list
* @param targetType Target type
*/
private static void addTargetRelevantBindings(List<ParameterBinding> availableParams, Type targetType,
TypeFactory typeFactory) {
boolean mappingTargetAvailable = false;
boolean targetTypeAvailable = false;
boolean targetPropertyNameAvailable = false;
// search available parameter bindings if mapping-target and/or target-type is available
for ( ParameterBinding pb : availableParams ) {
if ( pb.isMappingTarget() ) {
mappingTargetAvailable = true;
}
else if ( pb.isTargetType() ) {
targetTypeAvailable = true;
}
else if ( pb.isTargetPropertyName() ) {
targetPropertyNameAvailable = true;
}
}
if ( !mappingTargetAvailable ) {
availableParams.add( ParameterBinding.forMappingTargetBinding( targetType ) );
}
if ( !targetTypeAvailable ) {
availableParams.add( ParameterBinding.forTargetTypeBinding( typeFactory.classTypeOf( targetType ) ) );
}
if ( !targetPropertyNameAvailable ) {
availableParams.add( ParameterBinding.forTargetPropertyNameBinding( typeFactory.getType( String.class ) ) );
}
}
}

View File

@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.mapstruct.ap.internal.model.common.ParameterBinding; import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
/** /**
@ -20,10 +19,9 @@ import org.mapstruct.ap.internal.model.source.Method;
public class SourceRhsSelector implements MethodSelector { public class SourceRhsSelector implements MethodSelector {
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> candidates,
List<SelectedMethod<T>> candidates, SelectionContext context) {
List<Type> sourceTypes, Type mappingTargetType, SelectionCriteria criteria = context.getSelectionCriteria();
Type returnType, SelectionCriteria criteria) {
if ( candidates.size() < 2 || criteria.getSourceRHS() == null ) { if ( candidates.size() < 2 || criteria.getSourceRHS() == null ) {
return candidates; return candidates;
} }

View File

@ -11,7 +11,6 @@ import java.util.List;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.util.TypeUtils; import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
/** /**
@ -31,12 +30,9 @@ public class TargetTypeSelector implements MethodSelector {
} }
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes, SelectionCriteria criteria = context.getSelectionCriteria();
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
TypeMirror qualifyingTypeMirror = criteria.getQualifyingResultType(); TypeMirror qualifyingTypeMirror = criteria.getQualifyingResultType();
if ( qualifyingTypeMirror != null && !criteria.isLifecycleCallbackRequired() ) { if ( qualifyingTypeMirror != null && !criteria.isLifecycleCallbackRequired() ) {

View File

@ -11,9 +11,7 @@ import java.util.stream.Collectors;
import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.ParameterBinding; import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.MethodMatcher; import org.mapstruct.ap.internal.model.source.MethodMatcher;
import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.FormattingMessager;
@ -29,44 +27,24 @@ import static org.mapstruct.ap.internal.util.Collections.first;
*/ */
public class TypeSelector implements MethodSelector { public class TypeSelector implements MethodSelector {
private TypeFactory typeFactory;
private FormattingMessager messager; private FormattingMessager messager;
public TypeSelector(TypeFactory typeFactory, FormattingMessager messager) { public TypeSelector(FormattingMessager messager) {
this.typeFactory = typeFactory;
this.messager = messager; this.messager = messager;
} }
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
if ( methods.isEmpty() ) { if ( methods.isEmpty() ) {
return methods; return methods;
} }
Type returnType = context.getReturnType();
List<SelectedMethod<T>> result = new ArrayList<>(); List<SelectedMethod<T>> result = new ArrayList<>();
List<ParameterBinding> availableBindings; List<ParameterBinding> availableBindings = context.getAvailableParameterBindings();
if ( sourceTypes.isEmpty() ) {
// if no source types are given, we have a factory or lifecycle method
availableBindings = getAvailableParameterBindingsFromMethod(
mappingMethod,
mappingTargetType,
criteria.getSourceRHS()
);
}
else {
availableBindings = getAvailableParameterBindingsFromSourceTypes(
sourceTypes,
mappingTargetType,
mappingMethod
);
}
for ( SelectedMethod<T> method : methods ) { for ( SelectedMethod<T> method : methods ) {
List<List<ParameterBinding>> parameterBindingPermutations = List<List<ParameterBinding>> parameterBindingPermutations =
@ -74,7 +52,7 @@ public class TypeSelector implements MethodSelector {
if ( parameterBindingPermutations != null ) { if ( parameterBindingPermutations != null ) {
SelectedMethod<T> matchingMethod = SelectedMethod<T> matchingMethod =
getMatchingParameterBinding( returnType, mappingMethod, method, parameterBindingPermutations ); getMatchingParameterBinding( returnType, context, method, parameterBindingPermutations );
if ( matchingMethod != null ) { if ( matchingMethod != null ) {
result.add( matchingMethod ); result.add( matchingMethod );
@ -84,80 +62,8 @@ public class TypeSelector implements MethodSelector {
return result; return result;
} }
private List<ParameterBinding> getAvailableParameterBindingsFromMethod(Method method, Type targetType,
SourceRHS sourceRHS) {
List<ParameterBinding> availableParams = new ArrayList<>( method.getParameters().size() + 3 );
if ( sourceRHS != null ) {
availableParams.addAll( ParameterBinding.fromParameters( method.getParameters() ) );
availableParams.add( ParameterBinding.fromSourceRHS( sourceRHS ) );
}
else {
availableParams.addAll( ParameterBinding.fromParameters( method.getParameters() ) );
}
addTargetRelevantBindings( availableParams, targetType );
return availableParams;
}
private List<ParameterBinding> getAvailableParameterBindingsFromSourceTypes(List<Type> sourceTypes,
Type targetType, Method mappingMethod) {
List<ParameterBinding> availableParams = new ArrayList<>( sourceTypes.size() + 2 );
for ( Type sourceType : sourceTypes ) {
availableParams.add( ParameterBinding.forSourceTypeBinding( sourceType ) );
}
for ( Parameter param : mappingMethod.getParameters() ) {
if ( param.isMappingContext() ) {
availableParams.add( ParameterBinding.fromParameter( param ) );
}
}
addTargetRelevantBindings( availableParams, targetType );
return availableParams;
}
/**
* Adds default parameter bindings for the mapping-target and target-type if not already available.
*
* @param availableParams Already available params, new entries will be added to this list
* @param targetType Target type
*/
private void addTargetRelevantBindings(List<ParameterBinding> availableParams, Type targetType) {
boolean mappingTargetAvailable = false;
boolean targetTypeAvailable = false;
boolean targetPropertyNameAvailable = false;
// search available parameter bindings if mapping-target and/or target-type is available
for ( ParameterBinding pb : availableParams ) {
if ( pb.isMappingTarget() ) {
mappingTargetAvailable = true;
}
else if ( pb.isTargetType() ) {
targetTypeAvailable = true;
}
else if ( pb.isTargetPropertyName() ) {
targetPropertyNameAvailable = true;
}
}
if ( !mappingTargetAvailable ) {
availableParams.add( ParameterBinding.forMappingTargetBinding( targetType ) );
}
if ( !targetTypeAvailable ) {
availableParams.add( ParameterBinding.forTargetTypeBinding( typeFactory.classTypeOf( targetType ) ) );
}
if ( !targetPropertyNameAvailable ) {
availableParams.add( ParameterBinding.forTargetPropertyNameBinding( typeFactory.getType( String.class ) ) );
}
}
private <T extends Method> SelectedMethod<T> getMatchingParameterBinding(Type returnType, private <T extends Method> SelectedMethod<T> getMatchingParameterBinding(Type returnType,
Method mappingMethod, SelectedMethod<T> selectedMethodInfo, SelectionContext context, SelectedMethod<T> selectedMethodInfo,
List<List<ParameterBinding>> parameterAssignmentVariants) { List<List<ParameterBinding>> parameterAssignmentVariants) {
List<List<ParameterBinding>> matchingParameterAssignmentVariants = new ArrayList<>( List<List<ParameterBinding>> matchingParameterAssignmentVariants = new ArrayList<>(
@ -200,7 +106,7 @@ public class TypeSelector implements MethodSelector {
messager.printMessage( messager.printMessage(
selectedMethod.getExecutable(), selectedMethod.getExecutable(),
Message.LIFECYCLEMETHOD_AMBIGUOUS_PARAMETERS, Message.LIFECYCLEMETHOD_AMBIGUOUS_PARAMETERS,
mappingMethod context.getMappingMethod()
); );
return null; return null;

View File

@ -45,18 +45,16 @@ abstract class XmlElementDeclSelector implements MethodSelector {
} }
@Override @Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod, public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
List<SelectedMethod<T>> methods, SelectionContext context) {
List<Type> sourceTypes, Type resultType = context.getMappingMethod().getResultType();
Type mappingTargetType, String targetPropertyName = context.getSelectionCriteria().getTargetPropertyName();
Type returnType,
SelectionCriteria criteria) {
List<SelectedMethod<T>> nameMatches = new ArrayList<>(); List<SelectedMethod<T>> nameMatches = new ArrayList<>();
List<SelectedMethod<T>> scopeMatches = new ArrayList<>(); List<SelectedMethod<T>> scopeMatches = new ArrayList<>();
List<SelectedMethod<T>> nameAndScopeMatches = new ArrayList<>(); List<SelectedMethod<T>> nameAndScopeMatches = new ArrayList<>();
XmlElementRefInfo xmlElementRefInfo = XmlElementRefInfo xmlElementRefInfo =
findXmlElementRef( mappingMethod.getResultType(), criteria.getTargetPropertyName() ); findXmlElementRef( resultType, targetPropertyName );
for ( SelectedMethod<T> candidate : methods ) { for ( SelectedMethod<T> candidate : methods ) {
if ( !( candidate.getMethod() instanceof SourceMethod ) ) { if ( !( candidate.getMethod() instanceof SourceMethod ) ) {

View File

@ -5,7 +5,6 @@
*/ */
package org.mapstruct.ap.internal.processor.creation; package org.mapstruct.ap.internal.processor.creation;
import static java.util.Collections.singletonList;
import static org.mapstruct.ap.internal.util.Collections.first; import static org.mapstruct.ap.internal.util.Collections.first;
import static org.mapstruct.ap.internal.util.Collections.firstKey; import static org.mapstruct.ap.internal.util.Collections.firstKey;
import static org.mapstruct.ap.internal.util.Collections.firstValue; import static org.mapstruct.ap.internal.util.Collections.firstValue;
@ -57,6 +56,7 @@ import org.mapstruct.ap.internal.model.source.builtin.BuiltInMappingMethods;
import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod; import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod;
import org.mapstruct.ap.internal.model.source.selector.MethodSelectors; import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod; import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
import org.mapstruct.ap.internal.model.source.selector.SelectionContext;
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
import org.mapstruct.ap.internal.util.Collections; import org.mapstruct.ap.internal.util.Collections;
import org.mapstruct.ap.internal.util.ElementUtils; import org.mapstruct.ap.internal.util.ElementUtils;
@ -116,7 +116,7 @@ public class MappingResolverImpl implements MappingResolver {
this.conversions = new Conversions( typeFactory ); this.conversions = new Conversions( typeFactory );
this.builtInMethods = new BuiltInMappingMethods( typeFactory ); this.builtInMethods = new BuiltInMappingMethods( typeFactory );
this.methodSelectors = new MethodSelectors( typeUtils, elementUtils, typeFactory, messager ); this.methodSelectors = new MethodSelectors( typeUtils, elementUtils, messager );
this.verboseLogging = verboseLogging; this.verboseLogging = verboseLogging;
} }
@ -491,12 +491,8 @@ public class MappingResolverImpl implements MappingResolver {
private <T extends Method> List<SelectedMethod<T>> getBestMatch(List<T> methods, Type source, Type target) { private <T extends Method> List<SelectedMethod<T>> getBestMatch(List<T> methods, Type source, Type target) {
return methodSelectors.getMatchingMethods( return methodSelectors.getMatchingMethods(
mappingMethod,
methods, methods,
singletonList( source ), SelectionContext.forMappingMethods( mappingMethod, source, target, selectionCriteria, typeFactory )
target,
target,
selectionCriteria
); );
} }