mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-26 00:00:05 +08:00
#975 Refactor method-matching to unify selection and rendering of mapping method, factories and lifecycle methods
This commit is contained in:
parent
46363028bd
commit
79f87e8833
@ -31,6 +31,7 @@ import org.mapstruct.ap.internal.model.assignment.Assignment;
|
|||||||
import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper;
|
import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper;
|
||||||
import org.mapstruct.ap.internal.model.assignment.SetterWrapper;
|
import org.mapstruct.ap.internal.model.assignment.SetterWrapper;
|
||||||
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.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
||||||
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
|
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
|
||||||
@ -191,7 +192,11 @@ public class IterableMappingMethod extends MappingMethod {
|
|||||||
forgedMethodHistory
|
forgedMethodHistory
|
||||||
);
|
);
|
||||||
|
|
||||||
Assignment assignment = new MethodReference( forgedMethod, null, targetType );
|
Assignment assignment = new MethodReference(
|
||||||
|
forgedMethod,
|
||||||
|
null,
|
||||||
|
ParameterBinding.fromParameters( forgedMethod.getParameters() ) );
|
||||||
|
|
||||||
assignment.setAssignment( sourceRHS );
|
assignment.setAssignment( sourceRHS );
|
||||||
|
|
||||||
return assignment;
|
return assignment;
|
||||||
|
@ -19,17 +19,16 @@
|
|||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
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.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.QualifierSelector;
|
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
|
||||||
|
import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
|
||||||
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
|
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,45 +83,36 @@ public final class LifecycleCallbackFactory {
|
|||||||
Method method, SelectionParameters selectionParameters, List<SourceMethod> callbackMethods,
|
Method method, SelectionParameters selectionParameters, List<SourceMethod> callbackMethods,
|
||||||
MappingBuilderContext ctx, Set<String> existingVariableNames) {
|
MappingBuilderContext ctx, Set<String> existingVariableNames) {
|
||||||
|
|
||||||
Map<SourceMethod, List<Parameter>> parameterAssignmentsForSourceMethod
|
MethodSelectors selectors =
|
||||||
= new HashMap<SourceMethod, List<Parameter>>();
|
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory() );
|
||||||
|
|
||||||
List<SourceMethod> candidates =
|
List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods(
|
||||||
filterCandidatesByType( method, callbackMethods, parameterAssignmentsForSourceMethod, ctx );
|
method,
|
||||||
|
callbackMethods,
|
||||||
candidates = filterCandidatesByQualifiers( method, selectionParameters, candidates, ctx );
|
Collections.<Type> emptyList(),
|
||||||
|
method.getResultType(),
|
||||||
|
SelectionCriteria.forLifecycleMethods( selectionParameters ) );
|
||||||
|
|
||||||
return toLifecycleCallbackMethodRefs(
|
return toLifecycleCallbackMethodRefs(
|
||||||
method,
|
method,
|
||||||
candidates,
|
matchingMethods,
|
||||||
parameterAssignmentsForSourceMethod,
|
|
||||||
ctx,
|
ctx,
|
||||||
existingVariableNames );
|
existingVariableNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<SourceMethod> filterCandidatesByQualifiers(Method method,
|
|
||||||
SelectionParameters selectionParameters,
|
|
||||||
List<SourceMethod> candidates,
|
|
||||||
MappingBuilderContext ctx) {
|
|
||||||
QualifierSelector selector = new QualifierSelector( ctx.getTypeUtils(), ctx.getElementUtils() );
|
|
||||||
|
|
||||||
return selector.getMatchingMethods( method, candidates, null, null, new SelectionCriteria(
|
|
||||||
selectionParameters,
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
false) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<LifecycleCallbackMethodReference> toLifecycleCallbackMethodRefs(Method method,
|
private static List<LifecycleCallbackMethodReference> toLifecycleCallbackMethodRefs(Method method,
|
||||||
List<SourceMethod> candidates, Map<SourceMethod, List<Parameter>> parameterAssignmentsForSourceMethod,
|
List<SelectedMethod<SourceMethod>> candidates,
|
||||||
MappingBuilderContext ctx, Set<String> existingVariableNames) {
|
MappingBuilderContext ctx,
|
||||||
|
Set<String> existingVariableNames) {
|
||||||
|
|
||||||
List<LifecycleCallbackMethodReference> result = new ArrayList<LifecycleCallbackMethodReference>();
|
List<LifecycleCallbackMethodReference> result = new ArrayList<LifecycleCallbackMethodReference>();
|
||||||
for ( SourceMethod candidate : candidates ) {
|
for ( SelectedMethod<SourceMethod> candidate : candidates ) {
|
||||||
markMapperReferenceAsUsed( ctx.getMapperReferences(), candidate );
|
MapperReference mapperReference = findMapperReference( ctx.getMapperReferences(), candidate.getMethod() );
|
||||||
result.add(
|
result.add(
|
||||||
new LifecycleCallbackMethodReference(
|
new LifecycleCallbackMethodReference(
|
||||||
candidate,
|
candidate.getMethod(),
|
||||||
parameterAssignmentsForSourceMethod.get( candidate ),
|
mapperReference,
|
||||||
|
candidate.getParameterBindings(),
|
||||||
method.getReturnType(),
|
method.getReturnType(),
|
||||||
method.getResultType(),
|
method.getResultType(),
|
||||||
existingVariableNames ) );
|
existingVariableNames ) );
|
||||||
@ -130,77 +120,15 @@ public final class LifecycleCallbackFactory {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<SourceMethod> filterCandidatesByType(Method method,
|
private static MapperReference findMapperReference(List<MapperReference> mapperReferences, SourceMethod method) {
|
||||||
List<SourceMethod> callbackMethods, Map<SourceMethod, List<Parameter>> parameterAssignmentsForSourceMethod,
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
MappingBuilderContext ctx) {
|
|
||||||
|
|
||||||
List<SourceMethod> candidates = new ArrayList<SourceMethod>();
|
|
||||||
|
|
||||||
List<Parameter> availableParams = getAvailableParameters( method, ctx );
|
|
||||||
for ( SourceMethod callback : callbackMethods ) {
|
|
||||||
List<Parameter> parameterAssignments =
|
|
||||||
ParameterAssignmentUtil.getParameterAssignments( availableParams, callback.getParameters() );
|
|
||||||
|
|
||||||
if ( isValidCandidate( callback, method, parameterAssignments ) ) {
|
|
||||||
parameterAssignmentsForSourceMethod.put( callback, parameterAssignments );
|
|
||||||
candidates.add( callback );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return candidates;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidCandidate(SourceMethod candidate, Method method,
|
|
||||||
List<Parameter> parameterAssignments) {
|
|
||||||
if ( parameterAssignments == null ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ( !candidate.matches( extractSourceTypes( parameterAssignments ), method.getResultType() ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ( candidate.getReturnType().isVoid() || candidate.getReturnType().isTypeVar()
|
|
||||||
|| candidate.getReturnType().isAssignableTo( method.getResultType() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Parameter> getAvailableParameters(Method method, MappingBuilderContext ctx) {
|
|
||||||
List<Parameter> availableParams = new ArrayList<Parameter>( method.getParameters() );
|
|
||||||
if ( method.getMappingTargetParameter() == null ) {
|
|
||||||
availableParams.add( new Parameter( null, method.getResultType(), true, false, false) );
|
|
||||||
}
|
|
||||||
|
|
||||||
Parameter targetTypeParameter = new Parameter(
|
|
||||||
null,
|
|
||||||
ctx.getTypeFactory().classTypeOf( method.getResultType() ),
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false );
|
|
||||||
|
|
||||||
availableParams.add( targetTypeParameter );
|
|
||||||
return availableParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void markMapperReferenceAsUsed(List<MapperReference> references, Method method) {
|
|
||||||
for ( MapperReference ref : references ) {
|
|
||||||
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
if ( !ref.isUsed() && !method.isStatic() ) {
|
ref.setUsed( ref.isUsed() || !method.isStatic() );
|
||||||
ref.setUsed( true );
|
|
||||||
}
|
|
||||||
ref.setTypeRequiresImport( true );
|
ref.setTypeRequiresImport( true );
|
||||||
|
return ref;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
|
|
||||||
private static List<Type> extractSourceTypes(List<Parameter> parameters) {
|
|
||||||
List<Type> result = new ArrayList<Type>( parameters.size() );
|
|
||||||
|
|
||||||
for ( Parameter param : parameters ) {
|
|
||||||
if ( !param.isMappingTarget() && !param.isTargetType() ) {
|
|
||||||
result.add( param.getType() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<SourceMethod> filterBeforeMappingMethods(List<SourceMethod> methods) {
|
private static List<SourceMethod> filterBeforeMappingMethods(List<SourceMethod> methods) {
|
||||||
|
@ -18,11 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model;
|
||||||
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
import org.mapstruct.ap.internal.model.common.ParameterBinding;
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
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.SourceMethod;
|
import org.mapstruct.ap.internal.model.source.SourceMethod;
|
||||||
@ -34,35 +33,22 @@ import org.mapstruct.ap.internal.util.Strings;
|
|||||||
*
|
*
|
||||||
* @author Andreas Gudian
|
* @author Andreas Gudian
|
||||||
*/
|
*/
|
||||||
public class LifecycleCallbackMethodReference extends MappingMethod {
|
public class LifecycleCallbackMethodReference extends MethodReference {
|
||||||
|
|
||||||
private final Type declaringType;
|
private final Type declaringType;
|
||||||
private final List<Parameter> parameterAssignments;
|
|
||||||
private final Type methodReturnType;
|
private final Type methodReturnType;
|
||||||
private final Type methodResultType;
|
private final Type methodResultType;
|
||||||
private final String instanceVariableName;
|
|
||||||
private final String targetVariableName;
|
private final String targetVariableName;
|
||||||
|
|
||||||
public LifecycleCallbackMethodReference(SourceMethod method, List<Parameter> parameterAssignments,
|
public LifecycleCallbackMethodReference(SourceMethod method, MapperReference mapperReference,
|
||||||
|
List<ParameterBinding> parameterBindings,
|
||||||
Type methodReturnType, Type methodResultType,
|
Type methodReturnType, Type methodResultType,
|
||||||
Set<String> existingVariableNames) {
|
Set<String> existingVariableNames) {
|
||||||
super( method );
|
super( method, mapperReference, parameterBindings );
|
||||||
this.declaringType = method.getDeclaringMapper();
|
this.declaringType = method.getDeclaringMapper();
|
||||||
this.parameterAssignments = parameterAssignments;
|
|
||||||
this.methodReturnType = methodReturnType;
|
this.methodReturnType = methodReturnType;
|
||||||
this.methodResultType = methodResultType;
|
this.methodResultType = methodResultType;
|
||||||
|
|
||||||
if ( isStatic() ) {
|
|
||||||
this.instanceVariableName = declaringType.getName();
|
|
||||||
}
|
|
||||||
else if ( declaringType != null ) {
|
|
||||||
this.instanceVariableName =
|
|
||||||
Strings.getSaveVariableName( Introspector.decapitalize( declaringType.getName() ) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.instanceVariableName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( hasReturnType() ) {
|
if ( hasReturnType() ) {
|
||||||
this.targetVariableName = Strings.getSaveVariableName( "target", existingVariableNames );
|
this.targetVariableName = Strings.getSaveVariableName( "target", existingVariableNames );
|
||||||
existingVariableNames.add( this.targetVariableName );
|
existingVariableNames.add( this.targetVariableName );
|
||||||
@ -76,10 +62,6 @@ public class LifecycleCallbackMethodReference extends MappingMethod {
|
|||||||
return declaringType;
|
return declaringType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInstanceVariableName() {
|
|
||||||
return instanceVariableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the return type of the mapping method in which this callback method is called
|
* Returns the return type of the mapping method in which this callback method is called
|
||||||
*
|
*
|
||||||
@ -109,12 +91,8 @@ public class LifecycleCallbackMethodReference extends MappingMethod {
|
|||||||
return declaringType != null ? Collections.asSet( declaringType ) : java.util.Collections.<Type> emptySet();
|
return declaringType != null ? Collections.asSet( declaringType ) : java.util.Collections.<Type> emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Parameter> getParameterAssignments() {
|
|
||||||
return parameterAssignments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMappingTargetParameter() {
|
public boolean hasMappingTargetParameter() {
|
||||||
for ( Parameter param : parameterAssignments ) {
|
for ( ParameterBinding param : getParameterBindings() ) {
|
||||||
if ( param.isMappingTarget() ) {
|
if ( param.isMappingTarget() ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import java.util.Set;
|
|||||||
import org.mapstruct.ap.internal.model.assignment.Assignment;
|
import org.mapstruct.ap.internal.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper;
|
import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper;
|
||||||
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.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
||||||
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
|
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
|
||||||
@ -211,7 +212,11 @@ public class MapMappingMethod extends MappingMethod {
|
|||||||
history
|
history
|
||||||
);
|
);
|
||||||
|
|
||||||
Assignment assignment = new MethodReference( forgedMethod, null, targetType );
|
Assignment assignment = new MethodReference(
|
||||||
|
forgedMethod,
|
||||||
|
null,
|
||||||
|
ParameterBinding.fromParameters( forgedMethod.getParameters() ) );
|
||||||
|
|
||||||
assignment.setAssignment( sourceRHS );
|
assignment.setAssignment( sourceRHS );
|
||||||
|
|
||||||
forgedMethods.add( forgedMethod );
|
forgedMethods.add( forgedMethod );
|
||||||
|
@ -27,6 +27,7 @@ import java.util.Set;
|
|||||||
import org.mapstruct.ap.internal.model.assignment.Assignment;
|
import org.mapstruct.ap.internal.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
||||||
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.Type;
|
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.builtin.BuiltInMethod;
|
import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod;
|
||||||
@ -62,18 +63,19 @@ public class MethodReference extends MappingMethod implements Assignment {
|
|||||||
private Assignment assignment;
|
private Assignment assignment;
|
||||||
|
|
||||||
private final Type definingType;
|
private final Type definingType;
|
||||||
|
private final List<ParameterBinding> parameterBindings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new reference to the given method.
|
* Creates a new reference to the given method.
|
||||||
*
|
*
|
||||||
* @param method the target method of the reference
|
* @param method the target method of the reference
|
||||||
* @param declaringMapper the method declaring the mapper; {@code null} if the current mapper itself
|
* @param declaringMapper the method declaring the mapper; {@code null} if the current mapper itself
|
||||||
* @param targetType in case the referenced method has a parameter for passing the target type, the given
|
* @param parameterBindings the parameter bindings of this method reference
|
||||||
* target type, otherwise {@code null}
|
|
||||||
*/
|
*/
|
||||||
public MethodReference(Method method, MapperReference declaringMapper, Type targetType) {
|
public MethodReference(Method method, MapperReference declaringMapper, List<ParameterBinding> parameterBindings) {
|
||||||
super( method );
|
super( method );
|
||||||
this.declaringMapper = declaringMapper;
|
this.declaringMapper = declaringMapper;
|
||||||
|
this.parameterBindings = parameterBindings;
|
||||||
this.contextParam = null;
|
this.contextParam = null;
|
||||||
Set<Type> imported = new HashSet<Type>();
|
Set<Type> imported = new HashSet<Type>();
|
||||||
|
|
||||||
@ -81,8 +83,8 @@ public class MethodReference extends MappingMethod implements Assignment {
|
|||||||
imported.addAll( type.getImportTypes() );
|
imported.addAll( type.getImportTypes() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( targetType != null ) {
|
for ( ParameterBinding binding : parameterBindings ) {
|
||||||
imported.addAll( targetType.getImportTypes() );
|
imported.addAll( binding.getImportTypes() );
|
||||||
}
|
}
|
||||||
|
|
||||||
this.importTypes = Collections.<Type>unmodifiableSet( imported );
|
this.importTypes = Collections.<Type>unmodifiableSet( imported );
|
||||||
@ -99,6 +101,7 @@ public class MethodReference extends MappingMethod implements Assignment {
|
|||||||
this.thrownTypes = Collections.emptyList();
|
this.thrownTypes = Collections.emptyList();
|
||||||
this.definingType = null;
|
this.definingType = null;
|
||||||
this.isUpdateMethod = method.getMappingTargetParameter() != null;
|
this.isUpdateMethod = method.getMappingTargetParameter() != null;
|
||||||
|
this.parameterBindings = ParameterBinding.fromParameters( method.getParameters() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapperReference getDeclaringMapper() {
|
public MapperReference getDeclaringMapper() {
|
||||||
@ -214,4 +217,8 @@ public class MethodReference extends MappingMethod implements Assignment {
|
|||||||
public boolean isCallingUpdateMethod() {
|
public boolean isCallingUpdateMethod() {
|
||||||
return isUpdateMethod;
|
return isUpdateMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ParameterBinding> getParameterBindings() {
|
||||||
|
return parameterBindings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
|
||||||
* and/or other contributors as indicated by the @authors tag. See the
|
|
||||||
* copyright.txt file in the distribution for a full listing of all
|
|
||||||
* contributors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.mapstruct.ap.internal.model;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.lang.model.type.TypeKind;
|
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
|
||||||
|
|
||||||
public class ParameterAssignmentUtil {
|
|
||||||
|
|
||||||
private ParameterAssignmentUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Parameter> getParameterAssignments(List<Parameter> availableParams,
|
|
||||||
List<Parameter> methodParameters) {
|
|
||||||
List<Parameter> result = new ArrayList<Parameter>( methodParameters.size() );
|
|
||||||
|
|
||||||
for ( Parameter methodParam : methodParameters ) {
|
|
||||||
List<Parameter> assignableParams = findCandidateParameters( availableParams, methodParam );
|
|
||||||
|
|
||||||
if ( assignableParams.isEmpty() ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( assignableParams.size() == 1 ) {
|
|
||||||
result.add( assignableParams.get( 0 ) );
|
|
||||||
}
|
|
||||||
else if ( assignableParams.size() > 1 ) {
|
|
||||||
Parameter paramWithMatchingName = findParameterWithName( assignableParams, methodParam.getName() );
|
|
||||||
|
|
||||||
if ( paramWithMatchingName != null ) {
|
|
||||||
result.add( paramWithMatchingName );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Parameter findParameterWithName(List<Parameter> parameters, String name) {
|
|
||||||
for ( Parameter param : parameters ) {
|
|
||||||
if ( name.equals( param.getName() ) ) {
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param candidateParameters available for assignment.
|
|
||||||
* @param parameter that need assignment from one of the candidate parameters.
|
|
||||||
* @return list of matching candidate parameters that can be assigned.
|
|
||||||
*/
|
|
||||||
private static List<Parameter> findCandidateParameters(List<Parameter> candidateParameters, Parameter parameter) {
|
|
||||||
List<Parameter> result = new ArrayList<Parameter>( candidateParameters.size() );
|
|
||||||
|
|
||||||
for ( Parameter candidate : candidateParameters ) {
|
|
||||||
if ( ( isTypeVarOrWildcard( parameter ) || candidate.getType().isAssignableTo( parameter.getType() ) )
|
|
||||||
&& parameter.isMappingTarget() == candidate.isMappingTarget() && !parameter.isTargetType()
|
|
||||||
&& !candidate.isTargetType() ) {
|
|
||||||
result.add( candidate );
|
|
||||||
}
|
|
||||||
else if ( parameter.isTargetType() && candidate.isTargetType() ) {
|
|
||||||
result.add( candidate );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isTypeVarOrWildcard(Parameter parameter) {
|
|
||||||
TypeKind kind = parameter.getType().getTypeMirror().getKind();
|
|
||||||
return kind == TypeKind.TYPEVAR || kind == TypeKind.WILDCARD;
|
|
||||||
}
|
|
||||||
}
|
|
@ -43,13 +43,14 @@ import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAnd
|
|||||||
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
|
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
|
||||||
import org.mapstruct.ap.internal.model.common.ModelElement;
|
import org.mapstruct.ap.internal.model.common.ModelElement;
|
||||||
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.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
import org.mapstruct.ap.internal.model.source.ForgedMethod;
|
||||||
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
|
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
|
||||||
import org.mapstruct.ap.internal.model.source.FormattingParameters;
|
import org.mapstruct.ap.internal.model.source.FormattingParameters;
|
||||||
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
import org.mapstruct.ap.internal.model.source.PropertyEntry;
|
import org.mapstruct.ap.internal.model.source.PropertyEntry;
|
||||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||||
import org.mapstruct.ap.internal.model.source.Method;
|
|
||||||
import org.mapstruct.ap.internal.model.source.SourceReference;
|
import org.mapstruct.ap.internal.model.source.SourceReference;
|
||||||
import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism;
|
import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism;
|
||||||
import org.mapstruct.ap.internal.util.Executables;
|
import org.mapstruct.ap.internal.util.Executables;
|
||||||
@ -566,7 +567,11 @@ public class PropertyMapping extends ModelElement {
|
|||||||
methodRef = new ForgedMethod( existingName, methodRef );
|
methodRef = new ForgedMethod( existingName, methodRef );
|
||||||
}
|
}
|
||||||
|
|
||||||
assignment = new MethodReference( methodRef, null, targetType );
|
assignment = new MethodReference(
|
||||||
|
methodRef,
|
||||||
|
null,
|
||||||
|
ParameterBinding.fromParameters( methodRef.getParameters() ) );
|
||||||
|
|
||||||
assignment.setAssignment( source );
|
assignment.setAssignment( source );
|
||||||
|
|
||||||
forgedMethods.addAll( iterableMappingMethod.getForgedMethods() );
|
forgedMethods.addAll( iterableMappingMethod.getForgedMethods() );
|
||||||
@ -608,7 +613,10 @@ public class PropertyMapping extends ModelElement {
|
|||||||
String existingName = ctx.getExistingMappingMethod( mapMappingMethod ).getName();
|
String existingName = ctx.getExistingMappingMethod( mapMappingMethod ).getName();
|
||||||
methodRef = new ForgedMethod( existingName, methodRef );
|
methodRef = new ForgedMethod( existingName, methodRef );
|
||||||
}
|
}
|
||||||
assignment = new MethodReference( methodRef, null, targetType );
|
assignment = new MethodReference(
|
||||||
|
methodRef,
|
||||||
|
null,
|
||||||
|
ParameterBinding.fromParameters( methodRef.getParameters() ) );
|
||||||
assignment.setAssignment( source );
|
assignment.setAssignment( source );
|
||||||
|
|
||||||
forgedMethods.addAll( mapMappingMethod.getForgedMethods() );
|
forgedMethods.addAll( mapMappingMethod.getForgedMethods() );
|
||||||
@ -635,7 +643,11 @@ public class PropertyMapping extends ModelElement {
|
|||||||
getForgedMethodHistory( sourceRHS )
|
getForgedMethodHistory( sourceRHS )
|
||||||
);
|
);
|
||||||
|
|
||||||
Assignment assignment = new MethodReference( forgedMethod, null, targetType );
|
Assignment assignment = new MethodReference(
|
||||||
|
forgedMethod,
|
||||||
|
null,
|
||||||
|
ParameterBinding.fromParameters( forgedMethod.getParameters() ) );
|
||||||
|
|
||||||
assignment.setAssignment( sourceRHS );
|
assignment.setAssignment( sourceRHS );
|
||||||
|
|
||||||
this.forgedMethods.add( forgedMethod );
|
this.forgedMethods.add( forgedMethod );
|
||||||
|
@ -34,20 +34,18 @@ public class Parameter extends ModelElement {
|
|||||||
private final Type type;
|
private final Type type;
|
||||||
private final boolean mappingTarget;
|
private final boolean mappingTarget;
|
||||||
private final boolean targetType;
|
private final boolean targetType;
|
||||||
private final boolean mappingSource;
|
|
||||||
|
|
||||||
public Parameter(String name, Type type, boolean mappingTarget, boolean targetType, boolean mappingSource) {
|
public Parameter(String name, Type type, boolean mappingTarget, boolean targetType) {
|
||||||
// issue #909: FreeMarker doesn't like "values" as a parameter name
|
// issue #909: FreeMarker doesn't like "values" as a parameter name
|
||||||
this.name = "values".equals( name ) ? "values_" : name;
|
this.name = "values".equals( name ) ? "values_" : name;
|
||||||
this.originalName = name;
|
this.originalName = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.mappingTarget = mappingTarget;
|
this.mappingTarget = mappingTarget;
|
||||||
this.targetType = targetType;
|
this.targetType = targetType;
|
||||||
this.mappingSource = mappingSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Parameter(String name, Type type) {
|
public Parameter(String name, Type type) {
|
||||||
this( name, type, false, false, false );
|
this( name, type, false, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -62,10 +60,6 @@ public class Parameter extends ModelElement {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMappingSource() {
|
|
||||||
return mappingSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMappingTarget() {
|
public boolean isMappingTarget() {
|
||||||
return mappingTarget;
|
return mappingTarget;
|
||||||
}
|
}
|
||||||
@ -106,5 +100,4 @@ public class Parameter extends ModelElement {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.internal.model.common;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents how one parameter of a method to be called is populated.
|
||||||
|
*
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*/
|
||||||
|
public class ParameterBinding {
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
private final String variableName;
|
||||||
|
private final boolean targetType;
|
||||||
|
private final boolean mappingTarget;
|
||||||
|
|
||||||
|
private ParameterBinding(Type parameterType, String variableName, boolean mappingTarget, boolean targetType) {
|
||||||
|
this.type = parameterType;
|
||||||
|
this.variableName = variableName;
|
||||||
|
this.targetType = targetType;
|
||||||
|
this.mappingTarget = mappingTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of the variable (or parameter) that is being used as argument for the parameter being bound.
|
||||||
|
*/
|
||||||
|
public String getVariableName() {
|
||||||
|
return variableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true}, if the parameter being bound is a {@code @TargetType} parameter.
|
||||||
|
*/
|
||||||
|
public boolean isTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true}, if the parameter being bound is a {@code @MappingTarget} parameter.
|
||||||
|
*/
|
||||||
|
public boolean isMappingTarget() {
|
||||||
|
return mappingTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type of the parameter that is bound
|
||||||
|
*/
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Type> getImportTypes() {
|
||||||
|
if ( targetType ) {
|
||||||
|
return type.getImportTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param parameter parameter
|
||||||
|
* @return a parameter binding reflecting the given parameter as being used as argument for a method call
|
||||||
|
*/
|
||||||
|
public static ParameterBinding fromParameter(Parameter parameter) {
|
||||||
|
return new ParameterBinding(
|
||||||
|
parameter.getType(),
|
||||||
|
parameter.getName(),
|
||||||
|
parameter.isMappingTarget(),
|
||||||
|
parameter.isTargetType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ParameterBinding> fromParameters(List<Parameter> parameters) {
|
||||||
|
List<ParameterBinding> result = new ArrayList<ParameterBinding>( parameters.size() );
|
||||||
|
for ( Parameter param : parameters ) {
|
||||||
|
result.add( fromParameter( param ) );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classTypeOf the type representing {@code Class<X>} for the target type {@code X}
|
||||||
|
* @return a parameter binding representing a target type parameter
|
||||||
|
*/
|
||||||
|
public static ParameterBinding forTargetTypeBinding(Type classTypeOf) {
|
||||||
|
return new ParameterBinding( classTypeOf, null, false, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param resultType type of the mapping target
|
||||||
|
* @return a parameter binding representing a mapping target parameter
|
||||||
|
*/
|
||||||
|
public static ParameterBinding forMappingTargetBinding(Type resultType) {
|
||||||
|
return new ParameterBinding( resultType, null, true, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sourceType type of the parameter
|
||||||
|
* @return a parameter binding representing a mapping source type
|
||||||
|
*/
|
||||||
|
public static ParameterBinding forSourceTypeBinding(Type sourceType) {
|
||||||
|
return new ParameterBinding( sourceType, null, false, false );
|
||||||
|
}
|
||||||
|
}
|
@ -754,11 +754,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
return typeMirror.hashCode();
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
|
|
||||||
result = prime * result + ( ( packageName == null ) ? 0 : packageName.hashCode() );
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -787,7 +783,6 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
return typeMirror.toString();
|
return typeMirror.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return an identification that can be used as part in a forged method name.
|
* @return an identification that can be used as part in a forged method name.
|
||||||
|
@ -326,8 +326,7 @@ public class TypeFactory {
|
|||||||
parameter.getSimpleName().toString(),
|
parameter.getSimpleName().toString(),
|
||||||
getType( parameterType ),
|
getType( parameterType ),
|
||||||
MappingTargetPrism.getInstanceOn( parameter ) != null,
|
MappingTargetPrism.getInstanceOn( parameter ) != null,
|
||||||
TargetTypePrism.getInstanceOn( parameter ) != null,
|
TargetTypePrism.getInstanceOn( parameter ) != null ) );
|
||||||
false) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -116,7 +116,7 @@ public class ForgedMethod implements Method {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !first( sourceTypes ).equals( parameters.get( 0 ).getType() ) ) {
|
if ( !first( sourceTypes ).equals( first( parameters ).getType() ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model.source;
|
package org.mapstruct.ap.internal.model.source;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.hasNonNullElements;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -90,27 +88,18 @@ public class MethodMatcher {
|
|||||||
// check & collect generic types.
|
// check & collect generic types.
|
||||||
Map<TypeVariable, TypeMirror> genericTypesMap = new HashMap<TypeVariable, TypeMirror>();
|
Map<TypeVariable, TypeMirror> genericTypesMap = new HashMap<TypeVariable, TypeMirror>();
|
||||||
|
|
||||||
if ( hasNonNullElements( sourceTypes ) ) {
|
if ( candidateMethod.getParameters().size() == sourceTypes.size() ) {
|
||||||
// if sourceTypes contains non-null elements then only methods with all source parameters matching qualify
|
int i = 0;
|
||||||
if ( candidateMethod.getSourceParameters().size() == sourceTypes.size() ) {
|
for ( Parameter candidateParam : candidateMethod.getParameters() ) {
|
||||||
int i = 0;
|
Type sourceType = sourceTypes.get( i++ );
|
||||||
for ( Parameter candidateSourceParam : candidateMethod.getSourceParameters() ) {
|
if ( sourceType == null
|
||||||
Type sourceType = sourceTypes.get( i++ );
|
|| !matchSourceType( sourceType, candidateParam.getType(), genericTypesMap ) ) {
|
||||||
if ( sourceType == null
|
return false;
|
||||||
|| !matchSourceType( sourceType, candidateSourceParam.getType(), genericTypesMap ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// if the sourceTypes empty/contains only nulls then only factory and lifecycle methods qualify
|
return false;
|
||||||
if ( !candidateMethod.isObjectFactory() && !candidateMethod.isLifecycleCallbackMethod() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the method matches the proper result type to construct
|
// check if the method matches the proper result type to construct
|
||||||
|
@ -42,14 +42,19 @@ 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<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Type sourceType, Type targetType,
|
List<SelectedMethod<T>> methods,
|
||||||
SelectionCriteria criteria) {
|
List<Type> sourceTypes, Type targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
List<T> createCandidates = new ArrayList<T>();
|
if ( criteria.isLifecycleCallbackRequired() || criteria.isObjectFactoryRequired() ) {
|
||||||
List<T> updateCandidates = new ArrayList<T>();
|
return methods;
|
||||||
for ( T method : methods ) {
|
}
|
||||||
boolean isCreateCandidate = method.getMappingTargetParameter() == null;
|
|
||||||
|
List<SelectedMethod<T>> createCandidates = new ArrayList<SelectedMethod<T>>();
|
||||||
|
List<SelectedMethod<T>> updateCandidates = new ArrayList<SelectedMethod<T>>();
|
||||||
|
for ( SelectedMethod<T> method : methods ) {
|
||||||
|
boolean isCreateCandidate = method.getMethod().getMappingTargetParameter() == null;
|
||||||
if ( isCreateCandidate ) {
|
if ( isCreateCandidate ) {
|
||||||
createCandidates.add( method );
|
createCandidates.add( method );
|
||||||
}
|
}
|
||||||
|
@ -35,26 +35,26 @@ 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<T> getMatchingMethods(
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Method mappingMethod,
|
List<SelectedMethod<T>> methods,
|
||||||
List<T> methods,
|
List<Type> sourceTypes,
|
||||||
Type sourceType,
|
Type targetType,
|
||||||
Type targetType,
|
SelectionCriteria criteria) {
|
||||||
SelectionCriteria criteria
|
|
||||||
) {
|
|
||||||
|
|
||||||
if ( sourceType == null ) {
|
if ( sourceTypes.size() != 1 ) {
|
||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T> candidatesWithBestMatchingSourceType = new ArrayList<T>();
|
Type singleSourceType = first( sourceTypes );
|
||||||
|
|
||||||
|
List<SelectedMethod<T>> candidatesWithBestMatchingSourceType = new ArrayList<SelectedMethod<T>>();
|
||||||
int bestMatchingSourceTypeDistance = Integer.MAX_VALUE;
|
int bestMatchingSourceTypeDistance = Integer.MAX_VALUE;
|
||||||
|
|
||||||
// find the methods with the minimum distance regarding getParameter getParameter type
|
// find the methods with the minimum distance regarding getParameter getParameter type
|
||||||
for ( T method : methods ) {
|
for ( SelectedMethod<T> method : methods ) {
|
||||||
Parameter singleSourceParam = first( method.getSourceParameters() );
|
Parameter singleSourceParam = first( method.getMethod().getSourceParameters() );
|
||||||
|
|
||||||
int sourceTypeDistance = sourceType.distanceTo( singleSourceParam.getType() );
|
int sourceTypeDistance = singleSourceType.distanceTo( singleSourceParam.getType() );
|
||||||
bestMatchingSourceTypeDistance =
|
bestMatchingSourceTypeDistance =
|
||||||
addToCandidateListIfMinimal(
|
addToCandidateListIfMinimal(
|
||||||
candidatesWithBestMatchingSourceType,
|
candidatesWithBestMatchingSourceType,
|
||||||
@ -66,8 +66,8 @@ public class InheritanceSelector implements MethodSelector {
|
|||||||
return candidatesWithBestMatchingSourceType;
|
return candidatesWithBestMatchingSourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Method> int addToCandidateListIfMinimal(List<T> candidatesWithBestMathingType,
|
private <T extends Method> int addToCandidateListIfMinimal(List<SelectedMethod<T>> candidatesWithBestMathingType,
|
||||||
int bestMatchingTypeDistance, T method,
|
int bestMatchingTypeDistance, SelectedMethod<T> method,
|
||||||
int currentTypeDistance) {
|
int currentTypeDistance) {
|
||||||
if ( currentTypeDistance == bestMatchingTypeDistance ) {
|
if ( currentTypeDistance == bestMatchingTypeDistance ) {
|
||||||
candidatesWithBestMathingType.add( method );
|
candidatesWithBestMathingType.add( method );
|
||||||
|
@ -23,23 +23,26 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
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.MethodMatcher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects those methods from the given input set which match whether a factory was requested ({@link MethodMatcher} and
|
* Selects those methods from the given input set which match for the requested family of methods: factory methods,
|
||||||
* {@link org.mapstruct.ObjectFactory}).
|
* lifecycle callback methods, or any other mapping methods.
|
||||||
*
|
*
|
||||||
* @author Remo Meier
|
* @author Remo Meier
|
||||||
*/
|
*/
|
||||||
public class ObjectFactorySelector implements MethodSelector {
|
public class MethodFamilySelector implements MethodSelector {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods, Type sourceType,
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Type targetType, SelectionCriteria criteria) {
|
List<SelectedMethod<T>> methods,
|
||||||
|
List<Type> sourceTypes,
|
||||||
|
Type targetType, SelectionCriteria criteria) {
|
||||||
|
|
||||||
|
List<SelectedMethod<T>> result = new ArrayList<SelectedMethod<T>>( methods.size() );
|
||||||
|
for ( SelectedMethod<T> method : methods ) {
|
||||||
|
if ( method.getMethod().isObjectFactory() == criteria.isObjectFactoryRequired()
|
||||||
|
&& method.getMethod().isLifecycleCallbackMethod() == criteria.isLifecycleCallbackRequired() ) {
|
||||||
|
|
||||||
List<T> result = new ArrayList<T>();
|
|
||||||
for ( T method : methods ) {
|
|
||||||
if ( method.isObjectFactory() == criteria.isObjectFactoryRequired() ) {
|
|
||||||
result.add( method );
|
result.add( method );
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30,20 +30,21 @@ import org.mapstruct.ap.internal.model.source.Method;
|
|||||||
*
|
*
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public interface MethodSelector {
|
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 mappingMethod mapping method, defined in Mapper for which this selection is carried out
|
||||||
* @param methods list of available methods
|
* @param candidates list of available methods
|
||||||
* @param sourceType parameter type that should be matched
|
* @param sourceTypes parameter type(s) that should be matched
|
||||||
* @param targetType return type that should be matched
|
* @param targetType result type that should be matched
|
||||||
* @param criteria criteria used in the selection process
|
* @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<T> getMatchingMethods(Method mappingMethod, List<T> methods, Type sourceType,
|
<T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Type targetType, SelectionCriteria criteria);
|
List<SelectedMethod<T>> candidates,
|
||||||
|
List<Type> sourceTypes,
|
||||||
|
Type targetType, SelectionCriteria criteria);
|
||||||
}
|
}
|
||||||
|
@ -34,38 +34,48 @@ import org.mapstruct.ap.internal.model.source.Method;
|
|||||||
*
|
*
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public class MethodSelectors implements MethodSelector {
|
public class MethodSelectors {
|
||||||
|
|
||||||
private final List<MethodSelector> selectors;
|
private final List<MethodSelector> selectors;
|
||||||
|
|
||||||
public MethodSelectors(Types typeUtils, Elements elementUtils, TypeFactory typeFactory) {
|
public MethodSelectors(Types typeUtils, Elements elementUtils, TypeFactory typeFactory) {
|
||||||
selectors =
|
selectors = Arrays.asList(
|
||||||
Arrays.<MethodSelector>asList(
|
new MethodFamilySelector(),
|
||||||
new ObjectFactorySelector(),
|
new TypeSelector( typeFactory ),
|
||||||
new TypeSelector(),
|
new QualifierSelector( typeUtils, elementUtils ),
|
||||||
new QualifierSelector( typeUtils, elementUtils ),
|
new TargetTypeSelector( typeUtils, elementUtils ),
|
||||||
new TargetTypeSelector( typeUtils, elementUtils ),
|
new XmlElementDeclSelector( typeUtils, elementUtils ),
|
||||||
new XmlElementDeclSelector( typeUtils, elementUtils ),
|
new InheritanceSelector(),
|
||||||
new InheritanceSelector(),
|
new CreateOrUpdateSelector() );
|
||||||
new CreateOrUpdateSelector()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
* Selects those methods which match the given types and other criteria
|
||||||
Type sourceType, Type targetType,
|
*
|
||||||
SelectionCriteria 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 targetType return type that should be matched
|
||||||
|
* @param criteria criteria used in the selection 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 targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
List<T> candidates = new ArrayList<T>( methods );
|
List<SelectedMethod<T>> candidates = new ArrayList<SelectedMethod<T>>( methods.size() );
|
||||||
|
for ( T method : methods ) {
|
||||||
|
candidates.add( new SelectedMethod<T>( method ) );
|
||||||
|
}
|
||||||
|
|
||||||
for ( MethodSelector selector : selectors ) {
|
for ( MethodSelector selector : selectors ) {
|
||||||
candidates = selector.getMatchingMethods(
|
candidates = selector.getMatchingMethods(
|
||||||
mappingMethod,
|
mappingMethod,
|
||||||
candidates,
|
candidates,
|
||||||
sourceType,
|
sourceTypes,
|
||||||
targetType,
|
targetType,
|
||||||
criteria
|
criteria );
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,10 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Type sourceType, Type targetType,
|
List<SelectedMethod<T>> methods,
|
||||||
SelectionCriteria criteria) {
|
List<Type> sourceTypes, Type targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
int numberOfQualifiersToMatch = 0;
|
int numberOfQualifiersToMatch = 0;
|
||||||
|
|
||||||
@ -89,11 +90,11 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
// Check there are qualfiers for this mapping: Mapping#qualifier or Mapping#qualfiedByName
|
// Check there are qualfiers for this mapping: Mapping#qualifier or Mapping#qualfiedByName
|
||||||
if ( qualifierTypes.isEmpty() ) {
|
if ( qualifierTypes.isEmpty() ) {
|
||||||
// When no qualifiers, disqualify all methods marked with a qualifier by removing them from the candidates
|
// When no qualifiers, disqualify all methods marked with a qualifier by removing them from the candidates
|
||||||
List<T> nonQualiferAnnotatedMethods = new ArrayList<T>();
|
List<SelectedMethod<T>> nonQualiferAnnotatedMethods = new ArrayList<SelectedMethod<T>>( methods.size() );
|
||||||
for ( T candidate : methods ) {
|
for ( SelectedMethod<T> candidate : methods ) {
|
||||||
|
|
||||||
if ( candidate instanceof SourceMethod ) {
|
if ( candidate.getMethod() instanceof SourceMethod ) {
|
||||||
Set<AnnotationMirror> qualifierAnnotations = getQualifierAnnotationMirrors( candidate );
|
Set<AnnotationMirror> qualifierAnnotations = getQualifierAnnotationMirrors( candidate.getMethod() );
|
||||||
if ( qualifierAnnotations.isEmpty() ) {
|
if ( qualifierAnnotations.isEmpty() ) {
|
||||||
nonQualiferAnnotatedMethods.add( candidate );
|
nonQualiferAnnotatedMethods.add( candidate );
|
||||||
}
|
}
|
||||||
@ -107,15 +108,16 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Check all methods marked with qualfier (or methods in Mappers marked wiht a qualfier) for matches.
|
// Check all methods marked with qualfier (or methods in Mappers marked wiht a qualfier) for matches.
|
||||||
List<T> matches = new ArrayList<T>();
|
List<SelectedMethod<T>> matches = new ArrayList<SelectedMethod<T>>( methods.size() );
|
||||||
for ( T candidate : methods ) {
|
for ( SelectedMethod<T> candidate : methods ) {
|
||||||
|
|
||||||
if ( !( candidate instanceof SourceMethod ) ) {
|
if ( !( candidate.getMethod() instanceof SourceMethod ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve annotations
|
// retrieve annotations
|
||||||
Set<AnnotationMirror> qualifierAnnotationMirrors = getQualifierAnnotationMirrors( candidate );
|
Set<AnnotationMirror> qualifierAnnotationMirrors =
|
||||||
|
getQualifierAnnotationMirrors( candidate.getMethod() );
|
||||||
|
|
||||||
// now count if all qualifiers are matched
|
// now count if all qualifiers are matched
|
||||||
int matchingQualifierCounter = 0;
|
int matchingQualifierCounter = 0;
|
||||||
|
@ -16,28 +16,40 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model;
|
package org.mapstruct.ap.internal.model.source.selector;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
import org.mapstruct.ap.internal.model.common.ParameterBinding;
|
||||||
import org.mapstruct.ap.internal.model.source.Method;
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a reference to a factory method.
|
* A selected method with additional metadata that might be required for further usage of the selected method.
|
||||||
*
|
*
|
||||||
* @author Remo Meier
|
* @author Andreas Gudian
|
||||||
*/
|
*/
|
||||||
public class ObjectFactoryMethodReference extends MethodReference {
|
public class SelectedMethod<T extends Method> {
|
||||||
|
private T method;
|
||||||
|
private List<ParameterBinding> parameterBindings;
|
||||||
|
|
||||||
private final List<Parameter> parameterAssignments;
|
public SelectedMethod(T method) {
|
||||||
|
this.method = method;
|
||||||
public ObjectFactoryMethodReference(Method method, MapperReference ref, List<Parameter> parameterAssignments) {
|
|
||||||
super( method, ref, null );
|
|
||||||
this.parameterAssignments = parameterAssignments;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Parameter> getParameterAssignments() {
|
public T getMethod() {
|
||||||
return parameterAssignments;
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ParameterBinding> getParameterBindings() {
|
||||||
|
return parameterBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParameterBindings(List<ParameterBinding> parameterBindings) {
|
||||||
|
this.parameterBindings = parameterBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return method.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,6 +22,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
import org.mapstruct.ap.internal.model.source.SelectionParameters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,9 +38,11 @@ public class SelectionCriteria {
|
|||||||
private final TypeMirror qualifyingResultType;
|
private final TypeMirror qualifyingResultType;
|
||||||
private boolean preferUpdateMapping;
|
private boolean preferUpdateMapping;
|
||||||
private final boolean objectFactoryRequired;
|
private final boolean objectFactoryRequired;
|
||||||
|
private final boolean lifecycleCallbackRequired;
|
||||||
|
|
||||||
public SelectionCriteria(SelectionParameters selectionParameters, String targetPropertyName,
|
public SelectionCriteria(SelectionParameters selectionParameters, String targetPropertyName,
|
||||||
boolean preferUpdateMapping, boolean objectFactoryRequired) {
|
boolean preferUpdateMapping, boolean objectFactoryRequired,
|
||||||
|
boolean lifecycleCallbackRequired) {
|
||||||
if ( selectionParameters != null ) {
|
if ( selectionParameters != null ) {
|
||||||
qualifiers.addAll( selectionParameters.getQualifiers() );
|
qualifiers.addAll( selectionParameters.getQualifiers() );
|
||||||
qualifiedByNames.addAll( selectionParameters.getQualifyingNames() );
|
qualifiedByNames.addAll( selectionParameters.getQualifyingNames() );
|
||||||
@ -51,6 +54,7 @@ public class SelectionCriteria {
|
|||||||
this.targetPropertyName = targetPropertyName;
|
this.targetPropertyName = targetPropertyName;
|
||||||
this.preferUpdateMapping = preferUpdateMapping;
|
this.preferUpdateMapping = preferUpdateMapping;
|
||||||
this.objectFactoryRequired = objectFactoryRequired;
|
this.objectFactoryRequired = objectFactoryRequired;
|
||||||
|
this.lifecycleCallbackRequired = lifecycleCallbackRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,6 +64,13 @@ public class SelectionCriteria {
|
|||||||
return objectFactoryRequired;
|
return objectFactoryRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if lifecycle callback methods should be selected, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isLifecycleCallbackRequired() {
|
||||||
|
return lifecycleCallbackRequired;
|
||||||
|
}
|
||||||
|
|
||||||
public List<TypeMirror> getQualifiers() {
|
public List<TypeMirror> getQualifiers() {
|
||||||
return qualifiers;
|
return qualifiers;
|
||||||
}
|
}
|
||||||
@ -84,4 +95,17 @@ public class SelectionCriteria {
|
|||||||
this.preferUpdateMapping = preferUpdateMapping;
|
this.preferUpdateMapping = preferUpdateMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SelectionCriteria forMappingMethods(SelectionParameters selectionParameters,
|
||||||
|
String targetPropertyName, boolean preferUpdateMapping) {
|
||||||
|
|
||||||
|
return new SelectionCriteria( selectionParameters, targetPropertyName, preferUpdateMapping, false, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SelectionCriteria forFactoryMethods(SelectionParameters selectionParameters) {
|
||||||
|
return new SelectionCriteria( selectionParameters, null, false, true, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SelectionCriteria forLifecycleMethods(SelectionParameters selectionParameters) {
|
||||||
|
return new SelectionCriteria( selectionParameters, null, false, false, true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,16 +45,19 @@ public class TargetTypeSelector implements MethodSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Type sourceType, Type targetType,
|
List<SelectedMethod<T>> methods,
|
||||||
SelectionCriteria criteria) {
|
List<Type> sourceTypes, Type targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
TypeMirror qualifyingTypeMirror = criteria.getQualifyingResultType();
|
TypeMirror qualifyingTypeMirror = criteria.getQualifyingResultType();
|
||||||
if ( qualifyingTypeMirror != null ) {
|
if ( qualifyingTypeMirror != null && !criteria.isLifecycleCallbackRequired() ) {
|
||||||
|
|
||||||
List<T> candidatesWithQualifyingTargetType = new ArrayList<T>();
|
List<SelectedMethod<T>> candidatesWithQualifyingTargetType =
|
||||||
for ( T method : methods ) {
|
new ArrayList<SelectedMethod<T>>( methods.size() );
|
||||||
TypeMirror resultTypeMirror = method.getResultType().getTypeElement().asType();
|
|
||||||
|
for ( SelectedMethod<T> method : methods ) {
|
||||||
|
TypeMirror resultTypeMirror = method.getMethod().getResultType().getTypeElement().asType();
|
||||||
if ( typeUtils.isSameType( qualifyingTypeMirror, resultTypeMirror ) ) {
|
if ( typeUtils.isSameType( qualifyingTypeMirror, resultTypeMirror ) ) {
|
||||||
candidatesWithQualifyingTargetType.add( method );
|
candidatesWithQualifyingTargetType.add( method );
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.model.source.selector;
|
package org.mapstruct.ap.internal.model.source.selector;
|
||||||
|
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||||
|
import org.mapstruct.ap.internal.model.common.ParameterBinding;
|
||||||
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;
|
||||||
|
|
||||||
@ -34,17 +38,168 @@ import org.mapstruct.ap.internal.model.source.MethodMatcher;
|
|||||||
*/
|
*/
|
||||||
public class TypeSelector implements MethodSelector {
|
public class TypeSelector implements MethodSelector {
|
||||||
|
|
||||||
@Override
|
private TypeFactory typeFactory;
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
|
||||||
Type sourceType, Type targetType,
|
|
||||||
SelectionCriteria criteria) {
|
|
||||||
|
|
||||||
List<T> result = new ArrayList<T>();
|
public TypeSelector(TypeFactory typeFactory) {
|
||||||
for ( T method : methods ) {
|
this.typeFactory = typeFactory;
|
||||||
if ( !method.isLifecycleCallbackMethod() && method.matches( Arrays.asList( sourceType ), targetType ) ) {
|
}
|
||||||
result.add( method );
|
|
||||||
|
@Override
|
||||||
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
|
List<SelectedMethod<T>> methods,
|
||||||
|
List<Type> sourceTypes, Type targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
|
if ( methods.isEmpty() ) {
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SelectedMethod<T>> result = new ArrayList<SelectedMethod<T>>();
|
||||||
|
|
||||||
|
List<ParameterBinding> availableBindings;
|
||||||
|
if ( sourceTypes.isEmpty() ) {
|
||||||
|
// if no source types are given, we have a factory or lifecycle method
|
||||||
|
availableBindings = getAvailableParameterBindingsFromMethod( mappingMethod );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
availableBindings = getAvailableParameterBindingsFromSourceTypes( sourceTypes, targetType );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( SelectedMethod<T> method : methods ) {
|
||||||
|
List<List<ParameterBinding>> parameterBindingPermutations =
|
||||||
|
getCandidateParameterBindingPermutations( availableBindings, method.getMethod().getParameters() );
|
||||||
|
|
||||||
|
if ( parameterBindingPermutations != null ) {
|
||||||
|
SelectedMethod<T> matchingMethod =
|
||||||
|
getFirstMatchingParameterBinding( targetType, method, parameterBindingPermutations );
|
||||||
|
|
||||||
|
if ( matchingMethod != null ) {
|
||||||
|
result.add( matchingMethod );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ParameterBinding> getAvailableParameterBindingsFromMethod(Method method) {
|
||||||
|
List<ParameterBinding> availableParams = new ArrayList<ParameterBinding>( method.getParameters().size() + 2 );
|
||||||
|
|
||||||
|
availableParams.addAll( ParameterBinding.fromParameters( method.getParameters() ) );
|
||||||
|
addMappingTargetAndTargetTypeBindings( availableParams, method.getResultType() );
|
||||||
|
|
||||||
|
return availableParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ParameterBinding> getAvailableParameterBindingsFromSourceTypes(List<Type> sourceTypes,
|
||||||
|
Type targetType) {
|
||||||
|
|
||||||
|
List<ParameterBinding> availableParams = new ArrayList<ParameterBinding>( sourceTypes.size() + 2 );
|
||||||
|
|
||||||
|
addMappingTargetAndTargetTypeBindings( availableParams, targetType );
|
||||||
|
|
||||||
|
for ( Type sourceType : sourceTypes ) {
|
||||||
|
availableParams.add( ParameterBinding.forSourceTypeBinding( sourceType ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMappingTargetAndTargetTypeBindings(List<ParameterBinding> availableParams, Type targetType) {
|
||||||
|
availableParams.add( ParameterBinding.forMappingTargetBinding( targetType ) );
|
||||||
|
availableParams.add( ParameterBinding.forTargetTypeBinding( typeFactory.classTypeOf( targetType ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Method> SelectedMethod<T> getFirstMatchingParameterBinding(Type targetType,
|
||||||
|
SelectedMethod<T> method, List<List<ParameterBinding>> parameterAssignmentVariants) {
|
||||||
|
|
||||||
|
for ( List<ParameterBinding> parameterAssignments : parameterAssignmentVariants ) {
|
||||||
|
if ( method.getMethod().matches( extractTypes( parameterAssignments ), targetType ) ) {
|
||||||
|
method.setParameterBindings( parameterAssignments );
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param availableParams parameter bindings available in the scope of the method call
|
||||||
|
* @param methodParameters parameters of the method that is inspected
|
||||||
|
* @return all parameter binding permutations for which proper type checks need to be conducted.
|
||||||
|
*/
|
||||||
|
private static List<List<ParameterBinding>> getCandidateParameterBindingPermutations(
|
||||||
|
List<ParameterBinding> availableParams,
|
||||||
|
List<Parameter> methodParameters) {
|
||||||
|
|
||||||
|
if ( methodParameters.size() > availableParams.size() ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<List<ParameterBinding>> bindingPermutations = new ArrayList<List<ParameterBinding>>( 1 );
|
||||||
|
bindingPermutations.add( new ArrayList<ParameterBinding>( methodParameters.size() ) );
|
||||||
|
|
||||||
|
for ( Parameter methodParam : methodParameters ) {
|
||||||
|
List<ParameterBinding> candidateBindings =
|
||||||
|
findCandidateBindingsForParameter( availableParams, methodParam );
|
||||||
|
|
||||||
|
if ( candidateBindings.isEmpty() ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( candidateBindings.size() == 1 ) {
|
||||||
|
// short-cut to avoid list-copies for the usual case where only one binding fits
|
||||||
|
for ( List<ParameterBinding> variant : bindingPermutations ) {
|
||||||
|
// add binding to each existing variant
|
||||||
|
variant.add( first( candidateBindings ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List<List<ParameterBinding>> newVariants =
|
||||||
|
new ArrayList<List<ParameterBinding>>( bindingPermutations.size() * candidateBindings.size() );
|
||||||
|
for ( List<ParameterBinding> variant : bindingPermutations ) {
|
||||||
|
// create a copy of each variant for each binding
|
||||||
|
for ( ParameterBinding binding : candidateBindings ) {
|
||||||
|
List<ParameterBinding> extendedVariant =
|
||||||
|
new ArrayList<ParameterBinding>( methodParameters.size() );
|
||||||
|
extendedVariant.addAll( variant );
|
||||||
|
extendedVariant.add( binding );
|
||||||
|
|
||||||
|
newVariants.add( extendedVariant );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingPermutations = newVariants;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindingPermutations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param candidateParameters available for assignment.
|
||||||
|
* @param parameter that need assignment from one of the candidate parameter bindings.
|
||||||
|
* @return list of candidate parameter bindings that might be assignable.
|
||||||
|
*/
|
||||||
|
private static List<ParameterBinding> findCandidateBindingsForParameter(List<ParameterBinding> candidateParameters,
|
||||||
|
Parameter parameter) {
|
||||||
|
List<ParameterBinding> result = new ArrayList<ParameterBinding>( candidateParameters.size() );
|
||||||
|
|
||||||
|
for ( ParameterBinding candidate : candidateParameters ) {
|
||||||
|
if ( parameter.isTargetType() == candidate.isTargetType()
|
||||||
|
&& parameter.isMappingTarget() == candidate.isMappingTarget() ) {
|
||||||
|
result.add( candidate );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Type> extractTypes(List<ParameterBinding> parameters) {
|
||||||
|
List<Type> result = new ArrayList<Type>( parameters.size() );
|
||||||
|
|
||||||
|
for ( ParameterBinding param : parameters ) {
|
||||||
|
result.add( param.getType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,10 @@ public class XmlElementDeclSelector implements MethodSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(Method mappingMethod,
|
||||||
Type sourceType, Type targetType,
|
List<SelectedMethod<T>> methods,
|
||||||
SelectionCriteria criteria) {
|
List<Type> sourceTypes, Type targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
// only true source methods are qualifying
|
// only true source methods are qualifying
|
||||||
if ( !(mappingMethod instanceof SourceMethod) ) {
|
if ( !(mappingMethod instanceof SourceMethod) ) {
|
||||||
@ -72,18 +73,18 @@ public class XmlElementDeclSelector implements MethodSelector {
|
|||||||
|
|
||||||
SourceMethod sourceMappingMethod = (SourceMethod) mappingMethod;
|
SourceMethod sourceMappingMethod = (SourceMethod) mappingMethod;
|
||||||
|
|
||||||
List<T> nameMatches = new ArrayList<T>();
|
List<SelectedMethod<T>> nameMatches = new ArrayList<SelectedMethod<T>>();
|
||||||
List<T> scopeMatches = new ArrayList<T>();
|
List<SelectedMethod<T>> scopeMatches = new ArrayList<SelectedMethod<T>>();
|
||||||
List<T> nameAndScopeMatches = new ArrayList<T>();
|
List<SelectedMethod<T>> nameAndScopeMatches = new ArrayList<SelectedMethod<T>>();
|
||||||
XmlElementRefInfo xmlElementRefInfo =
|
XmlElementRefInfo xmlElementRefInfo =
|
||||||
findXmlElementRef( sourceMappingMethod.getResultType(), criteria.getTargetPropertyName() );
|
findXmlElementRef( sourceMappingMethod.getResultType(), criteria.getTargetPropertyName() );
|
||||||
|
|
||||||
for ( T candidate : methods ) {
|
for ( SelectedMethod<T> candidate : methods ) {
|
||||||
if ( !( candidate instanceof SourceMethod ) ) {
|
if ( !( candidate.getMethod() instanceof SourceMethod ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceMethod candidateMethod = (SourceMethod) candidate;
|
SourceMethod candidateMethod = (SourceMethod) candidate.getMethod();
|
||||||
XmlElementDeclPrism xmlElememtDecl = XmlElementDeclPrism.getInstanceOn( candidateMethod.getExecutable() );
|
XmlElementDeclPrism xmlElememtDecl = XmlElementDeclPrism.getInstanceOn( candidateMethod.getExecutable() );
|
||||||
|
|
||||||
if ( xmlElememtDecl == null ) {
|
if ( xmlElememtDecl == null ) {
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
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 java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -39,23 +42,20 @@ import org.mapstruct.ap.internal.model.HelperMethod;
|
|||||||
import org.mapstruct.ap.internal.model.MapperReference;
|
import org.mapstruct.ap.internal.model.MapperReference;
|
||||||
import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
|
import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
|
||||||
import org.mapstruct.ap.internal.model.MethodReference;
|
import org.mapstruct.ap.internal.model.MethodReference;
|
||||||
import org.mapstruct.ap.internal.model.ObjectFactoryMethodReference;
|
|
||||||
import org.mapstruct.ap.internal.model.ParameterAssignmentUtil;
|
|
||||||
import org.mapstruct.ap.internal.model.SourceRHS;
|
import org.mapstruct.ap.internal.model.SourceRHS;
|
||||||
import org.mapstruct.ap.internal.model.VirtualMappingMethod;
|
import org.mapstruct.ap.internal.model.VirtualMappingMethod;
|
||||||
import org.mapstruct.ap.internal.model.assignment.Assignment;
|
import org.mapstruct.ap.internal.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
import org.mapstruct.ap.internal.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.internal.model.common.DefaultConversionContext;
|
import org.mapstruct.ap.internal.model.common.DefaultConversionContext;
|
||||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
|
||||||
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.common.TypeFactory;
|
||||||
import org.mapstruct.ap.internal.model.source.FormattingParameters;
|
import org.mapstruct.ap.internal.model.source.FormattingParameters;
|
||||||
import org.mapstruct.ap.internal.model.source.Method;
|
import org.mapstruct.ap.internal.model.source.Method;
|
||||||
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.builtin.BuiltInMappingMethods;
|
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.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.FormattingMessager;
|
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||||
@ -109,7 +109,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
boolean preferUpdateMapping) {
|
boolean preferUpdateMapping) {
|
||||||
|
|
||||||
SelectionCriteria criteria =
|
SelectionCriteria criteria =
|
||||||
new SelectionCriteria( selectionParameters, targetPropertyName, preferUpdateMapping, false );
|
SelectionCriteria.forMappingMethods( selectionParameters, targetPropertyName, preferUpdateMapping );
|
||||||
|
|
||||||
String dateFormat = null;
|
String dateFormat = null;
|
||||||
String numberFormat = null;
|
String numberFormat = null;
|
||||||
@ -139,58 +139,46 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
public MethodReference getFactoryMethod(final Method mappingMethod, Type targetType,
|
public MethodReference getFactoryMethod(final Method mappingMethod, Type targetType,
|
||||||
SelectionParameters selectionParameters) {
|
SelectionParameters selectionParameters) {
|
||||||
|
|
||||||
SelectionCriteria criteria = new SelectionCriteria( selectionParameters, null, false, true );
|
List<SelectedMethod<Method>> matchingFactoryMethods =
|
||||||
|
methodSelectors.getMatchingMethods(
|
||||||
|
mappingMethod,
|
||||||
|
sourceModel,
|
||||||
|
java.util.Collections.<Type> emptyList(),
|
||||||
|
targetType,
|
||||||
|
SelectionCriteria.forFactoryMethods( selectionParameters ) );
|
||||||
|
|
||||||
ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, mappingMethod, null, null, null, criteria );
|
if (matchingFactoryMethods.isEmpty()) {
|
||||||
|
return null;
|
||||||
List<Method> matchingSourceMethods = attempt.getMatches( sourceModel, null, targetType );
|
|
||||||
|
|
||||||
List<MethodReference> factoryRefsWithAssigments = new ArrayList<MethodReference>();
|
|
||||||
List<Method> factoryRefSources = new ArrayList<Method>();
|
|
||||||
|
|
||||||
for ( Method matchingSourceMethod : matchingSourceMethods ) {
|
|
||||||
|
|
||||||
if ( matchingSourceMethod != null ) {
|
|
||||||
MapperReference ref = attempt.findMapperReference( matchingSourceMethod );
|
|
||||||
|
|
||||||
if ( matchingSourceMethod.getSourceParameters().isEmpty() ) {
|
|
||||||
// factory taking no argument
|
|
||||||
factoryRefsWithAssigments.add( new MethodReference( matchingSourceMethod, ref, null ) );
|
|
||||||
factoryRefSources.add( matchingSourceMethod );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// check whether factory have has a valid assignment, if so, choose as candidate
|
|
||||||
List<Parameter> availableParameters = new ArrayList<Parameter>();
|
|
||||||
availableParameters.addAll( mappingMethod.getSourceParameters() );
|
|
||||||
availableParameters.add(
|
|
||||||
new Parameter( null,
|
|
||||||
typeFactory.classTypeOf( targetType ),
|
|
||||||
false, true, false ) );
|
|
||||||
List<Parameter> factoryParamAssinment =
|
|
||||||
ParameterAssignmentUtil.getParameterAssignments( availableParameters,
|
|
||||||
matchingSourceMethod.getParameters() );
|
|
||||||
if ( factoryParamAssinment != null ) {
|
|
||||||
factoryRefSources.add( matchingSourceMethod );
|
|
||||||
factoryRefsWithAssigments.add(
|
|
||||||
new ObjectFactoryMethodReference( matchingSourceMethod, ref, factoryParamAssinment ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( factoryRefsWithAssigments.size() > 1 ) {
|
if ( matchingFactoryMethods.size() > 1 ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
mappingMethod.getExecutable(),
|
mappingMethod.getExecutable(),
|
||||||
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
|
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
|
||||||
targetType,
|
targetType,
|
||||||
Strings.join( factoryRefSources, ", " ) );
|
Strings.join( matchingFactoryMethods, ", " ) );
|
||||||
}
|
|
||||||
else if ( factoryRefsWithAssigments.size() == 1 ) {
|
return null;
|
||||||
// factory methods with assignment are favored over the ones without any
|
|
||||||
return factoryRefsWithAssigments.get( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no factory found
|
SelectedMethod<Method> matchingFactoryMethod = first( matchingFactoryMethods );
|
||||||
|
|
||||||
|
MapperReference ref = findMapperReference( matchingFactoryMethod.getMethod() );
|
||||||
|
|
||||||
|
return new MethodReference(
|
||||||
|
matchingFactoryMethod.getMethod(),
|
||||||
|
ref,
|
||||||
|
matchingFactoryMethod.getParameterBindings() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapperReference findMapperReference(Method method) {
|
||||||
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
|
ref.setUsed( ref.isUsed() || !method.isStatic() );
|
||||||
|
ref.setTypeRequiresImport( true );
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +303,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
private Assignment resolveViaMethod(Type sourceType, Type targetType, boolean considerBuiltInMethods) {
|
private Assignment resolveViaMethod(Type sourceType, Type targetType, boolean considerBuiltInMethods) {
|
||||||
|
|
||||||
// first try to find a matching source method
|
// first try to find a matching source method
|
||||||
Method matchingSourceMethod = getBestMatch( methods, sourceType, targetType );
|
SelectedMethod<Method> matchingSourceMethod = getBestMatch( methods, sourceType, targetType );
|
||||||
|
|
||||||
if ( matchingSourceMethod != null ) {
|
if ( matchingSourceMethod != null ) {
|
||||||
return getMappingMethodReference( matchingSourceMethod, targetType );
|
return getMappingMethodReference( matchingSourceMethod, targetType );
|
||||||
@ -329,15 +317,15 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Assignment resolveViaBuiltInMethod(Type sourceType, Type targetType) {
|
private Assignment resolveViaBuiltInMethod(Type sourceType, Type targetType) {
|
||||||
BuiltInMethod matchingBuiltInMethod =
|
SelectedMethod<BuiltInMethod> matchingBuiltInMethod =
|
||||||
getBestMatch( builtInMethods.getBuiltInMethods(), sourceType, targetType );
|
getBestMatch( builtInMethods.getBuiltInMethods(), sourceType, targetType );
|
||||||
|
|
||||||
if ( matchingBuiltInMethod != null ) {
|
if ( matchingBuiltInMethod != null ) {
|
||||||
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
|
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod.getMethod() ) );
|
||||||
ConversionContext ctx = new DefaultConversionContext( typeFactory, messager,
|
ConversionContext ctx = new DefaultConversionContext( typeFactory, messager,
|
||||||
sourceType,
|
sourceType,
|
||||||
targetType, dateFormat, numberFormat);
|
targetType, dateFormat, numberFormat);
|
||||||
Assignment methodReference = new MethodReference( matchingBuiltInMethod, ctx );
|
Assignment methodReference = new MethodReference( matchingBuiltInMethod.getMethod(), ctx );
|
||||||
methodReference.setAssignment( sourceRHS );
|
methodReference.setAssignment( sourceRHS );
|
||||||
return methodReference;
|
return methodReference;
|
||||||
}
|
}
|
||||||
@ -491,22 +479,12 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
&& !methodCandidate.isLifecycleCallbackMethod();
|
&& !methodCandidate.isLifecycleCallbackMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Method> List<T> getMatches(List<T> methods, Type sourceType, Type returnType) {
|
private <T extends Method> SelectedMethod<T> getBestMatch(List<T> methods, Type sourceType, Type returnType) {
|
||||||
return methodSelectors.getMatchingMethods(
|
|
||||||
|
List<SelectedMethod<T>> candidates = methodSelectors.getMatchingMethods(
|
||||||
mappingMethod,
|
mappingMethod,
|
||||||
methods,
|
methods,
|
||||||
sourceType,
|
singletonList( sourceType ),
|
||||||
returnType,
|
|
||||||
selectionCriteria
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends Method> T getBestMatch(List<T> methods, Type sourceType, Type returnType) {
|
|
||||||
|
|
||||||
List<T> candidates = methodSelectors.getMatchingMethods(
|
|
||||||
mappingMethod,
|
|
||||||
methods,
|
|
||||||
sourceType,
|
|
||||||
returnType,
|
returnType,
|
||||||
selectionCriteria
|
selectionCriteria
|
||||||
);
|
);
|
||||||
@ -533,33 +511,23 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( !candidates.isEmpty() ) {
|
if ( !candidates.isEmpty() ) {
|
||||||
return candidates.get( 0 );
|
return first( candidates );
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Assignment getMappingMethodReference(Method method,
|
private Assignment getMappingMethodReference(SelectedMethod<Method> method,
|
||||||
Type targetType) {
|
Type targetType) {
|
||||||
MapperReference mapperReference = findMapperReference( method );
|
MapperReference mapperReference = findMapperReference( method.getMethod() );
|
||||||
|
|
||||||
return new MethodReference( method,
|
return new MethodReference(
|
||||||
|
method.getMethod(),
|
||||||
mapperReference,
|
mapperReference,
|
||||||
SourceMethod.containsTargetTypeParameter( method.getParameters() ) ? targetType : null
|
method.getParameterBindings()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MapperReference findMapperReference(Method method) {
|
|
||||||
for ( MapperReference ref : mapperReferences ) {
|
|
||||||
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
|
||||||
ref.setUsed( !method.isStatic() );
|
|
||||||
ref.setTypeRequiresImport( true );
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given source and target type are both a collection type or both a map type and the source value
|
* Whether the given source and target type are both a collection type or both a map type and the source value
|
||||||
* can be propagated via a copy constructor.
|
* can be propagated via a copy constructor.
|
||||||
|
@ -22,10 +22,7 @@
|
|||||||
<#if hasReturnType()>
|
<#if hasReturnType()>
|
||||||
<@includeModel object=methodResultType /> ${targetVariableName} =
|
<@includeModel object=methodResultType /> ${targetVariableName} =
|
||||||
</#if>
|
</#if>
|
||||||
<#if declaringType??>${instanceVariableName}.</#if>${name}(
|
<#include 'MethodReference.ftl'>;
|
||||||
<#list parameterAssignments as param>
|
|
||||||
<#if param.targetType><@includeModel object=ext.targetType raw=true/>.class<#elseif param.mappingTarget>${ext.targetBeanName}<#else>${param.name}</#if><#if param_has_next>,<#else> </#if>
|
|
||||||
</#list>);
|
|
||||||
</@compress>
|
</@compress>
|
||||||
<#if hasReturnType()><#nt>
|
<#if hasReturnType()><#nt>
|
||||||
if ( ${targetVariableName} != null ) {
|
if ( ${targetVariableName} != null ) {
|
||||||
|
@ -28,18 +28,20 @@
|
|||||||
</#if>
|
</#if>
|
||||||
<#macro params>
|
<#macro params>
|
||||||
<@compress>
|
<@compress>
|
||||||
${name}<#if (parameters?size > 0)>( <@arguments/> )<#else>()</#if>
|
${name}<#if (parameterBindings?size > 0)>( <@arguments/> )<#else>()</#if>
|
||||||
</@compress>
|
</@compress>
|
||||||
</#macro>
|
</#macro>
|
||||||
<#macro arguments>
|
<#macro arguments>
|
||||||
<#list parameters as param>
|
<#list parameterBindings as param>
|
||||||
<#if param.targetType>
|
<#if param.targetType>
|
||||||
<#-- a class is passed on for casting, see @TargetType -->
|
<#-- a class is passed on for casting, see @TargetType -->
|
||||||
<@includeModel object=ext.targetType raw=true/>.class<#t>
|
<@includeModel object=ext.targetType raw=true/>.class<#t>
|
||||||
<#elseif param.mappingTarget>
|
<#elseif param.mappingTarget>
|
||||||
${ext.targetBeanName}.${ext.targetReadAccessorName}
|
${ext.targetBeanName}<#if ext.targetReadAccessorName??>.${ext.targetReadAccessorName}</#if><#t>
|
||||||
|
<#elseif assignment??>
|
||||||
|
<@_assignment/><#t>
|
||||||
<#else>
|
<#else>
|
||||||
<@_assignment/>
|
${param.variableName}<#t>
|
||||||
</#if>
|
</#if>
|
||||||
<#if param_has_next>, </#if><#t>
|
<#if param_has_next>, </#if><#t>
|
||||||
</#list>
|
</#list>
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
<#--
|
|
||||||
|
|
||||||
Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
|
||||||
and/or other contributors as indicated by the @authors tag. See the
|
|
||||||
copyright.txt file in the distribution for a full listing of all
|
|
||||||
contributors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<@compress single_line=true>
|
|
||||||
<#-- method is either internal to the mapper class, or external (via uses) declaringMapper!=null -->
|
|
||||||
<#if declaringMapper??><#if static><@includeModel object=declaringMapper.type/><#else>${mapperVariableName}</#if>.<@params/>
|
|
||||||
<#-- method is referenced java8 static method in the mapper to implement (interface) -->
|
|
||||||
<#elseif static><@includeModel object=definingType/>.<@params/>
|
|
||||||
<#else>
|
|
||||||
<@params/>
|
|
||||||
</#if>
|
|
||||||
<#macro params>
|
|
||||||
<@compress>
|
|
||||||
${name}<#if (parameterAssignments?size > 0)>( <@arguments/> )<#else>()</#if>
|
|
||||||
</@compress>
|
|
||||||
</#macro>
|
|
||||||
<#macro arguments>
|
|
||||||
<#list parameterAssignments as param>
|
|
||||||
<#if param.targetType>
|
|
||||||
<#-- a class is passed on for casting, see @TargetType -->
|
|
||||||
<@includeModel object=ext.targetType raw=true/>.class<#t>
|
|
||||||
<#elseif param.mappingTarget>
|
|
||||||
${ext.targetBeanName}.${ext.targetReadAccessorName}()
|
|
||||||
<#else>${param.name}</#if><#if param_has_next>, </#if><#t>
|
|
||||||
</#list>
|
|
||||||
<#-- context parameter, e.g. for builtin methods concerning date conversion -->
|
|
||||||
<#if contextParam??>, ${contextParam}</#if><#t>
|
|
||||||
</#macro>
|
|
||||||
</@compress>
|
|
@ -73,7 +73,8 @@ public class AnnotationProcessorTestRunner extends ParentRunner<Runner> {
|
|||||||
|
|
||||||
return Arrays.<Runner> asList(
|
return Arrays.<Runner> asList(
|
||||||
new InnerAnnotationProcessorRunner( klass, Compiler.JDK ),
|
new InnerAnnotationProcessorRunner( klass, Compiler.JDK ),
|
||||||
new InnerAnnotationProcessorRunner( klass, Compiler.ECLIPSE ) );
|
new InnerAnnotationProcessorRunner( klass, Compiler.ECLIPSE )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user