#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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
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.selector.MethodSelectors;
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
@ -134,15 +133,12 @@ public final class LifecycleMethodResolver {
MappingBuilderContext ctx, Set<String> existingVariableNames) {
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(
method,
callbackMethods,
Collections.emptyList(),
targetType,
method.getResultType(),
SelectionCriteria.forLifecycleMethods( selectionParameters ) );
SelectionContext.forLifecycleMethods( method, targetType, selectionParameters, ctx.getTypeFactory() )
);
return toLifecycleCallbackMethodRefs(
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.selector.MethodSelectors;
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;
/**
@ -126,15 +126,11 @@ public class ObjectFactoryMethodResolver {
MappingBuilderContext ctx) {
MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory(), ctx.getMessager() );
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager() );
return selectors.getMatchingMethods(
method,
getAllAvailableMethods( method, ctx.getSourceModel() ),
java.util.Collections.emptyList(),
alternativeTarget,
alternativeTarget,
SelectionCriteria.forFactoryMethods( selectionParameters )
SelectionContext.forFactoryMethods( method, alternativeTarget, selectionParameters, ctx.getTypeFactory() )
);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.ArrayList;
import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
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 {
@Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
List<SelectedMethod<T>> methods,
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
SelectionContext context) {
SelectionCriteria criteria = context.getSelectionCriteria();
List<SelectedMethod<T>> result = new ArrayList<>( methods.size() );
for ( SelectedMethod<T> method : methods ) {

View File

@ -7,7 +7,6 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.List;
import org.mapstruct.ap.internal.model.common.Type;
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
*
* @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 sourceTypes parameter type(s) that should be matched
* @param mappingTargetType mappingTargetType that should be matched
* @param returnType return type that should be matched
* @param criteria criteria used in the selection process
* @param context the context for the matching
* @return list of methods that passes the matching process
*/
<T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
List<SelectedMethod<T>> candidates,
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria);
<T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> candidates,
SelectionContext context);
}

View File

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

View File

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

View File

@ -49,12 +49,9 @@ public class QualifierSelector implements MethodSelector {
}
@Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
List<SelectedMethod<T>> methods,
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
SelectionContext context) {
SelectionCriteria criteria = context.getSelectionCriteria();
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 org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.Type;
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 {
@Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
List<SelectedMethod<T>> candidates,
List<Type> sourceTypes, Type mappingTargetType,
Type returnType, SelectionCriteria criteria) {
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> candidates,
SelectionContext context) {
SelectionCriteria criteria = context.getSelectionCriteria();
if ( candidates.size() < 2 || criteria.getSourceRHS() == null ) {
return candidates;
}

View File

@ -11,7 +11,6 @@ import java.util.List;
import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
/**
@ -31,12 +30,9 @@ public class TargetTypeSelector implements MethodSelector {
}
@Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
List<SelectedMethod<T>> methods,
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
SelectionContext context) {
SelectionCriteria criteria = context.getSelectionCriteria();
TypeMirror qualifyingTypeMirror = criteria.getQualifyingResultType();
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.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.MethodMatcher;
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 {
private TypeFactory typeFactory;
private FormattingMessager messager;
public TypeSelector(TypeFactory typeFactory, FormattingMessager messager) {
this.typeFactory = typeFactory;
public TypeSelector(FormattingMessager messager) {
this.messager = messager;
}
@Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
List<SelectedMethod<T>> methods,
List<Type> sourceTypes,
Type mappingTargetType,
Type returnType,
SelectionCriteria criteria) {
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
SelectionContext context) {
if ( methods.isEmpty() ) {
return methods;
}
Type returnType = context.getReturnType();
List<SelectedMethod<T>> result = new ArrayList<>();
List<ParameterBinding> availableBindings;
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
);
}
List<ParameterBinding> availableBindings = context.getAvailableParameterBindings();
for ( SelectedMethod<T> method : methods ) {
List<List<ParameterBinding>> parameterBindingPermutations =
@ -74,7 +52,7 @@ public class TypeSelector implements MethodSelector {
if ( parameterBindingPermutations != null ) {
SelectedMethod<T> matchingMethod =
getMatchingParameterBinding( returnType, mappingMethod, method, parameterBindingPermutations );
getMatchingParameterBinding( returnType, context, method, parameterBindingPermutations );
if ( matchingMethod != null ) {
result.add( matchingMethod );
@ -84,80 +62,8 @@ public class TypeSelector implements MethodSelector {
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,
Method mappingMethod, SelectedMethod<T> selectedMethodInfo,
SelectionContext context, SelectedMethod<T> selectedMethodInfo,
List<List<ParameterBinding>> parameterAssignmentVariants) {
List<List<ParameterBinding>> matchingParameterAssignmentVariants = new ArrayList<>(
@ -200,7 +106,7 @@ public class TypeSelector implements MethodSelector {
messager.printMessage(
selectedMethod.getExecutable(),
Message.LIFECYCLEMETHOD_AMBIGUOUS_PARAMETERS,
mappingMethod
context.getMappingMethod()
);
return null;

View File

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

View File

@ -5,7 +5,6 @@
*/
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.firstKey;
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.selector.MethodSelectors;
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.util.Collections;
import org.mapstruct.ap.internal.util.ElementUtils;
@ -116,7 +116,7 @@ public class MappingResolverImpl implements MappingResolver {
this.conversions = new Conversions( typeFactory );
this.builtInMethods = new BuiltInMappingMethods( typeFactory );
this.methodSelectors = new MethodSelectors( typeUtils, elementUtils, typeFactory, messager );
this.methodSelectors = new MethodSelectors( typeUtils, elementUtils, messager );
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) {
return methodSelectors.getMatchingMethods(
mappingMethod,
methods,
singletonList( source ),
target,
target,
selectionCriteria
SelectionContext.forMappingMethods( mappingMethod, source, target, selectionCriteria, typeFactory )
);
}