mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#160 allow selection of update methods by refactoring MethodMatcher but stopping selection of update method at new filter
This commit is contained in:
parent
0c226f8388
commit
37e5942c86
@ -50,7 +50,7 @@ public abstract class MappingMethod extends ModelElement {
|
|||||||
this.name = method.getName();
|
this.name = method.getName();
|
||||||
this.parameters = method.getParameters();
|
this.parameters = method.getParameters();
|
||||||
this.returnType = method.getReturnType();
|
this.returnType = method.getReturnType();
|
||||||
this.targetParameter = method.getTargetParameter();
|
this.targetParameter = method.getMappingTargetParameter();
|
||||||
this.accessibility = method.getAccessibility();
|
this.accessibility = method.getAccessibility();
|
||||||
this.thrownTypes = method.getThrownTypes();
|
this.thrownTypes = method.getThrownTypes();
|
||||||
this.isStatic = method.isStatic();
|
this.isStatic = method.isStatic();
|
||||||
|
@ -71,19 +71,18 @@ public class ForgedMethod implements Method {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(List<Type> sourceTypes, Type targetType) {
|
public boolean matches(Type sourceTypes, Type targetType) {
|
||||||
|
|
||||||
if ( !targetType.equals( returnType ) ) {
|
if ( !targetType.equals( returnType ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sourceTypes.size() == parameters.size() ) {
|
if ( parameters.size() != 1 ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for ( int i = 0; i < sourceTypes.size(); i++ ) {
|
|
||||||
if ( !sourceTypes.get( i ).equals( parameters.get( i ).getType() ) ) {
|
if ( !sourceTypes.equals( parameters.get( 0 ).getType() ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -110,7 +109,12 @@ public class ForgedMethod implements Method {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter getTargetParameter() {
|
public Parameter getMappingTargetParameter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Parameter getTargetTypeParameter() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +40,12 @@ public interface Method {
|
|||||||
* Checks whether the provided sourceType and provided targetType match with the parameter respectively return type
|
* Checks whether the provided sourceType and provided targetType match with the parameter respectively return type
|
||||||
* of the method. The check also should incorporate wild card and generic type variables
|
* of the method. The check also should incorporate wild card and generic type variables
|
||||||
*
|
*
|
||||||
* @param sourceTypes the sourceTypes to match to the parameter
|
* @param sourceType the sourceType to match to the parameter
|
||||||
* @param targetType the targetType to match to the returnType
|
* @param targetType the targetType to match to the returnType
|
||||||
*
|
*
|
||||||
* @return true when match
|
* @return true when match
|
||||||
*/
|
*/
|
||||||
boolean matches(List<Type> sourceTypes, Type targetType);
|
boolean matches(Type sourceType, Type targetType );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the mapper type declaring this method if it is not declared by the mapper interface currently processed
|
* Returns the mapper type declaring this method if it is not declared by the mapper interface currently processed
|
||||||
@ -71,18 +71,26 @@ public interface Method {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the list of 'true' source parameters excluding the parameter(s) that is designated as
|
* returns the list of 'true' source parameters excluding the parameter(s) that is designated as
|
||||||
* target by means of the target annotation {@link #getTargetParameter() }.
|
* target by means of the target annotation {@link #getMappingTargetParameter() }.
|
||||||
*
|
*
|
||||||
* @return list of 'true' source parameters
|
* @return list of 'true' source parameters
|
||||||
*/
|
*/
|
||||||
List<Parameter> getSourceParameters();
|
List<Parameter> getSourceParameters();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parameter designated as target parameter (if present) {@link #getSourceParameters() }
|
* Returns the parameter designated as mapping target (if present) {@link org.mapstruct.MappingTarget }
|
||||||
*
|
*
|
||||||
* @return target parameter (when present) null otherwise.
|
* @return mapping target parameter (when present) null otherwise.
|
||||||
*/
|
*/
|
||||||
Parameter getTargetParameter();
|
Parameter getMappingTargetParameter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter designated as target type (if present) {@link org.mapstruct.TargetType }
|
||||||
|
*
|
||||||
|
* @return target type parameter (when present) null otherwise.
|
||||||
|
*/
|
||||||
|
Parameter getTargetTypeParameter();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Accessibility} of this method.
|
* Returns the {@link Accessibility} of this method.
|
||||||
|
@ -24,7 +24,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.element.TypeParameterElement;
|
import javax.lang.model.element.TypeParameterElement;
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.ArrayType;
|
import javax.lang.model.type.ArrayType;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.PrimitiveType;
|
import javax.lang.model.type.PrimitiveType;
|
||||||
@ -34,8 +33,10 @@ import javax.lang.model.type.TypeVariable;
|
|||||||
import javax.lang.model.type.WildcardType;
|
import javax.lang.model.type.WildcardType;
|
||||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
import org.mapstruct.ap.model.common.TypeFactory;
|
||||||
|
|
||||||
import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.isSubType;
|
import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.isSubType;
|
||||||
|
|
||||||
@ -68,80 +69,65 @@ public class MethodMatcher {
|
|||||||
|
|
||||||
private final SourceMethod candidateMethod;
|
private final SourceMethod candidateMethod;
|
||||||
private final Types typeUtils;
|
private final Types typeUtils;
|
||||||
|
private final TypeFactory typeFactory;
|
||||||
|
|
||||||
MethodMatcher(Types typeUtils, SourceMethod candidateMethod) {
|
MethodMatcher(Types typeUtils, TypeFactory typeFactory, SourceMethod candidateMethod) {
|
||||||
this.typeUtils = typeUtils;
|
this.typeUtils = typeUtils;
|
||||||
this.candidateMethod = candidateMethod;
|
this.candidateMethod = candidateMethod;
|
||||||
|
this.typeFactory = typeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given source and target types are matched by this matcher's candidate method.
|
* Whether the given source and target types are matched by this matcher's candidate method.
|
||||||
*
|
*
|
||||||
* @param sourceTypes the source types
|
* @param sourceType the source types
|
||||||
* @param targetType the target type
|
* @param resultType the target type
|
||||||
*
|
*
|
||||||
* @return {@code true} when both, source type and target types match the signature of this matcher's method;
|
* @return {@code true} when both, source type and target types match the signature of this matcher's method;
|
||||||
* {@code false} otherwise.
|
* {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
boolean matches(List<Type> sourceTypes, Type targetType) {
|
boolean matches(Type sourceType, Type resultType) {
|
||||||
// check & collect generic types.
|
|
||||||
List<? extends VariableElement> candidateParameters = candidateMethod.getExecutable().getParameters();
|
|
||||||
|
|
||||||
if ( candidateParameters.size() != sourceTypes.size() ) {
|
// check & collect generic types.
|
||||||
|
Map<TypeVariable, TypeMirror> genericTypesMap = new HashMap<TypeVariable, TypeMirror>();
|
||||||
|
|
||||||
|
// only factory / mapping methods with zero or one source parameters qualify
|
||||||
|
if ( candidateMethod.getSourceParameters().size() > 1 ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<TypeVariable, TypeMirror> genericTypesMap = new HashMap<TypeVariable, TypeMirror>();
|
if ( sourceType != null ) {
|
||||||
|
// if the sourcetype is not null then only methods with one source parameter qualfiy
|
||||||
int i = 0;
|
if ( candidateMethod.getSourceParameters().size() == 1 ) {
|
||||||
for ( VariableElement candidateParameter : candidateParameters ) {
|
Parameter sourceParam = candidateMethod.getSourceParameters().iterator().next();
|
||||||
TypeMatcher parameterMatcher = new TypeMatcher( Assignability.VISITED_ASSIGNABLE_FROM, genericTypesMap );
|
if ( !matchSourceType( sourceType, sourceParam.getType(), genericTypesMap ) ) {
|
||||||
Type sourceType = sourceTypes.get( i++ );
|
|
||||||
if ( !parameterMatcher.visit( candidateParameter.asType(), sourceType.getTypeMirror() ) ) {
|
|
||||||
if (sourceType.isPrimitive() ) {
|
|
||||||
// the candidate source is primitive, so promote to its boxed type and check again (autobox)
|
|
||||||
TypeMirror boxedType = typeUtils.boxedClass( (PrimitiveType) sourceType.getTypeMirror() ).asType();
|
|
||||||
if ( !parameterMatcher.visit( candidateParameter.asType(), boxedType ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// NOTE: unboxing is deliberately not considered here. This should be handled via type-conversion
|
|
||||||
// (for NPE safety).
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check return type
|
|
||||||
TypeMirror candidateReturnType = candidateMethod.getExecutable().getReturnType();
|
|
||||||
TypeMatcher returnTypeMatcher = new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO, genericTypesMap );
|
|
||||||
|
|
||||||
if ( !returnTypeMatcher.visit( candidateReturnType, targetType.getTypeMirror() ) ) {
|
|
||||||
if ( targetType.isPrimitive() ) {
|
|
||||||
TypeMirror boxedType = typeUtils.boxedClass( (PrimitiveType) targetType.getTypeMirror() ).asType();
|
|
||||||
TypeMatcher boxedReturnTypeMatcher =
|
|
||||||
new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO, genericTypesMap );
|
|
||||||
|
|
||||||
if ( !boxedReturnTypeMatcher.visit( candidateReturnType, boxedType ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( candidateReturnType.getKind().isPrimitive() ) {
|
|
||||||
TypeMirror boxedCandidateReturnType =
|
|
||||||
typeUtils.boxedClass( (PrimitiveType) candidateReturnType ).asType();
|
|
||||||
TypeMatcher boxedReturnTypeMatcher =
|
|
||||||
new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO, genericTypesMap );
|
|
||||||
|
|
||||||
if ( !boxedReturnTypeMatcher.visit( boxedCandidateReturnType, targetType.getTypeMirror() ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// if the sourcetype is null then only methods with zero source parameters qualfiy
|
||||||
|
if ( !candidateMethod.getSourceParameters().isEmpty() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the method matches the proper result type to construct
|
||||||
|
Parameter targetTypeParameter = candidateMethod.getTargetTypeParameter();
|
||||||
|
if ( targetTypeParameter != null ) {
|
||||||
|
Type returnClassType = typeFactory.classTypeOf( resultType );
|
||||||
|
if ( !matchSourceType( returnClassType, targetTypeParameter.getType(), genericTypesMap ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check result type
|
||||||
|
if ( !matchResultType( resultType, candidateMethod.getResultType(), genericTypesMap ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// check if all type parameters are indeed mapped
|
// check if all type parameters are indeed mapped
|
||||||
if ( candidateMethod.getExecutable().getTypeParameters().size() != genericTypesMap.size() ) {
|
if ( candidateMethod.getExecutable().getTypeParameters().size() != genericTypesMap.size() ) {
|
||||||
@ -158,6 +144,63 @@ public class MethodMatcher {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean matchSourceType(Type sourceType,
|
||||||
|
Type candidateSourceType,
|
||||||
|
Map<TypeVariable, TypeMirror> genericTypesMap) {
|
||||||
|
|
||||||
|
TypeMatcher parameterMatcher = new TypeMatcher( Assignability.VISITED_ASSIGNABLE_FROM, genericTypesMap );
|
||||||
|
if ( !parameterMatcher.visit( candidateSourceType.getTypeMirror(), sourceType.getTypeMirror() ) ) {
|
||||||
|
if ( sourceType.isPrimitive() ) {
|
||||||
|
// the candidate source is primitive, so promote to its boxed type and check again (autobox)
|
||||||
|
TypeMirror boxedType = typeUtils.boxedClass( (PrimitiveType) sourceType.getTypeMirror() ).asType();
|
||||||
|
if ( !parameterMatcher.visit( candidateSourceType.getTypeMirror(), boxedType ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// NOTE: unboxing is deliberately not considered here. This should be handled via type-conversion
|
||||||
|
// (for NPE safety).
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchResultType(Type resultType,
|
||||||
|
Type candidateResultType,
|
||||||
|
Map<TypeVariable, TypeMirror> genericTypesMap) {
|
||||||
|
|
||||||
|
TypeMatcher returnTypeMatcher = new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO, genericTypesMap );
|
||||||
|
|
||||||
|
if ( !returnTypeMatcher.visit( candidateResultType.getTypeMirror(), resultType.getTypeMirror() ) ) {
|
||||||
|
if ( resultType.isPrimitive() ) {
|
||||||
|
TypeMirror boxedType = typeUtils.boxedClass( (PrimitiveType) resultType.getTypeMirror() ).asType();
|
||||||
|
TypeMatcher boxedReturnTypeMatcher =
|
||||||
|
new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO, genericTypesMap );
|
||||||
|
|
||||||
|
if ( !boxedReturnTypeMatcher.visit( candidateResultType.getTypeMirror(), boxedType ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( candidateResultType.getTypeMirror().getKind().isPrimitive() ) {
|
||||||
|
TypeMirror boxedCandidateReturnType =
|
||||||
|
typeUtils.boxedClass( (PrimitiveType) candidateResultType.getTypeMirror() ).asType();
|
||||||
|
TypeMatcher boxedReturnTypeMatcher =
|
||||||
|
new TypeMatcher( Assignability.VISITED_ASSIGNABLE_TO, genericTypesMap );
|
||||||
|
|
||||||
|
if ( !boxedReturnTypeMatcher.visit( boxedCandidateReturnType, resultType.getTypeMirror() ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private enum Assignability {
|
private enum Assignability {
|
||||||
VISITED_ASSIGNABLE_FROM, VISITED_ASSIGNABLE_TO
|
VISITED_ASSIGNABLE_FROM, VISITED_ASSIGNABLE_TO
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,8 @@ public class SourceMethod implements Method {
|
|||||||
private final Type declaringMapper;
|
private final Type declaringMapper;
|
||||||
private final ExecutableElement executable;
|
private final ExecutableElement executable;
|
||||||
private final List<Parameter> parameters;
|
private final List<Parameter> parameters;
|
||||||
private final Parameter targetParameter;
|
private final Parameter mappingTargetParameter;
|
||||||
|
private final Parameter targetTypeParameter;
|
||||||
private final Type returnType;
|
private final Type returnType;
|
||||||
private final Accessibility accessibility;
|
private final Accessibility accessibility;
|
||||||
private final List<Type> exceptionTypes;
|
private final List<Type> exceptionTypes;
|
||||||
@ -185,7 +186,8 @@ public class SourceMethod implements Method {
|
|||||||
this.mapMapping = mapMapping;
|
this.mapMapping = mapMapping;
|
||||||
this.accessibility = Accessibility.fromModifiers( executable.getModifiers() );
|
this.accessibility = Accessibility.fromModifiers( executable.getModifiers() );
|
||||||
|
|
||||||
this.targetParameter = determineTargetParameter( parameters );
|
this.mappingTargetParameter = determineMappingTargetParameter( parameters );
|
||||||
|
this.targetTypeParameter = determineTargetTypeParameter( parameters );
|
||||||
|
|
||||||
this.typeUtils = typeUtils;
|
this.typeUtils = typeUtils;
|
||||||
this.typeFactory = typeFactory;
|
this.typeFactory = typeFactory;
|
||||||
@ -193,7 +195,7 @@ public class SourceMethod implements Method {
|
|||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Parameter determineTargetParameter(Iterable<Parameter> parameters) {
|
private Parameter determineMappingTargetParameter(Iterable<Parameter> parameters) {
|
||||||
for ( Parameter parameter : parameters ) {
|
for ( Parameter parameter : parameters ) {
|
||||||
if ( parameter.isMappingTarget() ) {
|
if ( parameter.isMappingTarget() ) {
|
||||||
return parameter;
|
return parameter;
|
||||||
@ -203,6 +205,16 @@ public class SourceMethod implements Method {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Parameter determineTargetTypeParameter(Iterable<Parameter> parameters) {
|
||||||
|
for ( Parameter parameter : parameters ) {
|
||||||
|
if ( parameter.isTargetType() ) {
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc} {@link Method}
|
* {@inheritDoc} {@link Method}
|
||||||
*/
|
*/
|
||||||
@ -261,7 +273,7 @@ public class SourceMethod implements Method {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getResultType() {
|
public Type getResultType() {
|
||||||
return targetParameter != null ? targetParameter.getType() : returnType;
|
return mappingTargetParameter != null ? mappingTargetParameter.getType() : returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,12 +369,14 @@ public class SourceMethod implements Method {
|
|||||||
return equals( getResultType(), method.getResultType() );
|
return equals( getResultType(), method.getResultType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc} {@link Method}
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter getTargetParameter() {
|
public Parameter getMappingTargetParameter() {
|
||||||
return targetParameter;
|
return mappingTargetParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Parameter getTargetTypeParameter() {
|
||||||
|
return targetTypeParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIterableMapping() {
|
public boolean isIterableMapping() {
|
||||||
@ -455,9 +469,9 @@ public class SourceMethod implements Method {
|
|||||||
* {@inheritDoc} {@link Method}
|
* {@inheritDoc} {@link Method}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(List<Type> sourceTypes, Type targetType) {
|
public boolean matches(Type sourceType, Type targetType) {
|
||||||
MethodMatcher matcher = new MethodMatcher( typeUtils, this );
|
MethodMatcher matcher = new MethodMatcher( typeUtils, typeFactory, this );
|
||||||
return matcher.matches( sourceTypes, targetType );
|
return matcher.matches( sourceType, targetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,11 +71,7 @@ public abstract class BuiltInMethod implements Method {
|
|||||||
* excluding generic type variables. When the implementor sees a need for this, this method can be overridden.
|
* excluding generic type variables. When the implementor sees a need for this, this method can be overridden.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(List<Type> sourceTypes, Type targetType) {
|
public boolean matches(Type sourceType, Type targetType) {
|
||||||
if ( sourceTypes.size() > 1 ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Type sourceType = sourceTypes.iterator().next();
|
|
||||||
|
|
||||||
if ( getReturnType().isAssignableTo( targetType.erasure() )
|
if ( getReturnType().isAssignableTo( targetType.erasure() )
|
||||||
&& sourceType.erasure().isAssignableTo( getParameter().getType() ) ) {
|
&& sourceType.erasure().isAssignableTo( getParameter().getType() ) ) {
|
||||||
@ -118,12 +114,22 @@ public abstract class BuiltInMethod implements Method {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* target parameter mechanism not supported for built-in methods
|
* mapping target parameter mechanism not supported for built-in methods
|
||||||
*
|
*
|
||||||
* @return {@code null}
|
* @return {@code null}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Parameter getTargetParameter() {
|
public Parameter getMappingTargetParameter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* target type parameter mechanism not supported for built-in methods
|
||||||
|
*
|
||||||
|
* @return {@code null}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Parameter getTargetTypeParameter() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 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.model.source.selector;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
import org.mapstruct.ap.model.source.Method;
|
||||||
|
import org.mapstruct.ap.model.source.MethodMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects only create method candidates (so methods not containing {@link @MappingTarget} )
|
||||||
|
* {@link MethodMatcher}).
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class CreateOrUpdateSelector implements MethodSelector {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
||||||
|
Type sourceType, Type targetType,
|
||||||
|
SelectionCriteria criteria) {
|
||||||
|
|
||||||
|
List<T> createCandidates = new ArrayList<T>();
|
||||||
|
for ( T method : methods ) {
|
||||||
|
boolean isCreateCandidate = method.getMappingTargetParameter() == null;
|
||||||
|
if ( isCreateCandidate ) {
|
||||||
|
createCandidates.add( method );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createCandidates;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,6 @@ import java.util.List;
|
|||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.Parameter;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.model.common.TypeFactory;
|
import org.mapstruct.ap.model.common.TypeFactory;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
@ -41,11 +40,12 @@ public class MethodSelectors implements MethodSelector {
|
|||||||
public MethodSelectors(Types typeUtils, Elements elementUtils, TypeFactory typeFactory) {
|
public MethodSelectors(Types typeUtils, Elements elementUtils, TypeFactory typeFactory) {
|
||||||
selectors =
|
selectors =
|
||||||
Arrays.<MethodSelector>asList(
|
Arrays.<MethodSelector>asList(
|
||||||
new TypeSelector( typeFactory ),
|
new TypeSelector(),
|
||||||
new QualifierSelector( typeUtils, elementUtils ),
|
new QualifierSelector( typeUtils, elementUtils ),
|
||||||
new TargetTypeSelector( typeUtils, elementUtils ),
|
new TargetTypeSelector( typeUtils, elementUtils ),
|
||||||
new XmlElementDeclSelector( typeUtils ),
|
new XmlElementDeclSelector( typeUtils ),
|
||||||
new InheritanceSelector()
|
new InheritanceSelector(),
|
||||||
|
new CreateOrUpdateSelector()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,30 +67,4 @@ public class MethodSelectors implements MethodSelector {
|
|||||||
}
|
}
|
||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param typeFactory the type factory to use
|
|
||||||
* @param parameters the parameters to map the types for
|
|
||||||
* @param sourceType the source type
|
|
||||||
* @param returnType the return type
|
|
||||||
*
|
|
||||||
* @return the list of actual parameter types
|
|
||||||
*/
|
|
||||||
public static List<Type> getParameterTypes(TypeFactory typeFactory, List<Parameter> parameters, Type sourceType,
|
|
||||||
Type returnType) {
|
|
||||||
List<Type> result = new ArrayList<Type>();
|
|
||||||
for ( Parameter param : parameters ) {
|
|
||||||
if ( param.isTargetType() ) {
|
|
||||||
result.add( typeFactory.classTypeOf( returnType ) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( sourceType != null ) {
|
|
||||||
/* for factory methods (sourceType==null), no parameter must be added */
|
|
||||||
result.add( sourceType );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.model.common.TypeFactory;
|
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
import org.mapstruct.ap.model.source.MethodMatcher;
|
import org.mapstruct.ap.model.source.MethodMatcher;
|
||||||
|
|
||||||
@ -34,12 +33,6 @@ import org.mapstruct.ap.model.source.MethodMatcher;
|
|||||||
*/
|
*/
|
||||||
public class TypeSelector implements MethodSelector {
|
public class TypeSelector implements MethodSelector {
|
||||||
|
|
||||||
private final TypeFactory typeFactory;
|
|
||||||
|
|
||||||
public TypeSelector(TypeFactory typeFactory) {
|
|
||||||
this.typeFactory = typeFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
public <T extends Method> List<T> getMatchingMethods(Method mappingMethod, List<T> methods,
|
||||||
Type sourceType, Type targetType,
|
Type sourceType, Type targetType,
|
||||||
@ -47,13 +40,7 @@ public class TypeSelector implements MethodSelector {
|
|||||||
|
|
||||||
List<T> result = new ArrayList<T>();
|
List<T> result = new ArrayList<T>();
|
||||||
for ( T method : methods ) {
|
for ( T method : methods ) {
|
||||||
if ( method.getSourceParameters().size() > 1 ) {
|
if ( method.matches( sourceType, targetType ) ) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Type> parameterTypes =
|
|
||||||
MethodSelectors.getParameterTypes( typeFactory, method.getParameters(), sourceType, targetType );
|
|
||||||
if ( method.matches( parameterTypes, targetType ) ) {
|
|
||||||
result.add( method );
|
result.add( method );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
.setReturnType( returnType )
|
.setReturnType( returnType )
|
||||||
.setExceptionTypes( exceptionTypes )
|
.setExceptionTypes( exceptionTypes )
|
||||||
.setTypeUtils( typeUtils )
|
.setTypeUtils( typeUtils )
|
||||||
|
.setTypeFactory( typeFactory )
|
||||||
.createSourceMethod();
|
.createSourceMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,9 +444,19 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCandidateForMapping(Method methodCandidate) {
|
private boolean isCandidateForMapping(Method methodCandidate) {
|
||||||
|
return isCreateMethodForMapping( methodCandidate ) || isUpdateMethodForMapping( methodCandidate );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCreateMethodForMapping(Method methodCandidate) {
|
||||||
|
// a create method may not return void and has no target parameter
|
||||||
return methodCandidate.getSourceParameters().size() == 1 && !methodCandidate.getReturnType().isVoid()
|
return methodCandidate.getSourceParameters().size() == 1 && !methodCandidate.getReturnType().isVoid()
|
||||||
&& methodCandidate.getTargetParameter() == null; // @MappingTarget is not yet supported for property
|
&& methodCandidate.getMappingTargetParameter() == null;
|
||||||
// mappings
|
}
|
||||||
|
|
||||||
|
private boolean isUpdateMethodForMapping(Method methodCandidate) {
|
||||||
|
// an update method may, or may not return void and has a target parameter
|
||||||
|
return methodCandidate.getSourceParameters().size() == 1
|
||||||
|
&& methodCandidate.getMappingTargetParameter() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Method> T getBestMatch(List<T> methods, Type sourceType, Type returnType) {
|
private <T extends Method> T getBestMatch(List<T> methods, Type sourceType, Type returnType) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user