This commit is contained in:
Gunnar Morling 2014-10-12 18:24:17 +02:00
parent 9adbb423c6
commit a5dc5d78ab
5 changed files with 282 additions and 264 deletions

View File

@ -27,8 +27,8 @@ import java.util.Map;
import java.util.Set;
import javax.lang.model.element.ExecutableElement;
import javax.tools.Diagnostic;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.source.Mapping;
@ -54,7 +54,7 @@ public class BeanMappingMethod extends MappingMethod {
private final FactoryMethod factoryMethod;
public static class Builder {
public static class Builder {
private MappingContext ctx;
private SourceMethod method;
@ -64,7 +64,7 @@ public class BeanMappingMethod extends MappingMethod {
return this;
}
public Builder souceMethod( SourceMethod sourceMethod ) {
public Builder souceMethod(SourceMethod sourceMethod) {
this.method = sourceMethod;
return this;
}
@ -103,7 +103,7 @@ public class BeanMappingMethod extends MappingMethod {
// the current target accessor can also be a getter method.
// The following if block, checks if the target accessor should be overruled by an add method.
if ( cmStrategy.equals( CollectionMappingStrategy.SETTER_PREFERRED )
|| cmStrategy.equals( CollectionMappingStrategy.ADDER_PREFERRED ) ) {
|| cmStrategy.equals( CollectionMappingStrategy.ADDER_PREFERRED ) ) {
// first check if there's a setter method.
ExecutableElement adderMethod = null;
@ -115,7 +115,7 @@ public class BeanMappingMethod extends MappingMethod {
}
}
else if ( Executables.isGetterMethod( targetAccessor ) ) {
// the current accessor is a getter (no setter available). But still, an add method is according
// the current accessor is a getter (no setter available). But still, an add method is according
// to the above strategy (SETTER_PREFERRED || ADDER_PREFERRED) preferred over the getter.
Type targetType = ctx.getTypeFactory().getReturnType( targetAccessor );
adderMethod = method.getResultType().getAdderForType( targetType, targetPropertyName );
@ -135,41 +135,41 @@ public class BeanMappingMethod extends MappingMethod {
PropertyMapping.PropertyMappingBuilder builder = new PropertyMapping.PropertyMappingBuilder();
propertyMapping = builder
.mappingContext( ctx )
.souceMethod( method )
.targetAccessor( targetAccessor )
.targetPropertyName( targetPropertyName )
.parameter( parameter )
.build();
.mappingContext( ctx )
.souceMethod( method )
.targetAccessor( targetAccessor )
.targetPropertyName( targetPropertyName )
.parameter( parameter )
.build();
}
else if ( Executables.isSetterMethod( targetAccessor )
|| Executables.isGetterMethod( targetAccessor ) ) {
|| Executables.isGetterMethod( targetAccessor ) ) {
if ( !mapping.getConstant().isEmpty() ) {
// its a constant
PropertyMapping.ConstantMappingBuilder builder =
new PropertyMapping.ConstantMappingBuilder();
new PropertyMapping.ConstantMappingBuilder();
propertyMapping = builder
.mappingContext( ctx )
.sourceMethod( method )
.constantExpression( "\"" + mapping.getConstant() + "\"" )
.targetAccessor( targetAccessor )
.dateFormat( mapping.getDateFormat() )
.qualifiers( mapping.getQualifiers() )
.build();
.mappingContext( ctx )
.sourceMethod( method )
.constantExpression( "\"" + mapping.getConstant() + "\"" )
.targetAccessor( targetAccessor )
.dateFormat( mapping.getDateFormat() )
.qualifiers( mapping.getQualifiers() )
.build();
}
else if ( !mapping.getJavaExpression().isEmpty() ) {
// its an expression
PropertyMapping.JavaExpressionMappingBuilder builder =
new PropertyMapping.JavaExpressionMappingBuilder();
new PropertyMapping.JavaExpressionMappingBuilder();
propertyMapping = builder
.mappingContext( ctx )
.souceMethod( method )
.javaExpression( mapping.getJavaExpression() )
.targetAccessor( targetAccessor )
.build();
.mappingContext( ctx )
.souceMethod( method )
.javaExpression( mapping.getJavaExpression() )
.targetAccessor( targetAccessor )
.build();
}
}
}
@ -178,19 +178,19 @@ public class BeanMappingMethod extends MappingMethod {
for ( Parameter sourceParameter : method.getSourceParameters() ) {
PropertyMapping.PropertyMappingBuilder builder = new PropertyMapping.PropertyMappingBuilder();
PropertyMapping newPropertyMapping = builder
.mappingContext( ctx )
.souceMethod( method )
.targetAccessor( targetAccessor )
.targetPropertyName( targetPropertyName )
.parameter( sourceParameter )
.build();
.mappingContext( ctx )
.souceMethod( method )
.targetAccessor( targetAccessor )
.targetPropertyName( targetPropertyName )
.parameter( sourceParameter )
.build();
if ( propertyMapping != null && newPropertyMapping != null ) {
ctx.getMessager().printMessage(
Diagnostic.Kind.ERROR,
"Several possible source properties for target property \"" + targetPropertyName +
"\".",
method.getExecutable()
Diagnostic.Kind.ERROR,
"Several possible source properties for target property \"" + targetPropertyName +
"\".",
method.getExecutable()
);
break;
}
@ -209,11 +209,11 @@ public class BeanMappingMethod extends MappingMethod {
Set<String> targetProperties = Executables.getPropertyNames( targetAccessors );
reportErrorForUnmappedTargetPropertiesIfRequired(
method,
unmappedTargetPolicy,
targetProperties,
mappedTargetProperties,
ignoredTargetProperties
method,
unmappedTargetPolicy,
targetProperties,
mappedTargetProperties,
ignoredTargetProperties
);
FactoryMethod factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
return new BeanMappingMethod( method, propertyMappings, factoryMethod );
@ -235,7 +235,7 @@ public class BeanMappingMethod extends MappingMethod {
ReportingPolicy annotationValue = ReportingPolicy.valueOf( mapperSettings.unmappedTargetPolicy() );
if ( setViaAnnotation
|| ctx.getOptions().getUnmappedTargetPolicy() == null ) {
|| ctx.getOptions().getUnmappedTargetPolicy() == null ) {
return annotationValue;
}
else {
@ -271,34 +271,34 @@ public class BeanMappingMethod extends MappingMethod {
if ( mappedProperty.getSourceParameterName() != null ) {
Parameter sourceParameter = method.getSourceParameter(
mappedProperty.getSourceParameterName()
mappedProperty.getSourceParameterName()
);
if ( sourceParameter == null ) {
ctx.getMessager().printMessage(
Diagnostic.Kind.ERROR,
String.format(
"Method has no parameter named \"%s\".",
mappedProperty.getSourceParameterName()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getSourceAnnotationValue()
Diagnostic.Kind.ERROR,
String.format(
"Method has no parameter named \"%s\".",
mappedProperty.getSourceParameterName()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getSourceAnnotationValue()
);
foundUnmappedProperty = true;
}
else {
if ( !hasSourceProperty( sourceParameter, mappedProperty.getSourcePropertyName() ) ) {
ctx.getMessager().printMessage(
Diagnostic.Kind.ERROR,
String.format(
"The type of parameter \"%s\" has no property named \"%s\".",
mappedProperty.getSourceParameterName(),
mappedProperty.getSourcePropertyName()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getSourceAnnotationValue()
Diagnostic.Kind.ERROR,
String.format(
"The type of parameter \"%s\" has no property named \"%s\".",
mappedProperty.getSourceParameterName(),
mappedProperty.getSourcePropertyName()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getSourceAnnotationValue()
);
foundUnmappedProperty = true;
}
@ -306,31 +306,31 @@ public class BeanMappingMethod extends MappingMethod {
}
else if ( mappedProperty.getConstant().isEmpty()
&& mappedProperty.getJavaExpression().isEmpty()
&& !hasSourceProperty( mappedProperty.getSourcePropertyName() ) ) {
&& mappedProperty.getJavaExpression().isEmpty()
&& !hasSourceProperty( mappedProperty.getSourcePropertyName() ) ) {
ctx.getMessager().printMessage(
Diagnostic.Kind.ERROR,
String.format(
"No property named \"%s\" exists in source parameter(s).",
mappedProperty.getSourceName()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getSourceAnnotationValue()
Diagnostic.Kind.ERROR,
String.format(
"No property named \"%s\" exists in source parameter(s).",
mappedProperty.getSourceName()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getSourceAnnotationValue()
);
foundUnmappedProperty = true;
}
if ( !targetProperties.contains( mappedProperty.getTargetName() ) ) {
ctx.getMessager().printMessage(
Diagnostic.Kind.ERROR,
String.format(
"Unknown property \"%s\" in return type %s.",
mappedProperty.getTargetName(),
method.getResultType()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getTargetAnnotationValue()
Diagnostic.Kind.ERROR,
String.format(
"Unknown property \"%s\" in return type %s.",
mappedProperty.getTargetName(),
method.getResultType()
),
method.getExecutable(),
mappedProperty.getMirror(),
mappedProperty.getTargetAnnotationValue()
);
foundUnmappedProperty = true;
}
@ -339,11 +339,11 @@ public class BeanMappingMethod extends MappingMethod {
return !foundUnmappedProperty;
}
private void reportErrorForUnmappedTargetPropertiesIfRequired( SourceMethod method,
ReportingPolicy unmappedTargetPolicy,
Set<String> targetProperties,
Set<String> mappedTargetProperties,
Set<String> ignoredTargetProperties ) {
private void reportErrorForUnmappedTargetPropertiesIfRequired(SourceMethod method,
ReportingPolicy unmappedTargetPolicy,
Set<String> targetProperties,
Set<String> mappedTargetProperties,
Set<String> ignoredTargetProperties) {
Set<String> unmappedTargetProperties = new HashSet<String>();
@ -355,18 +355,18 @@ public class BeanMappingMethod extends MappingMethod {
if ( !unmappedTargetProperties.isEmpty() && unmappedTargetPolicy.requiresReport() ) {
ctx.getMessager().printMessage(
unmappedTargetPolicy.getDiagnosticKind(),
MessageFormat.format(
"Unmapped target {0,choice,1#property|1<properties}: \"{1}\"",
unmappedTargetProperties.size(),
Strings.join( unmappedTargetProperties, ", " )
),
method.getExecutable()
unmappedTargetPolicy.getDiagnosticKind(),
MessageFormat.format(
"Unmapped target {0,choice,1#property|1<properties}: \"{1}\"",
unmappedTargetProperties.size(),
Strings.join( unmappedTargetProperties, ", " )
),
method.getExecutable()
);
}
}
private boolean hasSourceProperty( String propertyName ) {
private boolean hasSourceProperty(String propertyName) {
for ( Parameter parameter : method.getSourceParameters() ) {
if ( hasSourceProperty( parameter, propertyName ) ) {
return true;
@ -376,7 +376,7 @@ public class BeanMappingMethod extends MappingMethod {
return false;
}
private boolean hasSourceProperty( Parameter parameter, String propertyName ) {
private boolean hasSourceProperty(Parameter parameter, String propertyName) {
List<ExecutableElement> getters = parameter.getType().getGetters();
return Executables.getPropertyNames( getters ).contains( propertyName );
}
@ -384,8 +384,8 @@ public class BeanMappingMethod extends MappingMethod {
}
private BeanMappingMethod(SourceMethod method,
List<PropertyMapping> propertyMappings,
FactoryMethod factoryMethod) {
List<PropertyMapping> propertyMappings,
FactoryMethod factoryMethod) {
super( method );
this.propertyMappings = propertyMappings;

View File

@ -18,11 +18,12 @@
*/
package org.mapstruct.ap.model;
import org.mapstruct.ap.model.assignment.Assignment;
import java.util.List;
import java.util.Set;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.mapstruct.ap.model.assignment.Assignment;
import org.mapstruct.ap.model.assignment.SetterWrapper;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
@ -41,57 +42,58 @@ public class IterableMappingMethod extends MappingMethod {
private final FactoryMethod factoryMethod;
private final boolean overridden;
public static class Builder {
public static class Builder {
private Method method;
private MappingContext ctx;
private String dateFormat;
private List<TypeMirror> qualifiers;
public Builder mappingContext( MappingContext mappingContext ) {
public Builder mappingContext(MappingContext mappingContext) {
this.ctx = mappingContext;
return this;
}
public Builder method( Method sourceMethod ) {
public Builder method(Method sourceMethod) {
this.method = sourceMethod;
return this;
}
public Builder dateFormat( String dateFormat ) {
public Builder dateFormat(String dateFormat) {
this.dateFormat = dateFormat;
return this;
}
public Builder qualifiers( List<TypeMirror> qualifiers ) {
public Builder qualifiers(List<TypeMirror> qualifiers) {
this.qualifiers = qualifiers;
return this;
}
public IterableMappingMethod build( ) {
public IterableMappingMethod build() {
Type sourceElementType =
method.getSourceParameters().iterator().next().getType().getTypeParameters().get( 0 );
method.getSourceParameters().iterator().next().getType().getTypeParameters().get( 0 );
Type targetElementType =
method.getResultType().getTypeParameters().get( 0 );
method.getResultType().getTypeParameters().get( 0 );
String conversionStr =
Strings.getSaveVariableName( sourceElementType.getName(), method.getParameterNames() );
Strings.getSaveVariableName( sourceElementType.getName(), method.getParameterNames() );
Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method,
"collection element",
sourceElementType,
targetElementType,
null, // there is no targetPropertyName
dateFormat,
qualifiers,
conversionStr
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
method,
"collection element",
sourceElementType,
targetElementType,
null, // there is no targetPropertyName
dateFormat,
qualifiers,
conversionStr
);
if ( assignment == null ) {
String message = String.format(
"Can't create implementation of method %s. Found no method nor built-in conversion for mapping "
"Can't create implementation of method %s. Found no method nor built-in conversion for mapping "
+ "source element type into target element type.",
method
method
);
method.printMessage( ctx.getMessager(), Diagnostic.Kind.ERROR, message );
}
@ -169,7 +171,7 @@ public class IterableMappingMethod extends MappingMethod {
}
IterableMappingMethod other = (IterableMappingMethod) obj;
if ( !getResultType().equals( other.getResultType() ) ) {
if ( !getResultType().equals( other.getResultType() ) ) {
return false;
}
@ -177,9 +179,9 @@ public class IterableMappingMethod extends MappingMethod {
return false;
}
for (int i = 0; i < getSourceParameters().size(); i++ ) {
for ( int i = 0; i < getSourceParameters().size(); i++ ) {
if ( !getSourceParameters().get( i ).getType().getTypeParameters().get( 0 )
.equals( other.getSourceParameters().get( i ).getType().getTypeParameters().get( 0 ) ) ) {
.equals( other.getSourceParameters().get( i ).getType().getTypeParameters().get( 0 ) ) ) {
return false;
}
}

View File

@ -18,11 +18,12 @@
*/
package org.mapstruct.ap.model;
import org.mapstruct.ap.model.assignment.Assignment;
import java.util.List;
import java.util.Set;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.mapstruct.ap.model.assignment.Assignment;
import org.mapstruct.ap.model.assignment.LocalVarWrapper;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
@ -42,7 +43,7 @@ public class MapMappingMethod extends MappingMethod {
private final FactoryMethod factoryMethod;
private final boolean overridden;
public static class Builder {
public static class Builder {
private String keyDateFormat;
private String valueDateFormat;
@ -51,32 +52,32 @@ public class MapMappingMethod extends MappingMethod {
private Method method;
private MappingContext ctx;
public Builder mappingContext( MappingContext mappingContext ) {
public Builder mappingContext(MappingContext mappingContext) {
this.ctx = mappingContext;
return this;
}
public Builder method( Method sourceMethod ) {
public Builder method(Method sourceMethod) {
this.method = sourceMethod;
return this;
}
public Builder keyDateFormat( String keyDateFormat ) {
public Builder keyDateFormat(String keyDateFormat) {
this.keyDateFormat = keyDateFormat;
return this;
}
public Builder valueDateFormat( String valueDateFormat ) {
public Builder valueDateFormat(String valueDateFormat) {
this.valueDateFormat = valueDateFormat;
return this;
}
public Builder keyQualifiers( List<TypeMirror> keyQualifiers ) {
public Builder keyQualifiers(List<TypeMirror> keyQualifiers) {
this.keyQualifiers = keyQualifiers;
return this;
}
public Builder valueQualifiers( List<TypeMirror> valueQualifiers ) {
public Builder valueQualifiers(List<TypeMirror> valueQualifiers) {
this.valueQualifiers = valueQualifiers;
return this;
}
@ -90,19 +91,22 @@ public class MapMappingMethod extends MappingMethod {
Type keySourceType = sourceTypeParams.get( 0 );
Type keyTargetType = resultTypeParams.get( 0 );
Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment( method,
"map key",
keySourceType,
keyTargetType,
null, // there is no targetPropertyName
keyDateFormat,
keyQualifiers,
"entry.getKey()"
Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment(
method,
"map key",
keySourceType,
keyTargetType,
null, // there is no targetPropertyName
keyDateFormat,
keyQualifiers,
"entry.getKey()"
);
if ( keyAssignment == null ) {
String message = String.format( "Can't create implementation of method %s. Found no method nor "
+ "built-in conversion for mapping source key type to target key type.", method );
String message = String.format(
"Can't create implementation of method %s. Found no method nor "
+ "built-in conversion for mapping source key type to target key type.", method
);
method.printMessage( ctx.getMessager(), Diagnostic.Kind.ERROR, message );
}
@ -110,19 +114,22 @@ public class MapMappingMethod extends MappingMethod {
Type valueSourceType = sourceTypeParams.get( 1 );
Type valueTargetType = resultTypeParams.get( 1 );
Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment( method,
"map value",
valueSourceType,
valueTargetType,
null, // there is no targetPropertyName
valueDateFormat,
valueQualifiers,
"entry.getValue()"
Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment(
method,
"map value",
valueSourceType,
valueTargetType,
null, // there is no targetPropertyName
valueDateFormat,
valueQualifiers,
"entry.getValue()"
);
if ( valueAssignment == null ) {
String message = String.format( "Can't create implementation of method %s. Found no method nor "
+ "built-in conversion for mapping source value type to target value type.", method );
String message = String.format(
"Can't create implementation of method %s. Found no method nor "
+ "built-in conversion for mapping source value type to target value type.", method
);
method.printMessage( ctx.getMessager(), Diagnostic.Kind.ERROR, message );
}
@ -137,7 +144,7 @@ public class MapMappingMethod extends MappingMethod {
}
private MapMappingMethod(Method method, Assignment keyAssignment, Assignment valueAssignment,
FactoryMethod factoryMethod) {
FactoryMethod factoryMethod) {
super( method );
this.keyAssignment = keyAssignment;
@ -232,9 +239,9 @@ public class MapMappingMethod extends MappingMethod {
return false;
}
for (int i = 0; i < getSourceParameters().size(); i++ ) {
for ( int i = 0; i < getSourceParameters().size(); i++ ) {
if ( !getSourceParameters().get( i ).getType().getTypeParameters().get( 0 )
.equals( other.getSourceParameters().get( i ).getType().getTypeParameters().get( 0 ) ) ) {
.equals( other.getSourceParameters().get( i ).getType().getTypeParameters().get( 0 ) ) ) {
return false;
}
}

View File

@ -25,7 +25,6 @@ import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.annotation.processing.Messager;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
@ -70,7 +69,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
private Messager messager;
private Options options;
private TypeFactory typeFactory;
private MappingContext mappingContext;
private MappingContext mappingContext;
@Override
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<SourceMethod> sourceModel) {
@ -82,16 +81,23 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
List<MapperReference> mapperReferences = initReferencedMappers( mapperTypeElement );
MappingContext ctx = new MappingContext(
typeFactory,
MappingContext ctx = new MappingContext(
typeFactory,
elementUtils,
typeUtils,
messager,
options,
new MappingResolverImpl(
context.getMessager(),
elementUtils,
typeUtils,
messager,
options,
new MappingResolverImpl( context.getMessager(), elementUtils, typeUtils, typeFactory, sourceModel, mapperReferences ),
mapperTypeElement,
typeFactory,
sourceModel,
mapperReferences
),
mapperTypeElement,
sourceModel,
mapperReferences
);
this.mappingContext = ctx;
return getMapper( mapperTypeElement, sourceModel );
@ -232,7 +238,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
return extraImports;
}
private List<MappingMethod> getMappingMethods(List<SourceMethod> methods ) {
private List<MappingMethod> getMappingMethods(List<SourceMethod> methods) {
List<MappingMethod> mappingMethods = new ArrayList<MappingMethod>();
for ( SourceMethod method : methods ) {
@ -245,7 +251,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
boolean hasFactoryMethod = false;
if ( method.isIterableMapping() ) {
IterableMappingMethod.Builder builder = new IterableMappingMethod.Builder( );
IterableMappingMethod.Builder builder = new IterableMappingMethod.Builder();
if ( method.getIterableMapping() == null && reverseMappingMethod != null &&
reverseMappingMethod.getIterableMapping() != null ) {
method.setIterableMapping( reverseMappingMethod.getIterableMapping() );
@ -259,18 +265,18 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
IterableMappingMethod iterableMappingMethod = builder
.mappingContext( mappingContext )
.method( method )
.dateFormat( dateFormat )
.qualifiers( qualifiers )
.build();
.mappingContext( mappingContext )
.method( method )
.dateFormat( dateFormat )
.qualifiers( qualifiers )
.build();
hasFactoryMethod = iterableMappingMethod.getFactoryMethod() != null;
mappingMethods.add( iterableMappingMethod );
}
else if ( method.isMapMapping() ) {
MapMappingMethod.Builder builder = new MapMappingMethod.Builder( );
MapMappingMethod.Builder builder = new MapMappingMethod.Builder();
if ( method.getMapMapping() == null && reverseMappingMethod != null &&
reverseMappingMethod.getMapMapping() != null ) {
@ -288,13 +294,13 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
MapMappingMethod mapMappingMethod = builder
.mappingContext( mappingContext )
.method( method )
.keyDateFormat( keyDateFormat )
.valueDateFormat( valueDateFormat )
.keyQualifiers( keyQualifiers )
.valueQualifiers( valueQualifiers )
.build();
.mappingContext( mappingContext )
.method( method )
.keyDateFormat( keyDateFormat )
.valueDateFormat( valueDateFormat )
.keyQualifiers( keyQualifiers )
.valueQualifiers( valueQualifiers )
.build();
hasFactoryMethod = mapMappingMethod.getFactoryMethod() != null;
mappingMethods.add( mapMappingMethod );
@ -310,9 +316,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
MappingMethod enumMappingMethod = builder
.mappingContext( mappingContext )
.souceMethod( method )
.build();
.mappingContext( mappingContext )
.souceMethod( method )
.build();
if ( enumMappingMethod != null ) {
mappingMethods.add( enumMappingMethod );
@ -320,7 +326,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
else {
BeanMappingMethod.Builder builder = new BeanMappingMethod.Builder( );
BeanMappingMethod.Builder builder = new BeanMappingMethod.Builder();
if ( method.getMappings().isEmpty() ) {
if ( reverseMappingMethod != null && !reverseMappingMethod.getMappings().isEmpty() ) {
@ -329,9 +335,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
BeanMappingMethod beanMappingMethod = builder
.mappingContext( mappingContext )
.souceMethod( method )
.build();
.mappingContext( mappingContext )
.souceMethod( method )
.build();
if ( beanMappingMethod != null ) {
hasFactoryMethod = beanMappingMethod.getFactoryMethod() != null;

View File

@ -22,7 +22,6 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.Messager;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
@ -74,7 +73,8 @@ public class MappingResolverImpl implements MappingResolver {
*/
private final Set<VirtualMappingMethod> usedVirtualMappings = new HashSet<VirtualMappingMethod>();
public MappingResolverImpl(Messager messager, Elements elementUtils, Types typeUtils, TypeFactory typeFactory, List<SourceMethod> sourceModel, List<MapperReference> mapperReferences) {
public MappingResolverImpl(Messager messager, Elements elementUtils, Types typeUtils, TypeFactory typeFactory,
List<SourceMethod> sourceModel, List<MapperReference> mapperReferences) {
this.messager = messager;
this.typeUtils = typeUtils;
this.typeFactory = typeFactory;
@ -85,9 +85,9 @@ public class MappingResolverImpl implements MappingResolver {
this.conversions = new Conversions( elementUtils, typeFactory );
this.builtInMethods = new BuiltInMappingMethods( typeFactory );
this.methodSelectors = new MethodSelectors(
typeUtils,
elementUtils,
typeFactory
typeUtils,
elementUtils,
typeFactory
);
}
@ -113,23 +113,24 @@ public class MappingResolverImpl implements MappingResolver {
*/
@Override
public Assignment getTargetAssignment(
Method mappingMethod,
String mappedElement,
Type sourceType,
Type targetType,
String targetPropertyName,
String dateFormat,
List<TypeMirror> qualifiers,
String sourceReference ) {
Method mappingMethod,
String mappedElement,
Type sourceType,
Type targetType,
String targetPropertyName,
String dateFormat,
List<TypeMirror> qualifiers,
String sourceReference) {
ResolvingAttempt attempt = new ResolvingAttempt( sourceModel,
mapperReferences,
mappingMethod,
mappedElement,
targetPropertyName,
dateFormat,
qualifiers,
sourceReference
ResolvingAttempt attempt = new ResolvingAttempt(
sourceModel,
mapperReferences,
mappingMethod,
mappedElement,
targetPropertyName,
dateFormat,
qualifiers,
sourceReference
);
return attempt.getTargetAssignment( sourceType, targetType );
@ -155,14 +156,14 @@ public class MappingResolverImpl implements MappingResolver {
// so this set must be cleared.
private final Set<VirtualMappingMethod> virtualMethodCandidates;
private ResolvingAttempt( List<SourceMethod> sourceModel,
List<MapperReference> mapperReferences,
Method mappingMethod,
String mappedElement,
String targetPropertyName,
String dateFormat,
List<TypeMirror> qualifiers,
String sourceReference ) {
private ResolvingAttempt(List<SourceMethod> sourceModel,
List<MapperReference> mapperReferences,
Method mappingMethod,
String mappedElement,
String targetPropertyName,
String dateFormat,
List<TypeMirror> qualifiers,
String sourceReference) {
this.mappingMethod = mappingMethod;
this.mappedElement = mappedElement;
this.methods = sourceModel;
@ -173,7 +174,7 @@ public class MappingResolverImpl implements MappingResolver {
this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>();
}
private Assignment getTargetAssignment( Type sourceType, Type targetType ) {
private Assignment getTargetAssignment(Type sourceType, Type targetType) {
// first simple mapping method
Assignment referencedMethod = resolveViaMethod( sourceType, targetType );
@ -192,7 +193,7 @@ public class MappingResolverImpl implements MappingResolver {
// then type conversion
Assignment conversion = resolveViaConversion( sourceType, targetType );
if ( conversion != null ) {
conversion.setAssignment( AssignmentFactory.createSimple( sourceReference) );
conversion.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
return conversion;
}
@ -221,7 +222,7 @@ public class MappingResolverImpl implements MappingResolver {
return null;
}
private Assignment resolveViaConversion( Type sourceType, Type targetType ) {
private Assignment resolveViaConversion(Type sourceType, Type targetType) {
ConversionProvider conversionProvider = conversions.getConversion( sourceType, targetType );
if ( conversionProvider == null ) {
@ -229,16 +230,15 @@ public class MappingResolverImpl implements MappingResolver {
}
ConversionContext ctx =
new DefaultConversionContext( typeFactory, targetType, dateFormat );
new DefaultConversionContext( typeFactory, targetType, dateFormat );
return conversionProvider.to( ctx );
}
/**
* Returns a reference to a method mapping the given source type to the given target type, if such a method
* exists.
*
*/
private Assignment resolveViaMethod( Type sourceType, Type targetType ) {
private Assignment resolveViaMethod(Type sourceType, Type targetType) {
// first try to find a matching source method
SourceMethod matchingSourceMethod = getBestMatch( methods, sourceType, targetType );
@ -249,13 +249,13 @@ public class MappingResolverImpl implements MappingResolver {
// then a matching built-in method
BuiltInMethod matchingBuiltInMethod =
getBestMatch( builtInMethods.getBuiltInMethods(), sourceType, targetType );
getBestMatch( builtInMethods.getBuiltInMethods(), sourceType, targetType );
if ( matchingBuiltInMethod != null ) {
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
ConversionContext ctx =
new DefaultConversionContext( typeFactory, targetType, dateFormat );
Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx );
new DefaultConversionContext( typeFactory, targetType, dateFormat );
Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx );
methodReference.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
return methodReference;
}
@ -273,7 +273,7 @@ public class MappingResolverImpl implements MappingResolver {
* </ul>
* then this method tries to resolve this combination and make a mapping methodY( methodX ( parameter ) )
*/
private Assignment resolveViaMethodAndMethod( Type sourceType, Type targetType ) {
private Assignment resolveViaMethodAndMethod(Type sourceType, Type targetType) {
List<Method> methodYCandidates = new ArrayList<Method>( methods );
methodYCandidates.addAll( builtInMethods.getBuiltInMethods() );
@ -288,12 +288,14 @@ public class MappingResolverImpl implements MappingResolver {
// a nested method call can be called. so C = methodY( methodX (A) )
for ( Method methodYCandidate : methodYCandidates ) {
if ( methodYCandidate.getSourceParameters().size() == 1 ) {
methodRefY = resolveViaMethod( methodYCandidate.getSourceParameters().get( 0 ).getType(),
targetType );
methodRefY = resolveViaMethod(
methodYCandidate.getSourceParameters().get( 0 ).getType(),
targetType
);
if ( methodRefY != null ) {
Assignment methodRefX = resolveViaMethod(
sourceType,
methodYCandidate.getSourceParameters().get( 0 ).getType()
Assignment methodRefX = resolveViaMethod(
sourceType,
methodYCandidate.getSourceParameters().get( 0 ).getType()
);
if ( methodRefX != null ) {
methodRefY.setAssignment( methodRefX );
@ -319,7 +321,7 @@ public class MappingResolverImpl implements MappingResolver {
* </ul>
* then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) )
*/
private Assignment resolveViaConversionAndMethod( Type sourceType, Type targetType ) {
private Assignment resolveViaConversionAndMethod(Type sourceType, Type targetType) {
List<Method> methodYCandidates = new ArrayList<Method>( methods );
methodYCandidates.addAll( builtInMethods.getBuiltInMethods() );
@ -329,13 +331,13 @@ public class MappingResolverImpl implements MappingResolver {
for ( Method methodYCandidate : methodYCandidates ) {
if ( methodYCandidate.getSourceParameters().size() == 1 ) {
methodRefY = resolveViaMethod(
methodYCandidate.getSourceParameters().get( 0 ).getType(),
targetType
methodYCandidate.getSourceParameters().get( 0 ).getType(),
targetType
);
if ( methodRefY != null ) {
Assignment conversionXRef = resolveViaConversion(
sourceType,
methodYCandidate.getSourceParameters().get( 0 ).getType()
sourceType,
methodYCandidate.getSourceParameters().get( 0 ).getType()
);
if ( conversionXRef != null ) {
methodRefY.setAssignment( conversionXRef );
@ -361,7 +363,7 @@ public class MappingResolverImpl implements MappingResolver {
* </ul>
* then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) )
*/
private Assignment resolveViaMethodAndConversion( Type sourceType, Type targetType ) {
private Assignment resolveViaMethodAndConversion(Type sourceType, Type targetType) {
List<Method> methodXCandidates = new ArrayList<Method>( methods );
methodXCandidates.addAll( builtInMethods.getBuiltInMethods() );
@ -372,8 +374,8 @@ public class MappingResolverImpl implements MappingResolver {
for ( Method methodXCandidate : methodXCandidates ) {
if ( methodXCandidate.getSourceParameters().size() == 1 ) {
Assignment methodRefX = resolveViaMethod(
sourceType,
methodXCandidate.getReturnType()
sourceType,
methodXCandidate.getReturnType()
);
if ( methodRefX != null ) {
conversionYRef = resolveViaConversion( methodXCandidate.getReturnType(), targetType );
@ -393,26 +395,27 @@ public class MappingResolverImpl implements MappingResolver {
return conversionYRef;
}
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) {
List<T> candidates = methodSelectors.getMatchingMethods(
mappingMethod,
methods,
sourceType,
returnType,
qualifiers,
targetPropertyName
mappingMethod,
methods,
sourceType,
returnType,
qualifiers,
targetPropertyName
);
// raise an error if more than one mapping method is suitable to map the given source type
// into the target type
if ( candidates.size() > 1 ) {
String errorMsg = String.format(
"Ambiguous mapping methods found for mapping " + mappedElement + " from %s to %s: %s.",
sourceType,
returnType,
Strings.join( candidates, ", " ) );
String errorMsg = String.format(
"Ambiguous mapping methods found for mapping " + mappedElement + " from %s to %s: %s.",
sourceType,
returnType,
Strings.join( candidates, ", " )
);
mappingMethod.printMessage( messager, Kind.ERROR, errorMsg );
}
@ -424,18 +427,18 @@ public class MappingResolverImpl implements MappingResolver {
return null;
}
private Assignment getMappingMethodReference( SourceMethod method,
Type targetType ) {
private Assignment getMappingMethodReference(SourceMethod method,
Type targetType) {
MapperReference mapperReference = findMapperReference( method );
return AssignmentFactory.createMethodReference(
method,
mapperReference,
SourceMethod.containsTargetTypeParameter( method.getParameters() ) ? targetType : null
method,
mapperReference,
SourceMethod.containsTargetTypeParameter( method.getParameters() ) ? targetType : null
);
}
private MapperReference findMapperReference( SourceMethod method ) {
private MapperReference findMapperReference(SourceMethod method) {
for ( MapperReference ref : mapperReferences ) {
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
return ref;
@ -459,27 +462,27 @@ public class MappingResolverImpl implements MappingResolver {
*
* @return {@code true} if the specified property can be mapped, {@code false} otherwise.
*/
private boolean isPropertyMappable( Type sourceType, Type targetType ) {
private boolean isPropertyMappable(Type sourceType, Type targetType) {
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
if ( sourceType.isCollectionType() && targetType.isCollectionType() ) {
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
sourceType,
targetType.getImplementationType() != null
? targetType.getImplementationType() : targetType
sourceType,
targetType.getImplementationType() != null
? targetType.getImplementationType() : targetType
);
}
if ( sourceType.isMapType() && targetType.isMapType() ) {
collectionOrMapTargetTypeHasCompatibleConstructor = mapTypeHasCompatibleConstructor(
sourceType,
targetType.getImplementationType() != null
? targetType.getImplementationType() : targetType
sourceType,
targetType.getImplementationType() != null
? targetType.getImplementationType() : targetType
);
}
if ( ( ( targetType.isCollectionType() || targetType.isMapType() )
&& collectionOrMapTargetTypeHasCompatibleConstructor ) ) {
&& collectionOrMapTargetTypeHasCompatibleConstructor ) ) {
return true;
}
@ -495,19 +498,19 @@ public class MappingResolverImpl implements MappingResolver {
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
* otherwise.
*/
private boolean collectionTypeHasCompatibleConstructor( Type sourceType, Type targetType ) {
private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead
// we just check whether the target type is parameterized in a way that it implicitly should have a
// constructor which accepts the source type
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty()
? typeFactory.getType( Object.class ).getTypeMirror()
: sourceType.getTypeParameters().get( 0 ).getTypeMirror();
? typeFactory.getType( Object.class ).getTypeMirror()
: sourceType.getTypeParameters().get( 0 ).getTypeMirror();
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty()
? typeFactory.getType( Object.class ).getTypeMirror()
: targetType.getTypeParameters().get( 0 ).getTypeMirror();
? typeFactory.getType( Object.class ).getTypeMirror()
: targetType.getTypeParameters().get( 0 ).getTypeMirror();
return typeUtils.isAssignable( sourceElementType, targetElementType );
}
@ -521,7 +524,7 @@ public class MappingResolverImpl implements MappingResolver {
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
* otherwise.
*/
private boolean mapTypeHasCompatibleConstructor( Type sourceType, Type targetType ) {
private boolean mapTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead
// we just check whether the target type is parameterized in a way that it implicitly should have a
@ -551,7 +554,7 @@ public class MappingResolverImpl implements MappingResolver {
}
return typeUtils.isAssignable( sourceKeyType, targetKeyType )
&& typeUtils.isAssignable( sourceValueType, targetValueType );
&& typeUtils.isAssignable( sourceValueType, targetValueType );
}
}
}