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

View File

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

View File

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

View File

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

View File

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