#975 Refactor method-matching to unify selection and rendering of mapping method, factories and lifecycle methods

This commit is contained in:
Andreas Gudian 2016-12-18 00:48:20 +01:00
parent 46363028bd
commit 79f87e8833
29 changed files with 589 additions and 514 deletions

View File

@ -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;

View File

@ -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) {

View File

@ -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;
} }

View File

@ -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 );

View File

@ -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;
}
} }

View File

@ -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;
}
}

View File

@ -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 );

View File

@ -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;
} }
} }

View File

@ -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 );
}
}

View File

@ -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.

View File

@ -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;

View File

@ -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;
} }

View File

@ -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

View File

@ -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 );
} }

View File

@ -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 );

View File

@ -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 );
} }
} }

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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();
} }
} }

View File

@ -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 );
}
} }

View File

@ -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 );
} }

View File

@ -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;
}
} }

View File

@ -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 ) {

View File

@ -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.

View File

@ -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 ) {

View File

@ -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>

View File

@ -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>

View File

@ -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