From 585f94457462bcf32d9d8f76f99f060b8981b218 Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Wed, 14 Aug 2013 21:36:37 +0200 Subject: [PATCH] #61 Refactoring Type into a wrapper around TypeMirror --- .../ap/conversion/ConversionProvider.java | 3 + .../mapstruct/ap/conversion/Conversions.java | 46 +-- .../ap/conversion/DateToStringConversion.java | 6 +- .../conversion/DefaultConversionContext.java | 10 +- .../java/org/mapstruct/ap/model/Mapper.java | 12 +- .../org/mapstruct/ap/model/MappingMethod.java | 1 + .../java/org/mapstruct/ap/model/Type.java | 265 +++++------------- ...nnotationBasedComponentModelProcessor.java | 14 +- .../ap/processor/CdiComponentProcessor.java | 5 +- .../DefaultModelElementProcessorContext.java | 15 + .../processor/Jsr330ComponentProcessor.java | 5 +- .../ap/processor/MapperCreationProcessor.java | 49 ++-- .../processor/MethodRetrievalProcessor.java | 19 +- .../ap/processor/ModelElementProcessor.java | 3 + .../processor/SpringComponentProcessor.java | 5 +- .../org/mapstruct/ap/util/Executables.java | 12 +- .../java/org/mapstruct/ap/util/Filters.java | 10 +- .../org/mapstruct/ap/util/TypeFactory.java | 192 +++++++++++++ .../java/org/mapstruct/ap/util/TypeUtil.java | 129 --------- ...pstruct.ap.model.IterableMappingMethod.ftl | 2 +- ...rg.mapstruct.ap.model.MapMappingMethod.ftl | 2 +- .../org.mapstruct.ap.model.Parameter.ftl | 2 +- ...org.mapstruct.ap.model.PropertyMapping.ftl | 4 +- 23 files changed, 395 insertions(+), 416 deletions(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java delete mode 100644 processor/src/main/java/org/mapstruct/ap/util/TypeUtil.java diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/ConversionProvider.java b/processor/src/main/java/org/mapstruct/ap/conversion/ConversionProvider.java index a5735dc86..8962c5a8b 100644 --- a/processor/src/main/java/org/mapstruct/ap/conversion/ConversionProvider.java +++ b/processor/src/main/java/org/mapstruct/ap/conversion/ConversionProvider.java @@ -20,6 +20,7 @@ package org.mapstruct.ap.conversion; import org.mapstruct.ap.model.Type; import org.mapstruct.ap.model.TypeConversion; +import org.mapstruct.ap.util.TypeFactory; /** * Implementations create inline {@link TypeConversion}s such as @@ -80,5 +81,7 @@ public interface ConversionProvider { * @return The date format if this conversion. */ String getDateFormat(); + + TypeFactory getTypeFactory(); } } diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java b/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java index f0868384b..7374bca2a 100644 --- a/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java +++ b/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java @@ -22,12 +22,10 @@ import java.math.BigInteger; import java.util.Date; import java.util.HashMap; import java.util.Map; -import javax.lang.model.type.DeclaredType; import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; import org.mapstruct.ap.model.Type; -import org.mapstruct.ap.util.TypeUtil; +import org.mapstruct.ap.util.TypeFactory; import static org.mapstruct.ap.conversion.ReverseConversion.reverse; @@ -38,16 +36,16 @@ import static org.mapstruct.ap.conversion.ReverseConversion.reverse; */ public class Conversions { - private TypeUtil typeUtil; private final Map conversions = new HashMap(); - private final DeclaredType enumType; - private final DeclaredType stringType; + private final Type enumType; + private final Type stringType; + private final TypeFactory typeFactory; - public Conversions(Elements elementUtils, Types typeUtils, TypeUtil typeUtil) { - this.typeUtil = typeUtil; + public Conversions(Elements elementUtils, TypeFactory typeFactory) { + this.typeFactory = typeFactory; - this.enumType = typeUtils.getDeclaredType( elementUtils.getTypeElement( Enum.class.getCanonicalName() ) ); - this.stringType = typeUtils.getDeclaredType( elementUtils.getTypeElement( String.class.getCanonicalName() ) ); + this.enumType = typeFactory.getType( Enum.class ); + this.stringType = typeFactory.getType( String.class ); //native types <> native types, including wrappers registerNativeTypeConversion( byte.class, Byte.class ); @@ -202,28 +200,32 @@ public class Conversions { } private void register(Class sourceType, Class targetType, ConversionProvider conversion) { - conversions.put( Key.forClasses( sourceType, targetType ), conversion ); - conversions.put( Key.forClasses( targetType, sourceType ), reverse( conversion ) ); + conversions.put( forClasses( sourceType, targetType ), conversion ); + conversions.put( forClasses( targetType, sourceType ), reverse( conversion ) ); } public ConversionProvider getConversion(Type sourceType, Type targetType) { - if ( sourceType.isEnumType() && targetType.equals( typeUtil.getType( stringType ) ) ) { - sourceType = typeUtil.getType( enumType ); + if ( sourceType.isEnumType() && targetType.equals( stringType ) ) { + sourceType = enumType; } - else if ( targetType.isEnumType() && sourceType.equals( typeUtil.getType( stringType ) ) ) { - targetType = typeUtil.getType( enumType ); + else if ( targetType.isEnumType() && sourceType.equals( stringType ) ) { + targetType = enumType; } return conversions.get( new Key( sourceType, targetType ) ); } + private Key forClasses(Class sourceClass, Class targetClass) { + Type sourceType = typeFactory.getType( sourceClass ); + Type targetType = typeFactory.getType( targetClass ); + + return new Key( sourceType, targetType ); + } + private static class Key { private final Type sourceType; private final Type targetType; - private static Key forClasses(Class sourceType, Class targetType) { - return new Key( Type.forClass( sourceType ), Type.forClass( targetType ) ); - } private Key(Type sourceType, Type targetType) { this.sourceType = sourceType; @@ -240,10 +242,8 @@ public class Conversions { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result - + ( ( sourceType == null ) ? 0 : sourceType.hashCode() ); - result = prime * result - + ( ( targetType == null ) ? 0 : targetType.hashCode() ); + result = prime * result + ( ( sourceType == null ) ? 0 : sourceType.hashCode() ); + result = prime * result + ( ( targetType == null ) ? 0 : targetType.hashCode() ); return result; } diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/DateToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/DateToStringConversion.java index fb98e6f35..05c009d96 100644 --- a/processor/src/main/java/org/mapstruct/ap/conversion/DateToStringConversion.java +++ b/processor/src/main/java/org/mapstruct/ap/conversion/DateToStringConversion.java @@ -39,7 +39,7 @@ public class DateToStringConversion implements ConversionProvider { @Override public TypeConversion to(String sourceReference, Context conversionContext) { return new TypeConversion( - asSet( Type.forClass( SimpleDateFormat.class ) ), + asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ), Collections.emptyList(), getConversionString( sourceReference, conversionContext, "format" ) ); @@ -48,8 +48,8 @@ public class DateToStringConversion implements ConversionProvider { @Override public TypeConversion from(String targetReference, Context conversionContext) { return new TypeConversion( - asSet( Type.forClass( SimpleDateFormat.class ) ), - Arrays.asList( Type.forClass( ParseException.class ) ), + asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ), + Arrays.asList( conversionContext.getTypeFactory().getType( ParseException.class ) ), getConversionString( targetReference, conversionContext, "parse" ) ); } diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/DefaultConversionContext.java b/processor/src/main/java/org/mapstruct/ap/conversion/DefaultConversionContext.java index 697b482d3..7ed09963d 100644 --- a/processor/src/main/java/org/mapstruct/ap/conversion/DefaultConversionContext.java +++ b/processor/src/main/java/org/mapstruct/ap/conversion/DefaultConversionContext.java @@ -20,6 +20,7 @@ package org.mapstruct.ap.conversion; import org.mapstruct.ap.conversion.ConversionProvider.Context; import org.mapstruct.ap.model.Type; +import org.mapstruct.ap.util.TypeFactory; /** * Default implementation of the {@link Context} passed to conversion providers. @@ -30,8 +31,10 @@ public class DefaultConversionContext implements ConversionProvider.Context { private final Type targetType; private final String format; + private final TypeFactory typeFactory; - public DefaultConversionContext(Type targetType, String format) { + public DefaultConversionContext(TypeFactory typeFactory, Type targetType, String format) { + this.typeFactory = typeFactory; this.targetType = targetType; this.format = format; } @@ -45,4 +48,9 @@ public class DefaultConversionContext implements ConversionProvider.Context { public String getDateFormat() { return format; } + + @Override + public TypeFactory getTypeFactory() { + return typeFactory; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java index 2bed37e43..c6f59e2cd 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java @@ -25,6 +25,8 @@ import java.util.SortedSet; import java.util.TreeSet; import javax.annotation.Generated; +import org.mapstruct.ap.util.TypeFactory; + /** * Represents a type implementing a mapper interface (annotated with {@code @Mapper}. This is the root object of the * mapper model. @@ -33,6 +35,7 @@ import javax.annotation.Generated; */ public class Mapper extends AbstractModelElement { + private final TypeFactory typeFactory; private final String packageName; private final String interfaceName; private final String implementationName; @@ -41,7 +44,7 @@ public class Mapper extends AbstractModelElement { private final List referencedMappers; private final Options options; - public Mapper(String packageName, String interfaceName, String implementationName, + public Mapper(TypeFactory typeFactory, String packageName, String interfaceName, String implementationName, List mappingMethods, List referencedMappers, Options options) { this.packageName = packageName; this.interfaceName = interfaceName; @@ -50,12 +53,13 @@ public class Mapper extends AbstractModelElement { this.mappingMethods = mappingMethods; this.referencedMappers = referencedMappers; this.options = options; + this.typeFactory = typeFactory; } @Override public SortedSet getImportTypes() { SortedSet importedTypes = new TreeSet(); - importedTypes.add( Type.forClass( Generated.class ) ); + importedTypes.add( typeFactory.getType( Generated.class ) ); for ( MappingMethod mappingMethod : mappingMethods ) { for ( Type type : mappingMethod.getImportTypes() ) { @@ -87,9 +91,7 @@ public class Mapper extends AbstractModelElement { collection.add( typeToAdd ); } - addWithDependents( collection, typeToAdd.getCollectionImplementationType() ); - addWithDependents( collection, typeToAdd.getIterableImplementationType() ); - addWithDependents( collection, typeToAdd.getMapImplementationType() ); + addWithDependents( collection, typeToAdd.getImplementationType() ); for ( Type type : typeToAdd.getTypeParameters() ) { addWithDependents( collection, type ); diff --git a/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java index 10b203dec..64d370a6e 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java @@ -92,6 +92,7 @@ public abstract class MappingMethod extends AbstractModelElement { } types.add( getReturnType() ); + types.addAll( getReturnType().getImportTypes() ); return types; } diff --git a/processor/src/main/java/org/mapstruct/ap/model/Type.java b/processor/src/main/java/org/mapstruct/ap/model/Type.java index 811541fec..8ba814cd0 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Type.java @@ -18,176 +18,88 @@ */ package org.mapstruct.ap.model; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.NavigableMap; -import java.util.NavigableSet; import java.util.Set; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentNavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.SimpleElementVisitor6; +import javax.lang.model.util.Types; -import org.mapstruct.ap.util.Strings; +import org.mapstruct.ap.util.TypeFactory; /** - * Represents the type of a bean property, parameter etc. + * Represents the type of a bean property, parameter etc. Each type corresponds to a {@link TypeMirror}, i.e. there are + * different instances for e.g. {@code Set} and {@code Set}. + *

+ * Allows for a unified handling of declared and primitive types and usage within templates. Instances are obtained + * through {@link TypeFactory}. * * @author Gunnar Morling */ public class Type extends AbstractModelElement implements Comparable { - /** - * Type representing {@code void} - */ - public static final Type VOID = new Type( "void" ); - private static final Set PRIMITIVE_TYPE_NAMES = new HashSet( - Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" ) - ); - - private static final ConcurrentMap DEFAULT_ITERABLE_IMPLEMENTATION_TYPES = - new ConcurrentHashMap(); - private static final ConcurrentMap DEFAULT_COLLECTION_IMPLEMENTATION_TYPES = - new ConcurrentHashMap(); - private static final ConcurrentMap DEFAULT_MAP_IMPLEMENTATION_TYPES = - new ConcurrentHashMap(); - - static { - //base - DEFAULT_ITERABLE_IMPLEMENTATION_TYPES.put( Iterable.class.getName(), forClass( ArrayList.class ) ); - DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( Collection.class.getName(), forClass( ArrayList.class ) ); - - //list - DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( List.class.getName(), forClass( ArrayList.class ) ); - - //set - DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( Set.class.getName(), forClass( HashSet.class ) ); - DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( SortedSet.class.getName(), forClass( TreeSet.class ) ); - DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( NavigableSet.class.getName(), forClass( TreeSet.class ) ); - - DEFAULT_ITERABLE_IMPLEMENTATION_TYPES.putAll( DEFAULT_COLLECTION_IMPLEMENTATION_TYPES ); - - //map - DEFAULT_MAP_IMPLEMENTATION_TYPES.put( Map.class.getName(), forClass( HashMap.class ) ); - DEFAULT_MAP_IMPLEMENTATION_TYPES.put( SortedMap.class.getName(), forClass( TreeMap.class ) ); - DEFAULT_MAP_IMPLEMENTATION_TYPES.put( NavigableMap.class.getName(), forClass( TreeMap.class ) ); - DEFAULT_MAP_IMPLEMENTATION_TYPES.put( ConcurrentMap.class.getName(), forClass( ConcurrentHashMap.class ) ); - DEFAULT_MAP_IMPLEMENTATION_TYPES.put( - ConcurrentNavigableMap.class.getName(), - forClass( ConcurrentSkipListMap.class ) - ); - } - - private final String canonicalName; private final String packageName; private final String name; + private final String qualifiedName; private final List typeParameters; private final boolean isInterface; private final boolean isEnumType; - private final boolean isCollectionType; private final boolean isIterableType; private final boolean isMapType; - private final Type collectionImplementationType; - private final Type iterableImplementationType; - private final Type mapImplementationType; + private final Type implementationType; + private final TypeMirror typeMirror; + private final Types typeUtils; + private final TypeElement typeElement; - public static Type forClass(Class clazz) { - Package pakkage = clazz.getPackage(); - - if ( pakkage != null ) { - return new Type( - clazz.getCanonicalName(), - pakkage.getName(), - clazz.getSimpleName(), - clazz.isInterface(), - clazz.isEnum(), - Collection.class.isAssignableFrom( clazz ), - Iterable.class.isAssignableFrom( clazz ), - Map.class.isAssignableFrom( clazz ), - Collections.emptyList() - ); - } - else { - return new Type( clazz.getSimpleName() ); - } - } - - public Type(String name) { - this( name, null, name, false, false, false, false, false, Collections.emptyList() ); - } - - public Type(String packageName, String name) { - this( - packageName + "." + name, - packageName, - name, - false, - false, - false, - false, - false, - Collections.emptyList() - ); - } - - public Type(String canonicalName, String packageName, String name, boolean isInterface, boolean isEnumType, - boolean isCollectionType, - boolean isIterableType, boolean isMapType, List typeParameters) { - this.canonicalName = canonicalName; - this.packageName = packageName; - this.name = name; - this.isInterface = isInterface; - this.isEnumType = isEnumType; - this.isCollectionType = isCollectionType; + public Type(TypeMirror typeMirror, List typeParameters, Type implementationType, boolean isIterableType, + boolean isMapType, + Types typeUtils, Elements elementUtils) { + this.typeMirror = typeMirror; + this.implementationType = implementationType; + this.typeParameters = typeParameters; this.isIterableType = isIterableType; this.isMapType = isMapType; - this.typeParameters = typeParameters; + this.typeUtils = typeUtils; - if ( isCollectionType ) { - collectionImplementationType = DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.get( packageName + "." + name ); + DeclaredType declaredType = typeMirror.getKind() == TypeKind.DECLARED ? (DeclaredType) typeMirror : null; + + if ( declaredType != null ) { + isEnumType = declaredType.asElement().getKind() == ElementKind.ENUM; + isInterface = declaredType.asElement().getKind() == ElementKind.INTERFACE; + name = declaredType.asElement().getSimpleName().toString(); + + typeElement = declaredType.asElement().accept( new TypeElementRetrievalVisitor(), null ); + + if ( typeElement != null ) { + packageName = elementUtils.getPackageOf( typeElement ).getQualifiedName().toString(); + qualifiedName = typeElement.getQualifiedName().toString(); + } + else { + packageName = null; + qualifiedName = name; + } } else { - collectionImplementationType = null; - } - - if ( isIterableType ) { - iterableImplementationType = DEFAULT_ITERABLE_IMPLEMENTATION_TYPES.get( packageName + "." + name ); - } - else { - iterableImplementationType = null; - } - - if ( isMapType ) { - Type mapType = DEFAULT_MAP_IMPLEMENTATION_TYPES.get( packageName + "." + name ); - mapImplementationType = mapType != null ? new Type( - mapType.getPackageName() + "." + mapType.getName(), - mapType.getPackageName(), - mapType.getName(), - mapType.isInterface(), - mapType.isEnumType(), - mapType.isCollectionType(), - mapType.isIterableType(), - true, - typeParameters - ) : null; - } - else { - mapImplementationType = null; + isEnumType = false; + isInterface = false; + typeElement = null; + name = typeMirror.toString(); + packageName = null; + qualifiedName = name; } } - public String getCanonicalName() { - return canonicalName; + public TypeMirror getTypeMirror() { + return typeMirror; + } + + public TypeElement getTypeElement() { + return typeElement; } public String getPackageName() { @@ -203,7 +115,7 @@ public class Type extends AbstractModelElement implements Comparable { } public boolean isPrimitive() { - return packageName == null && PRIMITIVE_TYPE_NAMES.contains( name ); + return typeMirror.getKind().isPrimitive(); } public boolean isInterface() { @@ -214,26 +126,8 @@ public class Type extends AbstractModelElement implements Comparable { return isEnumType; } - public Type getCollectionImplementationType() { - return collectionImplementationType; - } - - public Type getIterableImplementationType() { - return iterableImplementationType; - } - - public Type getMapImplementationType() { - return mapImplementationType; - } - - public boolean isCollectionType() { - return isCollectionType; - } - public Type getImplementationType() { - return collectionImplementationType != null ? collectionImplementationType : - iterableImplementationType != null ? iterableImplementationType : - mapImplementationType; + return implementationType; } public boolean isIterableType() { @@ -245,12 +139,13 @@ public class Type extends AbstractModelElement implements Comparable { } public String getFullyQualifiedName() { - return packageName == null ? name : packageName + "." + name; + return qualifiedName; } @Override public Set getImportTypes() { - return Collections.emptySet(); + return implementationType != null ? org.mapstruct.ap.util.Collections.asSet( implementationType ) : + Collections.emptySet(); } @Override @@ -259,7 +154,6 @@ public class Type extends AbstractModelElement implements Comparable { int result = 1; result = prime * result + ( ( name == null ) ? 0 : name.hashCode() ); result = prime * result + ( ( packageName == null ) ? 0 : packageName.hashCode() ); - result = prime * result + ( ( typeParameters == null ) ? 0 : typeParameters.hashCode() ); return result; } @@ -275,31 +169,8 @@ public class Type extends AbstractModelElement implements Comparable { return false; } Type other = (Type) obj; - if ( name == null ) { - if ( other.name != null ) { - return false; - } - } - else if ( !name.equals( other.name ) ) { - return false; - } - if ( packageName == null ) { - if ( other.packageName != null ) { - return false; - } - } - else if ( !packageName.equals( other.packageName ) ) { - return false; - } - if ( typeParameters == null ) { - if ( other.typeParameters != null ) { - return false; - } - } - else if ( !typeParameters.equals( other.typeParameters ) ) { - return false; - } - return true; + + return typeUtils.isSameType( typeMirror, other.typeMirror ); } @Override @@ -309,11 +180,13 @@ public class Type extends AbstractModelElement implements Comparable { @Override public String toString() { - if ( !typeParameters.isEmpty() ) { - return name + "<" + Strings.join( typeParameters, ", " ) + ">"; - } - else { - return name; + return typeMirror.toString(); + } + + private static class TypeElementRetrievalVisitor extends SimpleElementVisitor6 { + @Override + public TypeElement visitType(TypeElement e, Void p) { + return e; } } } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/AnnotationBasedComponentModelProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/AnnotationBasedComponentModelProcessor.java index 03b0fcb1a..5282a009b 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/AnnotationBasedComponentModelProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/AnnotationBasedComponentModelProcessor.java @@ -27,6 +27,7 @@ import org.mapstruct.ap.model.AnnotationMapperReference; import org.mapstruct.ap.model.Mapper; import org.mapstruct.ap.model.MapperReference; import org.mapstruct.ap.util.OptionsHelper; +import org.mapstruct.ap.util.TypeFactory; /** * An {@link ModelElementProcessor} which converts the given {@link Mapper} @@ -38,8 +39,12 @@ import org.mapstruct.ap.util.OptionsHelper; */ public abstract class AnnotationBasedComponentModelProcessor implements ModelElementProcessor { + private TypeFactory typeFactory; + @Override public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) { + this.typeFactory = context.getTypeFactory(); + String componentModel = MapperPrism.getInstanceOn( mapperTypeElement ).componentModel(); String effectiveComponentModel = OptionsHelper.getEffectiveComponentModel( context.getOptions(), @@ -68,7 +73,10 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle * @return the mapper reference replacing the original one */ protected MapperReference replacementMapperReference(MapperReference originalReference) { - return new AnnotationMapperReference( getMapperReferenceAnnotation(), originalReference.getMapperType() ); + return new AnnotationMapperReference( + getMapperReferenceAnnotation(), + originalReference.getMapperType() + ); } /** @@ -90,4 +98,8 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle public int getPriority() { return 1100; } + + protected TypeFactory getTypeFactory() { + return typeFactory; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java index 931641a28..fff9344ae 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/CdiComponentProcessor.java @@ -20,7 +20,6 @@ package org.mapstruct.ap.processor; import org.mapstruct.ap.model.Annotation; import org.mapstruct.ap.model.Mapper; -import org.mapstruct.ap.model.Type; /** * A {@link ModelElementProcessor} which converts the given {@link Mapper} @@ -38,11 +37,11 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso @Override protected Annotation getTypeAnnotation() { - return new Annotation( new Type( "javax.enterprise.context", "ApplicationScoped" ) ); + return new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) ); } @Override protected Annotation getMapperReferenceAnnotation() { - return new Annotation( new Type( "javax.inject", "Inject" ) ); + return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/DefaultModelElementProcessorContext.java b/processor/src/main/java/org/mapstruct/ap/processor/DefaultModelElementProcessorContext.java index ff0825e47..699209320 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/DefaultModelElementProcessorContext.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/DefaultModelElementProcessorContext.java @@ -29,6 +29,7 @@ import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; import org.mapstruct.ap.model.Options; +import org.mapstruct.ap.util.TypeFactory; /** * Default implementation of the processor context. @@ -40,10 +41,15 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso private final ProcessingEnvironment processingEnvironment; private final DelegatingMessager messager; private final Options options; + private final TypeFactory typeFactory; public DefaultModelElementProcessorContext(ProcessingEnvironment processingEnvironment, Options options) { this.processingEnvironment = processingEnvironment; this.messager = new DelegatingMessager( processingEnvironment.getMessager() ); + this.typeFactory = new TypeFactory( + processingEnvironment.getElementUtils(), + processingEnvironment.getTypeUtils() + ); this.options = options; } @@ -62,6 +68,11 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso return processingEnvironment.getElementUtils(); } + @Override + public TypeFactory getTypeFactory() { + return typeFactory; + } + @Override public Messager getMessager() { return messager; @@ -86,6 +97,7 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso this.delegate = delegate; } + @Override public void printMessage(Kind kind, CharSequence msg) { delegate.printMessage( kind, msg ); if ( kind == Kind.ERROR ) { @@ -93,6 +105,7 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso } } + @Override public void printMessage(Kind kind, CharSequence msg, Element e) { delegate.printMessage( kind, msg, e ); if ( kind == Kind.ERROR ) { @@ -100,6 +113,7 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso } } + @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { delegate.printMessage( kind, msg, e, a ); if ( kind == Kind.ERROR ) { @@ -107,6 +121,7 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso } } + @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { delegate.printMessage( kind, msg, e, a, v ); if ( kind == Kind.ERROR ) { diff --git a/processor/src/main/java/org/mapstruct/ap/processor/Jsr330ComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/Jsr330ComponentProcessor.java index 86d3380c7..39d6e63d4 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/Jsr330ComponentProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/Jsr330ComponentProcessor.java @@ -20,7 +20,6 @@ package org.mapstruct.ap.processor; import org.mapstruct.ap.model.Annotation; import org.mapstruct.ap.model.Mapper; -import org.mapstruct.ap.model.Type; /** * A {@link ModelElementProcessor} which converts the given {@link Mapper} @@ -38,11 +37,11 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce @Override protected Annotation getTypeAnnotation() { - return new Annotation( new Type( "javax.inject", "Named" ) ); + return new Annotation( getTypeFactory().getType( "javax.inject.Named" ) ); } @Override protected Annotation getMapperReferenceAnnotation() { - return new Annotation( new Type( "javax.inject", "Inject" ) ); + return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java index 79acbfed1..53e757d23 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -30,9 +30,9 @@ import java.util.Set; import javax.annotation.processing.Messager; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; import org.mapstruct.ap.MapperPrism; @@ -58,7 +58,7 @@ import org.mapstruct.ap.model.source.Method; import org.mapstruct.ap.util.Executables; import org.mapstruct.ap.util.Filters; import org.mapstruct.ap.util.Strings; -import org.mapstruct.ap.util.TypeUtil; +import org.mapstruct.ap.util.TypeFactory; /** * A {@link ModelElementProcessor} which creates a {@link Mapper} from the given @@ -71,24 +71,24 @@ public class MapperCreationProcessor implements ModelElementProcessor sourceModel) { this.elementUtils = context.getElementUtils(); - this.typeUtils = context.getTypeUtils(); this.messager = context.getMessager(); this.options = context.getOptions(); - this.typeUtil = new TypeUtil( context.getElementUtils(), context.getTypeUtils() ); - this.conversions = new Conversions( elementUtils, typeUtils, typeUtil ); - this.executables = new Executables( typeUtil ); + this.typeFactory = context.getTypeFactory(); + this.conversions = new Conversions( elementUtils, typeFactory ); + this.executables = new Executables( typeFactory ); + this.filters = new Filters( executables ); return getMapper( mapperTypeElement, sourceModel ); } @@ -104,6 +104,7 @@ public class MapperCreationProcessor implements ModelElementProcessor mapperReferences = getReferencedMappers( element ); return new Mapper( + typeFactory, elementUtils.getPackageOf( element ).getQualifiedName().toString(), element.getSimpleName().toString(), element.getSimpleName() + IMPLEMENTATION_SUFFIX, @@ -143,7 +144,7 @@ public class MapperCreationProcessor implements ModelElementProcessor sourceGetters = Filters.getterMethodsIn( + TypeElement parameterElement = parameter.getType().getTypeElement(); + List sourceGetters = filters.getterMethodsIn( elementUtils.getAllMembers( parameterElement ) ); @@ -252,8 +254,8 @@ public class MapperCreationProcessor implements ModelElementProcessor targetSetters = Filters.setterMethodsIn( + TypeElement resultTypeElement = method.getResultType().getTypeElement(); + List targetSetters = filters.setterMethodsIn( elementUtils.getAllMembers( resultTypeElement ) ); @@ -348,8 +350,8 @@ public class MapperCreationProcessor implements ModelElementProcessor getters = Filters.setterMethodsIn( + TypeElement parameterTypeElement = parameter.getType().getTypeElement(); + List getters = filters.setterMethodsIn( elementUtils.getAllMembers( parameterTypeElement ) ); @@ -357,8 +359,8 @@ public class MapperCreationProcessor implements ModelElementProcessor targetSetters = Filters.setterMethodsIn( + TypeElement resultTypeElement = method.getResultType().getTypeElement(); + List targetSetters = filters.setterMethodsIn( elementUtils.getAllMembers( resultTypeElement ) ); @@ -528,7 +530,10 @@ public class MapperCreationProcessor implements ModelElementProcessor methods, Type parameterType, @@ -540,8 +545,7 @@ public class MapperCreationProcessor implements ModelElementProcessor> { private Messager messager; - private Types typeUtils; - private TypeUtil typeUtil; + private TypeFactory typeFactory; private Executables executables; @Override public List process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) { this.messager = context.getMessager(); - this.typeUtils = context.getTypeUtils(); - this.typeUtil = new TypeUtil( context.getElementUtils(), typeUtils ); - this.executables = new Executables( typeUtil ); + this.typeFactory = context.getTypeFactory(); + this.executables = new Executables( typeFactory ); return retrieveMethods( mapperTypeElement, true ); } @@ -146,7 +144,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor { Elements getElementUtils(); + TypeFactory getTypeFactory(); + Messager getMessager(); Options getOptions(); diff --git a/processor/src/main/java/org/mapstruct/ap/processor/SpringComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/SpringComponentProcessor.java index 3b3ab0a00..1513cc7bd 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/SpringComponentProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/SpringComponentProcessor.java @@ -20,7 +20,6 @@ package org.mapstruct.ap.processor; import org.mapstruct.ap.model.Annotation; import org.mapstruct.ap.model.Mapper; -import org.mapstruct.ap.model.Type; /** * A {@link ModelElementProcessor} which converts the given {@link Mapper} @@ -38,11 +37,11 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce @Override protected Annotation getTypeAnnotation() { - return new Annotation( new Type( "org.springframework.stereotype", "Component" ) ); + return new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) ); } @Override protected Annotation getMapperReferenceAnnotation() { - return new Annotation( new Type( "org.springframework.beans.factory.annotation", "Autowired" ) ); + return new Annotation( getTypeFactory().getType( "org.springframework.beans.factory.annotation.Autowired" ) ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/util/Executables.java b/processor/src/main/java/org/mapstruct/ap/util/Executables.java index c6681fc55..97059d0ab 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/Executables.java +++ b/processor/src/main/java/org/mapstruct/ap/util/Executables.java @@ -38,10 +38,10 @@ import org.mapstruct.ap.model.Type; */ public class Executables { - private final TypeUtil typeUtil; + private final TypeFactory typeFactory; - public Executables(TypeUtil typeUtil) { - this.typeUtil = typeUtil; + public Executables(TypeFactory typeFactory) { + this.typeFactory = typeFactory; } public boolean isGetterMethod(ExecutableElement method) { @@ -119,7 +119,7 @@ public class Executables { return new Parameter( parameter.getSimpleName().toString(), - typeUtil.retrieveType( parameter.asType() ), + typeFactory.getType( parameter.asType() ), false ); } @@ -133,7 +133,7 @@ public class Executables { .add( new Parameter( parameter.getSimpleName().toString(), - typeUtil.retrieveType( parameter.asType() ), + typeFactory.getType( parameter.asType() ), MappingTargetPrism.getInstanceOn( parameter ) != null ) ); @@ -143,6 +143,6 @@ public class Executables { } public Type retrieveReturnType(ExecutableElement method) { - return typeUtil.retrieveType( method.getReturnType() ); + return typeFactory.getType( method.getReturnType() ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/util/Filters.java b/processor/src/main/java/org/mapstruct/ap/util/Filters.java index ba3187a4e..71a37957b 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/Filters.java +++ b/processor/src/main/java/org/mapstruct/ap/util/Filters.java @@ -32,13 +32,13 @@ import static javax.lang.model.util.ElementFilter.methodsIn; */ public class Filters { - //TODO - private static Executables executables = new Executables( null ); + private final Executables executables; - private Filters() { + public Filters(Executables executables) { + this.executables = executables; } - public static List getterMethodsIn(Iterable elements) { + public List getterMethodsIn(Iterable elements) { List getterMethods = new LinkedList(); for ( ExecutableElement method : methodsIn( elements ) ) { @@ -50,7 +50,7 @@ public class Filters { return getterMethods; } - public static List setterMethodsIn(Iterable elements) { + public List setterMethodsIn(Iterable elements) { List setterMethods = new LinkedList(); for ( ExecutableElement method : methodsIn( elements ) ) { diff --git a/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java new file mode 100644 index 000000000..9a404498b --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java @@ -0,0 +1,192 @@ +/** + * Copyright 2012-2013 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.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.NavigableSet; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +import org.mapstruct.ap.model.Type; + +/** + * Factory creating {@link Type} instances. + * + * @author Gunnar Morling + */ +public class TypeFactory { + + private final Elements elementUtils; + private final Types typeUtils; + + private final TypeMirror iterableType; + private final TypeMirror mapType; + + private final Map implementationTypes = new HashMap(); + + public TypeFactory(Elements elementUtils, Types typeUtils) { + this.elementUtils = elementUtils; + this.typeUtils = typeUtils; + + iterableType = typeUtils.erasure( elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType() ); + mapType = typeUtils.erasure( elementUtils.getTypeElement( Map.class.getCanonicalName() ).asType() ); + + implementationTypes.put( Iterable.class.getName(), getType( ArrayList.class ) ); + implementationTypes.put( Collection.class.getName(), getType( ArrayList.class ) ); + implementationTypes.put( List.class.getName(), getType( ArrayList.class ) ); + + implementationTypes.put( Set.class.getName(), getType( HashSet.class ) ); + implementationTypes.put( SortedSet.class.getName(), getType( TreeSet.class ) ); + implementationTypes.put( NavigableSet.class.getName(), getType( TreeSet.class ) ); + + implementationTypes.put( Map.class.getName(), getType( HashMap.class ) ); + implementationTypes.put( SortedMap.class.getName(), getType( TreeMap.class ) ); + implementationTypes.put( NavigableMap.class.getName(), getType( TreeMap.class ) ); + implementationTypes.put( ConcurrentMap.class.getName(), getType( ConcurrentHashMap.class ) ); + implementationTypes.put( ConcurrentNavigableMap.class.getName(), getType( ConcurrentSkipListMap.class ) ); + } + + public Type getType(Class type) { + return type.isPrimitive() ? getType( getPrimitiveType( type ) ) : getType( type.getCanonicalName() ); + } + + public Type getType(String canonicalName) { + TypeElement typeElement = elementUtils.getTypeElement( canonicalName ); + return getType( typeElement ); + } + + public Type getType(TypeElement typeElement) { + return getType( typeElement.asType() ); + } + + public Type getType(TypeMirror mirror) { + Type implementationType = getImplementationType( mirror ); + + boolean isIterableType = typeUtils.isSubtype( + mirror, + iterableType + ); + boolean isMapType = typeUtils.isSubtype( + mirror, + mapType + ); + + return new Type( + mirror, + getTypeParameters( mirror ), + implementationType, + isIterableType, + isMapType, + typeUtils, + elementUtils + ); + } + + private List getTypeParameters(TypeMirror mirror) { + if ( mirror.getKind() != TypeKind.DECLARED ) { + return java.util.Collections.emptyList(); + } + + DeclaredType declaredType = (DeclaredType) mirror; + ArrayList typeParameters = new ArrayList( declaredType.getTypeArguments().size() ); + + for ( TypeMirror typeParameter : declaredType.getTypeArguments() ) { + typeParameters.add( getType( typeParameter ) ); + } + + return typeParameters; + } + + private TypeMirror getPrimitiveType(Class primitiveType) { + return primitiveType == byte.class ? typeUtils.getPrimitiveType( TypeKind.BYTE ) : + primitiveType == short.class ? typeUtils.getPrimitiveType( TypeKind.SHORT ) : + primitiveType == int.class ? typeUtils.getPrimitiveType( TypeKind.INT ) : + primitiveType == long.class ? typeUtils.getPrimitiveType( TypeKind.LONG ) : + primitiveType == float.class ? typeUtils.getPrimitiveType( TypeKind.FLOAT ) : + primitiveType == double.class ? typeUtils.getPrimitiveType( TypeKind.DOUBLE ) : + primitiveType == boolean.class ? typeUtils.getPrimitiveType( TypeKind.BOOLEAN ) : + primitiveType == char.class ? typeUtils.getPrimitiveType( TypeKind.CHAR ) : + typeUtils.getPrimitiveType( TypeKind.BYTE ); + } + + private Type getImplementationType(TypeMirror mirror) { + if ( mirror.getKind() != TypeKind.DECLARED ) { + return null; + } + + DeclaredType declaredType = (DeclaredType) mirror; + + Type implementationType = implementationTypes.get( + ( (TypeElement) declaredType.asElement() ).getQualifiedName() + .toString() + ); + + if ( implementationType != null ) { + return new Type( + typeUtils.getDeclaredType( + implementationType.getTypeElement(), + declaredType.getTypeArguments().toArray( new TypeMirror[] { } ) + ), + getTypeParameters( mirror ), + null, + implementationType.isIterableType(), + implementationType.isMapType(), + typeUtils, + elementUtils + ); + } + + return null; + } + + /** + * @param type1 first type + * @param type2 second type + * + * @return {@code true} if and only if the first type is assignable to the second + */ + public boolean isAssignable(Type type1, Type type2) { + if ( type1.equals( type2 ) ) { + return true; + } + + TypeMirror mirror1 = type1.getTypeMirror(); + TypeMirror mirror2 = type2.getTypeMirror(); + return null != mirror1 && null != mirror2 && typeUtils.isAssignable( mirror1, mirror2 ); + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/util/TypeUtil.java b/processor/src/main/java/org/mapstruct/ap/util/TypeUtil.java deleted file mode 100644 index 734c0c40a..000000000 --- a/processor/src/main/java/org/mapstruct/ap/util/TypeUtil.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright 2012-2013 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.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; - -import org.mapstruct.ap.model.Type; - -public class TypeUtil { - - private final Elements elementUtils; - private final Types typeUtils; - private final TypeMirror collectionType; - private final TypeMirror iterableType; - private final TypeMirror mapType; - - public TypeUtil(Elements elementUtils, Types typeUtils) { - this.elementUtils = elementUtils; - this.typeUtils = typeUtils; - collectionType = elementUtils.getTypeElement( Collection.class.getCanonicalName() ).asType(); - iterableType = elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType(); - mapType = elementUtils.getTypeElement( Map.class.getCanonicalName() ).asType(); - } - - public Type getType(DeclaredType type) { - List typeParameters = new ArrayList(); - - boolean isIterableType = isIterableType( type ); - for ( TypeMirror mirror : type.getTypeArguments() ) { - typeParameters.add( retrieveType( mirror ) ); - } - - return new Type( - ( (TypeElement) type.asElement() ).getQualifiedName().toString(), - elementUtils.getPackageOf( type.asElement() ).toString(), - type.asElement().getSimpleName().toString(), - type.asElement().getKind() == ElementKind.INTERFACE, - type.asElement().getKind() == ElementKind.ENUM, - isCollectionType( type ), - isIterableType, - isMapType( type ), - typeParameters - ); - } - - private boolean isIterableType(DeclaredType type) { - return typeUtils.isAssignable( typeUtils.erasure( type ), typeUtils.erasure( iterableType ) ); - } - - private boolean isCollectionType(DeclaredType type) { - return typeUtils.isAssignable( typeUtils.erasure( type ), typeUtils.erasure( collectionType ) ); - } - - private boolean isMapType(DeclaredType type) { - return typeUtils.isAssignable( typeUtils.erasure( type ), typeUtils.erasure( mapType ) ); - } - - public Type retrieveType(TypeMirror mirror) { - if ( mirror == null ) { - return null; - } - else if ( mirror.getKind() == TypeKind.DECLARED ) { - return getType( ( (DeclaredType) mirror ) ); - } - else if ( mirror.getKind() == TypeKind.VOID ) { - return Type.VOID; - } - else { - return new Type( mirror.toString() ); - } - } - - /** - * @param type1 first type - * @param type2 second type - * - * @return {@code true} if and only if the first type is assignable to the second - */ - public boolean isAssignable(Type type1, Type type2) { - if ( type1.equals( type2 ) ) { - return true; - } - - TypeMirror mirror1 = toTypeMirror( type1 ); - TypeMirror mirror2 = toTypeMirror( type2 ); - return null != mirror1 && null != mirror2 && typeUtils.isAssignable( mirror1, mirror2 ); - } - - private TypeMirror toTypeMirror(Type type) { - TypeElement rawType = elementUtils.getTypeElement( type.getCanonicalName() ); - - if ( null == rawType ) { - return null; - } - - TypeMirror[] parameters = new TypeMirror[type.getTypeParameters().size()]; - for ( int i = 0; i < type.getTypeParameters().size(); i++ ) { - parameters[i] = toTypeMirror( type.getTypeParameters().get( i ) ); - } - - return typeUtils.getDeclaredType( rawType, parameters ); - } -} diff --git a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl index 5950ac918..fa968c12e 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl @@ -28,7 +28,7 @@ ${resultName}.clear(); <#else> <#-- Use the interface type on the left side, except it is java.lang.Iterable; use the implementation type - if present - on the right side --> - <#if resultType.name == "Iterable" && resultType.packageName == "java.lang">${resultType.iterableImplementationType.name}<#else>${resultType.name}<<@includeModel object=resultType.typeParameters[0]/>> ${resultName} = new <#if resultType.iterableImplementationType??>${resultType.iterableImplementationType.name}<#else>${resultType.name}<<@includeModel object=resultType.typeParameters[0]/>>(); + <#if resultType.fullyQualifiedName == "java.lang.Iterable">${resultType.implementationType.name}<#else>${resultType.name}<<@includeModel object=resultType.typeParameters[0]/>> ${resultName} = new <#if resultType.implementationType??>${resultType.implementationType.name}<#else>${resultType.name}<<@includeModel object=resultType.typeParameters[0]/>>(); for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) { diff --git a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl index 3b00bc91c..2ed381a2d 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl @@ -27,7 +27,7 @@ <#if existingInstanceMapping> ${resultName}.clear(); <#else> - <@includeModel object=resultType /> ${resultName} = new <#if resultType.mapImplementationType??><@includeModel object=resultType.mapImplementationType /><#else><@includeModel object=resultType />(); + <@includeModel object=resultType /> ${resultName} = new <#if resultType.implementationType??><@includeModel object=resultType.implementationType /><#else><@includeModel object=resultType />(); for ( Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, > ${entryVariableName} : ${sourceParameter.name}.entrySet() ) { diff --git a/processor/src/main/resources/org.mapstruct.ap.model.Parameter.ftl b/processor/src/main/resources/org.mapstruct.ap.model.Parameter.ftl index 7bb3cf286..88bfeb039 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.Parameter.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.Parameter.ftl @@ -18,4 +18,4 @@ limitations under the License. --> -${type} ${name} \ No newline at end of file +<@includeModel object=type/> ${name} \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl b/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl index 8367291d2..05d97439c 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl @@ -32,9 +32,9 @@ <#-- c) simply set --> <#else> - <#if targetType.collectionType == true> + <#if targetType.implementationType??> if ( ${sourceBeanName}.${sourceAccessorName}() != null ) { - ${ext.targetBeanName}.${targetAccessorName}( new <#if targetType.collectionImplementationType??>${targetType.collectionImplementationType.name}<#else>${targetType.name}<#if targetType.elementType??><${targetType.elementType.name}>( ${sourceBeanName}.${sourceAccessorName}() ) ); + ${ext.targetBeanName}.${targetAccessorName}( new <#if targetType.implementationType??>${targetType.implementationType.name}<#else>${targetType.name}<#if targetType.elementType??><${targetType.elementType.name}>( ${sourceBeanName}.${sourceAccessorName}() ) ); } <#else> ${ext.targetBeanName}.${targetAccessorName}( ${sourceBeanName}.${sourceAccessorName}() );