mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#61 Refactoring Type into a wrapper around TypeMirror
This commit is contained in:
parent
86a8e72692
commit
585f944574
@ -20,6 +20,7 @@ package org.mapstruct.ap.conversion;
|
|||||||
|
|
||||||
import org.mapstruct.ap.model.Type;
|
import org.mapstruct.ap.model.Type;
|
||||||
import org.mapstruct.ap.model.TypeConversion;
|
import org.mapstruct.ap.model.TypeConversion;
|
||||||
|
import org.mapstruct.ap.util.TypeFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations create inline {@link TypeConversion}s such as
|
* Implementations create inline {@link TypeConversion}s such as
|
||||||
@ -80,5 +81,7 @@ public interface ConversionProvider {
|
|||||||
* @return The date format if this conversion.
|
* @return The date format if this conversion.
|
||||||
*/
|
*/
|
||||||
String getDateFormat();
|
String getDateFormat();
|
||||||
|
|
||||||
|
TypeFactory getTypeFactory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,10 @@ import java.math.BigInteger;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.lang.model.type.DeclaredType;
|
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Type;
|
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;
|
import static org.mapstruct.ap.conversion.ReverseConversion.reverse;
|
||||||
|
|
||||||
@ -38,16 +36,16 @@ import static org.mapstruct.ap.conversion.ReverseConversion.reverse;
|
|||||||
*/
|
*/
|
||||||
public class Conversions {
|
public class Conversions {
|
||||||
|
|
||||||
private TypeUtil typeUtil;
|
|
||||||
private final Map<Key, ConversionProvider> conversions = new HashMap<Conversions.Key, ConversionProvider>();
|
private final Map<Key, ConversionProvider> conversions = new HashMap<Conversions.Key, ConversionProvider>();
|
||||||
private final DeclaredType enumType;
|
private final Type enumType;
|
||||||
private final DeclaredType stringType;
|
private final Type stringType;
|
||||||
|
private final TypeFactory typeFactory;
|
||||||
|
|
||||||
public Conversions(Elements elementUtils, Types typeUtils, TypeUtil typeUtil) {
|
public Conversions(Elements elementUtils, TypeFactory typeFactory) {
|
||||||
this.typeUtil = typeUtil;
|
this.typeFactory = typeFactory;
|
||||||
|
|
||||||
this.enumType = typeUtils.getDeclaredType( elementUtils.getTypeElement( Enum.class.getCanonicalName() ) );
|
this.enumType = typeFactory.getType( Enum.class );
|
||||||
this.stringType = typeUtils.getDeclaredType( elementUtils.getTypeElement( String.class.getCanonicalName() ) );
|
this.stringType = typeFactory.getType( String.class );
|
||||||
|
|
||||||
//native types <> native types, including wrappers
|
//native types <> native types, including wrappers
|
||||||
registerNativeTypeConversion( byte.class, Byte.class );
|
registerNativeTypeConversion( byte.class, Byte.class );
|
||||||
@ -202,28 +200,32 @@ public class Conversions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void register(Class<?> sourceType, Class<?> targetType, ConversionProvider conversion) {
|
private void register(Class<?> sourceType, Class<?> targetType, ConversionProvider conversion) {
|
||||||
conversions.put( Key.forClasses( sourceType, targetType ), conversion );
|
conversions.put( forClasses( sourceType, targetType ), conversion );
|
||||||
conversions.put( Key.forClasses( targetType, sourceType ), reverse( conversion ) );
|
conversions.put( forClasses( targetType, sourceType ), reverse( conversion ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversionProvider getConversion(Type sourceType, Type targetType) {
|
public ConversionProvider getConversion(Type sourceType, Type targetType) {
|
||||||
if ( sourceType.isEnumType() && targetType.equals( typeUtil.getType( stringType ) ) ) {
|
if ( sourceType.isEnumType() && targetType.equals( stringType ) ) {
|
||||||
sourceType = typeUtil.getType( enumType );
|
sourceType = enumType;
|
||||||
}
|
}
|
||||||
else if ( targetType.isEnumType() && sourceType.equals( typeUtil.getType( stringType ) ) ) {
|
else if ( targetType.isEnumType() && sourceType.equals( stringType ) ) {
|
||||||
targetType = typeUtil.getType( enumType );
|
targetType = enumType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return conversions.get( new Key( sourceType, targetType ) );
|
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 static class Key {
|
||||||
private final Type sourceType;
|
private final Type sourceType;
|
||||||
private final Type targetType;
|
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) {
|
private Key(Type sourceType, Type targetType) {
|
||||||
this.sourceType = sourceType;
|
this.sourceType = sourceType;
|
||||||
@ -240,10 +242,8 @@ public class Conversions {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result
|
result = prime * result + ( ( sourceType == null ) ? 0 : sourceType.hashCode() );
|
||||||
+ ( ( sourceType == null ) ? 0 : sourceType.hashCode() );
|
result = prime * result + ( ( targetType == null ) ? 0 : targetType.hashCode() );
|
||||||
result = prime * result
|
|
||||||
+ ( ( targetType == null ) ? 0 : targetType.hashCode() );
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ public class DateToStringConversion implements ConversionProvider {
|
|||||||
@Override
|
@Override
|
||||||
public TypeConversion to(String sourceReference, Context conversionContext) {
|
public TypeConversion to(String sourceReference, Context conversionContext) {
|
||||||
return new TypeConversion(
|
return new TypeConversion(
|
||||||
asSet( Type.forClass( SimpleDateFormat.class ) ),
|
asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
|
||||||
Collections.<Type>emptyList(),
|
Collections.<Type>emptyList(),
|
||||||
getConversionString( sourceReference, conversionContext, "format" )
|
getConversionString( sourceReference, conversionContext, "format" )
|
||||||
);
|
);
|
||||||
@ -48,8 +48,8 @@ public class DateToStringConversion implements ConversionProvider {
|
|||||||
@Override
|
@Override
|
||||||
public TypeConversion from(String targetReference, Context conversionContext) {
|
public TypeConversion from(String targetReference, Context conversionContext) {
|
||||||
return new TypeConversion(
|
return new TypeConversion(
|
||||||
asSet( Type.forClass( SimpleDateFormat.class ) ),
|
asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
|
||||||
Arrays.asList( Type.forClass( ParseException.class ) ),
|
Arrays.asList( conversionContext.getTypeFactory().getType( ParseException.class ) ),
|
||||||
getConversionString( targetReference, conversionContext, "parse" )
|
getConversionString( targetReference, conversionContext, "parse" )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package org.mapstruct.ap.conversion;
|
|||||||
|
|
||||||
import org.mapstruct.ap.conversion.ConversionProvider.Context;
|
import org.mapstruct.ap.conversion.ConversionProvider.Context;
|
||||||
import org.mapstruct.ap.model.Type;
|
import org.mapstruct.ap.model.Type;
|
||||||
|
import org.mapstruct.ap.util.TypeFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the {@link Context} passed to conversion providers.
|
* 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 Type targetType;
|
||||||
private final String format;
|
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.targetType = targetType;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
}
|
}
|
||||||
@ -45,4 +48,9 @@ public class DefaultConversionContext implements ConversionProvider.Context {
|
|||||||
public String getDateFormat() {
|
public String getDateFormat() {
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeFactory getTypeFactory() {
|
||||||
|
return typeFactory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import java.util.SortedSet;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import javax.annotation.Generated;
|
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
|
* Represents a type implementing a mapper interface (annotated with {@code @Mapper}. This is the root object of the
|
||||||
* mapper model.
|
* mapper model.
|
||||||
@ -33,6 +35,7 @@ import javax.annotation.Generated;
|
|||||||
*/
|
*/
|
||||||
public class Mapper extends AbstractModelElement {
|
public class Mapper extends AbstractModelElement {
|
||||||
|
|
||||||
|
private final TypeFactory typeFactory;
|
||||||
private final String packageName;
|
private final String packageName;
|
||||||
private final String interfaceName;
|
private final String interfaceName;
|
||||||
private final String implementationName;
|
private final String implementationName;
|
||||||
@ -41,7 +44,7 @@ public class Mapper extends AbstractModelElement {
|
|||||||
private final List<MapperReference> referencedMappers;
|
private final List<MapperReference> referencedMappers;
|
||||||
private final Options options;
|
private final Options options;
|
||||||
|
|
||||||
public Mapper(String packageName, String interfaceName, String implementationName,
|
public Mapper(TypeFactory typeFactory, String packageName, String interfaceName, String implementationName,
|
||||||
List<MappingMethod> mappingMethods, List<MapperReference> referencedMappers, Options options) {
|
List<MappingMethod> mappingMethods, List<MapperReference> referencedMappers, Options options) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.interfaceName = interfaceName;
|
this.interfaceName = interfaceName;
|
||||||
@ -50,12 +53,13 @@ public class Mapper extends AbstractModelElement {
|
|||||||
this.mappingMethods = mappingMethods;
|
this.mappingMethods = mappingMethods;
|
||||||
this.referencedMappers = referencedMappers;
|
this.referencedMappers = referencedMappers;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.typeFactory = typeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SortedSet<Type> getImportTypes() {
|
public SortedSet<Type> getImportTypes() {
|
||||||
SortedSet<Type> importedTypes = new TreeSet<Type>();
|
SortedSet<Type> importedTypes = new TreeSet<Type>();
|
||||||
importedTypes.add( Type.forClass( Generated.class ) );
|
importedTypes.add( typeFactory.getType( Generated.class ) );
|
||||||
|
|
||||||
for ( MappingMethod mappingMethod : mappingMethods ) {
|
for ( MappingMethod mappingMethod : mappingMethods ) {
|
||||||
for ( Type type : mappingMethod.getImportTypes() ) {
|
for ( Type type : mappingMethod.getImportTypes() ) {
|
||||||
@ -87,9 +91,7 @@ public class Mapper extends AbstractModelElement {
|
|||||||
collection.add( typeToAdd );
|
collection.add( typeToAdd );
|
||||||
}
|
}
|
||||||
|
|
||||||
addWithDependents( collection, typeToAdd.getCollectionImplementationType() );
|
addWithDependents( collection, typeToAdd.getImplementationType() );
|
||||||
addWithDependents( collection, typeToAdd.getIterableImplementationType() );
|
|
||||||
addWithDependents( collection, typeToAdd.getMapImplementationType() );
|
|
||||||
|
|
||||||
for ( Type type : typeToAdd.getTypeParameters() ) {
|
for ( Type type : typeToAdd.getTypeParameters() ) {
|
||||||
addWithDependents( collection, type );
|
addWithDependents( collection, type );
|
||||||
|
@ -92,6 +92,7 @@ public abstract class MappingMethod extends AbstractModelElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
types.add( getReturnType() );
|
types.add( getReturnType() );
|
||||||
|
types.addAll( getReturnType().getImportTypes() );
|
||||||
|
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
@ -18,176 +18,88 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.NavigableMap;
|
|
||||||
import java.util.NavigableSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
import javax.lang.model.element.ElementKind;
|
||||||
import java.util.SortedSet;
|
import javax.lang.model.element.TypeElement;
|
||||||
import java.util.TreeMap;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import java.util.TreeSet;
|
import javax.lang.model.type.TypeKind;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import javax.lang.model.util.Elements;
|
||||||
import java.util.concurrent.ConcurrentNavigableMap;
|
import javax.lang.model.util.SimpleElementVisitor6;
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
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<String>} and {@code Set<Integer>}.
|
||||||
|
* <p>
|
||||||
|
* Allows for a unified handling of declared and primitive types and usage within templates. Instances are obtained
|
||||||
|
* through {@link TypeFactory}.
|
||||||
*
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class Type extends AbstractModelElement implements Comparable<Type> {
|
public class Type extends AbstractModelElement implements Comparable<Type> {
|
||||||
/**
|
|
||||||
* Type representing {@code void}
|
|
||||||
*/
|
|
||||||
public static final Type VOID = new Type( "void" );
|
|
||||||
|
|
||||||
private static final Set<String> PRIMITIVE_TYPE_NAMES = new HashSet<String>(
|
|
||||||
Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" )
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final ConcurrentMap<String, Type> DEFAULT_ITERABLE_IMPLEMENTATION_TYPES =
|
|
||||||
new ConcurrentHashMap<String, Type>();
|
|
||||||
private static final ConcurrentMap<String, Type> DEFAULT_COLLECTION_IMPLEMENTATION_TYPES =
|
|
||||||
new ConcurrentHashMap<String, Type>();
|
|
||||||
private static final ConcurrentMap<String, Type> DEFAULT_MAP_IMPLEMENTATION_TYPES =
|
|
||||||
new ConcurrentHashMap<String, Type>();
|
|
||||||
|
|
||||||
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 packageName;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final String qualifiedName;
|
||||||
private final List<Type> typeParameters;
|
private final List<Type> typeParameters;
|
||||||
private final boolean isInterface;
|
private final boolean isInterface;
|
||||||
private final boolean isEnumType;
|
private final boolean isEnumType;
|
||||||
private final boolean isCollectionType;
|
|
||||||
private final boolean isIterableType;
|
private final boolean isIterableType;
|
||||||
private final boolean isMapType;
|
private final boolean isMapType;
|
||||||
private final Type collectionImplementationType;
|
private final Type implementationType;
|
||||||
private final Type iterableImplementationType;
|
private final TypeMirror typeMirror;
|
||||||
private final Type mapImplementationType;
|
private final Types typeUtils;
|
||||||
|
private final TypeElement typeElement;
|
||||||
|
|
||||||
public static Type forClass(Class<?> clazz) {
|
public Type(TypeMirror typeMirror, List<Type> typeParameters, Type implementationType, boolean isIterableType,
|
||||||
Package pakkage = clazz.getPackage();
|
boolean isMapType,
|
||||||
|
Types typeUtils, Elements elementUtils) {
|
||||||
if ( pakkage != null ) {
|
this.typeMirror = typeMirror;
|
||||||
return new Type(
|
this.implementationType = implementationType;
|
||||||
clazz.getCanonicalName(),
|
this.typeParameters = typeParameters;
|
||||||
pakkage.getName(),
|
|
||||||
clazz.getSimpleName(),
|
|
||||||
clazz.isInterface(),
|
|
||||||
clazz.isEnum(),
|
|
||||||
Collection.class.isAssignableFrom( clazz ),
|
|
||||||
Iterable.class.isAssignableFrom( clazz ),
|
|
||||||
Map.class.isAssignableFrom( clazz ),
|
|
||||||
Collections.<Type>emptyList()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new Type( clazz.getSimpleName() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type(String name) {
|
|
||||||
this( name, null, name, false, false, false, false, false, Collections.<Type>emptyList() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type(String packageName, String name) {
|
|
||||||
this(
|
|
||||||
packageName + "." + name,
|
|
||||||
packageName,
|
|
||||||
name,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
Collections.<Type>emptyList()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type(String canonicalName, String packageName, String name, boolean isInterface, boolean isEnumType,
|
|
||||||
boolean isCollectionType,
|
|
||||||
boolean isIterableType, boolean isMapType, List<Type> typeParameters) {
|
|
||||||
this.canonicalName = canonicalName;
|
|
||||||
this.packageName = packageName;
|
|
||||||
this.name = name;
|
|
||||||
this.isInterface = isInterface;
|
|
||||||
this.isEnumType = isEnumType;
|
|
||||||
this.isCollectionType = isCollectionType;
|
|
||||||
this.isIterableType = isIterableType;
|
this.isIterableType = isIterableType;
|
||||||
this.isMapType = isMapType;
|
this.isMapType = isMapType;
|
||||||
this.typeParameters = typeParameters;
|
this.typeUtils = typeUtils;
|
||||||
|
|
||||||
if ( isCollectionType ) {
|
DeclaredType declaredType = typeMirror.getKind() == TypeKind.DECLARED ? (DeclaredType) typeMirror : null;
|
||||||
collectionImplementationType = DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.get( packageName + "." + name );
|
|
||||||
|
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 {
|
else {
|
||||||
collectionImplementationType = null;
|
packageName = null;
|
||||||
|
qualifiedName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isIterableType ) {
|
|
||||||
iterableImplementationType = DEFAULT_ITERABLE_IMPLEMENTATION_TYPES.get( packageName + "." + name );
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iterableImplementationType = null;
|
isEnumType = false;
|
||||||
}
|
isInterface = false;
|
||||||
|
typeElement = null;
|
||||||
if ( isMapType ) {
|
name = typeMirror.toString();
|
||||||
Type mapType = DEFAULT_MAP_IMPLEMENTATION_TYPES.get( packageName + "." + name );
|
packageName = null;
|
||||||
mapImplementationType = mapType != null ? new Type(
|
qualifiedName = name;
|
||||||
mapType.getPackageName() + "." + mapType.getName(),
|
|
||||||
mapType.getPackageName(),
|
|
||||||
mapType.getName(),
|
|
||||||
mapType.isInterface(),
|
|
||||||
mapType.isEnumType(),
|
|
||||||
mapType.isCollectionType(),
|
|
||||||
mapType.isIterableType(),
|
|
||||||
true,
|
|
||||||
typeParameters
|
|
||||||
) : null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mapImplementationType = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCanonicalName() {
|
public TypeMirror getTypeMirror() {
|
||||||
return canonicalName;
|
return typeMirror;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeElement getTypeElement() {
|
||||||
|
return typeElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
@ -203,7 +115,7 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrimitive() {
|
public boolean isPrimitive() {
|
||||||
return packageName == null && PRIMITIVE_TYPE_NAMES.contains( name );
|
return typeMirror.getKind().isPrimitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInterface() {
|
public boolean isInterface() {
|
||||||
@ -214,26 +126,8 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
return isEnumType;
|
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() {
|
public Type getImplementationType() {
|
||||||
return collectionImplementationType != null ? collectionImplementationType :
|
return implementationType;
|
||||||
iterableImplementationType != null ? iterableImplementationType :
|
|
||||||
mapImplementationType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIterableType() {
|
public boolean isIterableType() {
|
||||||
@ -245,12 +139,13 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getFullyQualifiedName() {
|
public String getFullyQualifiedName() {
|
||||||
return packageName == null ? name : packageName + "." + name;
|
return qualifiedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Type> getImportTypes() {
|
public Set<Type> getImportTypes() {
|
||||||
return Collections.emptySet();
|
return implementationType != null ? org.mapstruct.ap.util.Collections.<Type>asSet( implementationType ) :
|
||||||
|
Collections.<Type>emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -259,7 +154,6 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
|
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
|
||||||
result = prime * result + ( ( packageName == null ) ? 0 : packageName.hashCode() );
|
result = prime * result + ( ( packageName == null ) ? 0 : packageName.hashCode() );
|
||||||
result = prime * result + ( ( typeParameters == null ) ? 0 : typeParameters.hashCode() );
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,31 +169,8 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Type other = (Type) obj;
|
Type other = (Type) obj;
|
||||||
if ( name == null ) {
|
|
||||||
if ( other.name != null ) {
|
return typeUtils.isSameType( typeMirror, other.typeMirror );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -309,11 +180,13 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if ( !typeParameters.isEmpty() ) {
|
return typeMirror.toString();
|
||||||
return name + "<" + Strings.join( typeParameters, ", " ) + ">";
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return name;
|
private static class TypeElementRetrievalVisitor extends SimpleElementVisitor6<TypeElement, Void> {
|
||||||
|
@Override
|
||||||
|
public TypeElement visitType(TypeElement e, Void p) {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import org.mapstruct.ap.model.AnnotationMapperReference;
|
|||||||
import org.mapstruct.ap.model.Mapper;
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.MapperReference;
|
import org.mapstruct.ap.model.MapperReference;
|
||||||
import org.mapstruct.ap.util.OptionsHelper;
|
import org.mapstruct.ap.util.OptionsHelper;
|
||||||
|
import org.mapstruct.ap.util.TypeFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link ModelElementProcessor} which converts the given {@link Mapper}
|
* 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<Mapper, Mapper> {
|
public abstract class AnnotationBasedComponentModelProcessor implements ModelElementProcessor<Mapper, Mapper> {
|
||||||
|
|
||||||
|
private TypeFactory typeFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) {
|
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) {
|
||||||
|
this.typeFactory = context.getTypeFactory();
|
||||||
|
|
||||||
String componentModel = MapperPrism.getInstanceOn( mapperTypeElement ).componentModel();
|
String componentModel = MapperPrism.getInstanceOn( mapperTypeElement ).componentModel();
|
||||||
String effectiveComponentModel = OptionsHelper.getEffectiveComponentModel(
|
String effectiveComponentModel = OptionsHelper.getEffectiveComponentModel(
|
||||||
context.getOptions(),
|
context.getOptions(),
|
||||||
@ -68,7 +73,10 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
|
|||||||
* @return the mapper reference replacing the original one
|
* @return the mapper reference replacing the original one
|
||||||
*/
|
*/
|
||||||
protected MapperReference replacementMapperReference(MapperReference originalReference) {
|
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() {
|
public int getPriority() {
|
||||||
return 1100;
|
return 1100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TypeFactory getTypeFactory() {
|
||||||
|
return typeFactory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.processor;
|
|||||||
|
|
||||||
import org.mapstruct.ap.model.Annotation;
|
import org.mapstruct.ap.model.Annotation;
|
||||||
import org.mapstruct.ap.model.Mapper;
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.Type;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||||
@ -38,11 +37,11 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Annotation getTypeAnnotation() {
|
protected Annotation getTypeAnnotation() {
|
||||||
return new Annotation( new Type( "javax.enterprise.context", "ApplicationScoped" ) );
|
return new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Annotation getMapperReferenceAnnotation() {
|
protected Annotation getMapperReferenceAnnotation() {
|
||||||
return new Annotation( new Type( "javax.inject", "Inject" ) );
|
return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import javax.lang.model.util.Types;
|
|||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Options;
|
import org.mapstruct.ap.model.Options;
|
||||||
|
import org.mapstruct.ap.util.TypeFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the processor context.
|
* Default implementation of the processor context.
|
||||||
@ -40,10 +41,15 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso
|
|||||||
private final ProcessingEnvironment processingEnvironment;
|
private final ProcessingEnvironment processingEnvironment;
|
||||||
private final DelegatingMessager messager;
|
private final DelegatingMessager messager;
|
||||||
private final Options options;
|
private final Options options;
|
||||||
|
private final TypeFactory typeFactory;
|
||||||
|
|
||||||
public DefaultModelElementProcessorContext(ProcessingEnvironment processingEnvironment, Options options) {
|
public DefaultModelElementProcessorContext(ProcessingEnvironment processingEnvironment, Options options) {
|
||||||
this.processingEnvironment = processingEnvironment;
|
this.processingEnvironment = processingEnvironment;
|
||||||
this.messager = new DelegatingMessager( processingEnvironment.getMessager() );
|
this.messager = new DelegatingMessager( processingEnvironment.getMessager() );
|
||||||
|
this.typeFactory = new TypeFactory(
|
||||||
|
processingEnvironment.getElementUtils(),
|
||||||
|
processingEnvironment.getTypeUtils()
|
||||||
|
);
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +68,11 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso
|
|||||||
return processingEnvironment.getElementUtils();
|
return processingEnvironment.getElementUtils();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeFactory getTypeFactory() {
|
||||||
|
return typeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Messager getMessager() {
|
public Messager getMessager() {
|
||||||
return messager;
|
return messager;
|
||||||
@ -86,6 +97,7 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso
|
|||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void printMessage(Kind kind, CharSequence msg) {
|
public void printMessage(Kind kind, CharSequence msg) {
|
||||||
delegate.printMessage( kind, msg );
|
delegate.printMessage( kind, msg );
|
||||||
if ( kind == Kind.ERROR ) {
|
if ( kind == Kind.ERROR ) {
|
||||||
@ -93,6 +105,7 @@ public class DefaultModelElementProcessorContext implements ModelElementProcesso
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void printMessage(Kind kind, CharSequence msg, Element e) {
|
public void printMessage(Kind kind, CharSequence msg, Element e) {
|
||||||
delegate.printMessage( kind, msg, e );
|
delegate.printMessage( kind, msg, e );
|
||||||
if ( kind == Kind.ERROR ) {
|
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) {
|
public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) {
|
||||||
delegate.printMessage( kind, msg, e, a );
|
delegate.printMessage( kind, msg, e, a );
|
||||||
if ( kind == Kind.ERROR ) {
|
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) {
|
public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) {
|
||||||
delegate.printMessage( kind, msg, e, a, v );
|
delegate.printMessage( kind, msg, e, a, v );
|
||||||
if ( kind == Kind.ERROR ) {
|
if ( kind == Kind.ERROR ) {
|
||||||
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.processor;
|
|||||||
|
|
||||||
import org.mapstruct.ap.model.Annotation;
|
import org.mapstruct.ap.model.Annotation;
|
||||||
import org.mapstruct.ap.model.Mapper;
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.Type;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||||
@ -38,11 +37,11 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Annotation getTypeAnnotation() {
|
protected Annotation getTypeAnnotation() {
|
||||||
return new Annotation( new Type( "javax.inject", "Named" ) );
|
return new Annotation( getTypeFactory().getType( "javax.inject.Named" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Annotation getMapperReferenceAnnotation() {
|
protected Annotation getMapperReferenceAnnotation() {
|
||||||
return new Annotation( new Type( "javax.inject", "Inject" ) );
|
return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,9 @@ import java.util.Set;
|
|||||||
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;
|
||||||
|
import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.mapstruct.ap.MapperPrism;
|
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.Executables;
|
||||||
import org.mapstruct.ap.util.Filters;
|
import org.mapstruct.ap.util.Filters;
|
||||||
import org.mapstruct.ap.util.Strings;
|
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
|
* A {@link ModelElementProcessor} which creates a {@link Mapper} from the given
|
||||||
@ -71,24 +71,24 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
private static final String IMPLEMENTATION_SUFFIX = "Impl";
|
private static final String IMPLEMENTATION_SUFFIX = "Impl";
|
||||||
|
|
||||||
private Elements elementUtils;
|
private Elements elementUtils;
|
||||||
private Types typeUtils;
|
|
||||||
private Messager messager;
|
private Messager messager;
|
||||||
private Options options;
|
private Options options;
|
||||||
|
|
||||||
private TypeUtil typeUtil;
|
private TypeFactory typeFactory;
|
||||||
private Conversions conversions;
|
private Conversions conversions;
|
||||||
private Executables executables;
|
private Executables executables;
|
||||||
|
private Filters filters;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<Method> sourceModel) {
|
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<Method> sourceModel) {
|
||||||
this.elementUtils = context.getElementUtils();
|
this.elementUtils = context.getElementUtils();
|
||||||
this.typeUtils = context.getTypeUtils();
|
|
||||||
this.messager = context.getMessager();
|
this.messager = context.getMessager();
|
||||||
this.options = context.getOptions();
|
this.options = context.getOptions();
|
||||||
|
|
||||||
this.typeUtil = new TypeUtil( context.getElementUtils(), context.getTypeUtils() );
|
this.typeFactory = context.getTypeFactory();
|
||||||
this.conversions = new Conversions( elementUtils, typeUtils, typeUtil );
|
this.conversions = new Conversions( elementUtils, typeFactory );
|
||||||
this.executables = new Executables( typeUtil );
|
this.executables = new Executables( typeFactory );
|
||||||
|
this.filters = new Filters( executables );
|
||||||
|
|
||||||
return getMapper( mapperTypeElement, sourceModel );
|
return getMapper( mapperTypeElement, sourceModel );
|
||||||
}
|
}
|
||||||
@ -104,6 +104,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
List<MapperReference> mapperReferences = getReferencedMappers( element );
|
List<MapperReference> mapperReferences = getReferencedMappers( element );
|
||||||
|
|
||||||
return new Mapper(
|
return new Mapper(
|
||||||
|
typeFactory,
|
||||||
elementUtils.getPackageOf( element ).getQualifiedName().toString(),
|
elementUtils.getPackageOf( element ).getQualifiedName().toString(),
|
||||||
element.getSimpleName().toString(),
|
element.getSimpleName().toString(),
|
||||||
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
|
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
|
||||||
@ -143,7 +144,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
|
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
|
||||||
|
|
||||||
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
||||||
mapperReferences.add( new DefaultMapperReference( typeUtil.retrieveType( usedMapper ) ) );
|
mapperReferences.add( new DefaultMapperReference( typeFactory.getType( usedMapper ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapperReferences;
|
return mapperReferences;
|
||||||
@ -191,7 +192,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) {
|
private void reportErrorIfNoImplementationTypeIsRegisteredForInterfaceReturnType(Method method) {
|
||||||
if ( method.getReturnType() != Type.VOID && method.getReturnType().isInterface() &&
|
if ( method.getReturnType().getTypeMirror().getKind() != TypeKind.VOID &&
|
||||||
|
method.getReturnType().isInterface() &&
|
||||||
method.getReturnType().getImplementationType() == null ) {
|
method.getReturnType().getImplementationType() == null ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
Kind.ERROR,
|
Kind.ERROR,
|
||||||
@ -219,8 +221,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
Mapping mapping = method.getMapping( targetPropertyName );
|
Mapping mapping = method.getMapping( targetPropertyName );
|
||||||
String dateFormat = mapping != null ? mapping.getDateFormat() : null;
|
String dateFormat = mapping != null ? mapping.getDateFormat() : null;
|
||||||
String sourcePropertyName = mapping != null ? mapping.getSourcePropertyName() : targetPropertyName;
|
String sourcePropertyName = mapping != null ? mapping.getSourcePropertyName() : targetPropertyName;
|
||||||
TypeElement parameterElement = elementUtils.getTypeElement( parameter.getType().getCanonicalName() );
|
TypeElement parameterElement = parameter.getType().getTypeElement();
|
||||||
List<ExecutableElement> sourceGetters = Filters.getterMethodsIn(
|
List<ExecutableElement> sourceGetters = filters.getterMethodsIn(
|
||||||
elementUtils.getAllMembers( parameterElement )
|
elementUtils.getAllMembers( parameterElement )
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -252,8 +254,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeElement resultTypeElement = elementUtils.getTypeElement( method.getResultType().getCanonicalName() );
|
TypeElement resultTypeElement = method.getResultType().getTypeElement();
|
||||||
List<ExecutableElement> targetSetters = Filters.setterMethodsIn(
|
List<ExecutableElement> targetSetters = filters.setterMethodsIn(
|
||||||
elementUtils.getAllMembers( resultTypeElement )
|
elementUtils.getAllMembers( resultTypeElement )
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -348,8 +350,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasProperty(Parameter parameter, String propertyName) {
|
private boolean hasProperty(Parameter parameter, String propertyName) {
|
||||||
TypeElement parameterTypeElement = elementUtils.getTypeElement( parameter.getType().getCanonicalName() );
|
TypeElement parameterTypeElement = parameter.getType().getTypeElement();
|
||||||
List<ExecutableElement> getters = Filters.setterMethodsIn(
|
List<ExecutableElement> getters = filters.setterMethodsIn(
|
||||||
elementUtils.getAllMembers( parameterTypeElement )
|
elementUtils.getAllMembers( parameterTypeElement )
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -357,8 +359,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean reportErrorIfMappedPropertiesDontExist(Method method) {
|
private boolean reportErrorIfMappedPropertiesDontExist(Method method) {
|
||||||
TypeElement resultTypeElement = elementUtils.getTypeElement( method.getResultType().getCanonicalName() );
|
TypeElement resultTypeElement = method.getResultType().getTypeElement();
|
||||||
List<ExecutableElement> targetSetters = Filters.setterMethodsIn(
|
List<ExecutableElement> targetSetters = filters.setterMethodsIn(
|
||||||
elementUtils.getAllMembers( resultTypeElement )
|
elementUtils.getAllMembers( resultTypeElement )
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -528,7 +530,10 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return conversionProvider.to( sourceReference, new DefaultConversionContext( targetType, dateFormat ) );
|
return conversionProvider.to(
|
||||||
|
sourceReference,
|
||||||
|
new DefaultConversionContext( typeFactory, targetType, dateFormat )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingMethodReference getMappingMethodReference(Iterable<Method> methods, Type parameterType,
|
private MappingMethodReference getMappingMethodReference(Iterable<Method> methods, Type parameterType,
|
||||||
@ -540,8 +545,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
|
|
||||||
Parameter singleSourceParam = method.getSourceParameters().iterator().next();
|
Parameter singleSourceParam = method.getSourceParameters().iterator().next();
|
||||||
|
|
||||||
if ( singleSourceParam.getType().equals( parameterType ) &&
|
if ( singleSourceParam.getType().equals( parameterType ) && method.getResultType().equals( returnType ) ) {
|
||||||
method.getResultType().equals( returnType ) ) {
|
|
||||||
return new MappingMethodReference( method );
|
return new MappingMethodReference( method );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,8 +565,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
if ( property.getSourceType().equals( property.getTargetType() ) ||
|
if ( property.getSourceType().equals( property.getTargetType() ) ||
|
||||||
property.getMappingMethod() != null ||
|
property.getMappingMethod() != null ||
|
||||||
property.getConversion() != null ||
|
property.getConversion() != null ||
|
||||||
( property.getTargetType().isCollectionType() &&
|
property.getTargetType().getImplementationType() != null ) {
|
||||||
property.getTargetType().getCollectionImplementationType() != null ) ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ 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;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.Types;
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.mapstruct.ap.IterableMappingPrism;
|
import org.mapstruct.ap.IterableMappingPrism;
|
||||||
@ -42,7 +42,7 @@ import org.mapstruct.ap.model.source.MapMapping;
|
|||||||
import org.mapstruct.ap.model.source.Mapping;
|
import org.mapstruct.ap.model.source.Mapping;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
import org.mapstruct.ap.util.Executables;
|
import org.mapstruct.ap.util.Executables;
|
||||||
import org.mapstruct.ap.util.TypeUtil;
|
import org.mapstruct.ap.util.TypeFactory;
|
||||||
|
|
||||||
import static javax.lang.model.util.ElementFilter.methodsIn;
|
import static javax.lang.model.util.ElementFilter.methodsIn;
|
||||||
|
|
||||||
@ -57,16 +57,14 @@ import static javax.lang.model.util.ElementFilter.methodsIn;
|
|||||||
public class MethodRetrievalProcessor implements ModelElementProcessor<Void, List<Method>> {
|
public class MethodRetrievalProcessor implements ModelElementProcessor<Void, List<Method>> {
|
||||||
|
|
||||||
private Messager messager;
|
private Messager messager;
|
||||||
private Types typeUtils;
|
private TypeFactory typeFactory;
|
||||||
private TypeUtil typeUtil;
|
|
||||||
private Executables executables;
|
private Executables executables;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Method> process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) {
|
public List<Method> process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) {
|
||||||
this.messager = context.getMessager();
|
this.messager = context.getMessager();
|
||||||
this.typeUtils = context.getTypeUtils();
|
this.typeFactory = context.getTypeFactory();
|
||||||
this.typeUtil = new TypeUtil( context.getElementUtils(), typeUtils );
|
this.executables = new Executables( typeFactory );
|
||||||
this.executables = new Executables( typeUtil );
|
|
||||||
|
|
||||||
return retrieveMethods( mapperTypeElement, true );
|
return retrieveMethods( mapperTypeElement, true );
|
||||||
}
|
}
|
||||||
@ -146,7 +144,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
else if ( parameters.size() == 1 ) {
|
else if ( parameters.size() == 1 ) {
|
||||||
return
|
return
|
||||||
Method.forReferencedMethod(
|
Method.forReferencedMethod(
|
||||||
typeUtil.getType( typeUtils.getDeclaredType( element ) ),
|
typeFactory.getType( element ),
|
||||||
method,
|
method,
|
||||||
parameters,
|
parameters,
|
||||||
returnType
|
returnType
|
||||||
@ -203,12 +201,13 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( resultType == Type.VOID ) {
|
if ( resultType.getTypeMirror().getKind() == TypeKind.VOID ) {
|
||||||
messager.printMessage( Kind.ERROR, "Can't generate mapping method with return type void.", method );
|
messager.printMessage( Kind.ERROR, "Can't generate mapping method with return type void.", method );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( returnType != Type.VOID && !typeUtil.isAssignable( resultType, returnType ) ) {
|
if ( returnType.getTypeMirror().getKind() != TypeKind.VOID &&
|
||||||
|
!typeFactory.isAssignable( resultType, returnType ) ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
Kind.ERROR,
|
Kind.ERROR,
|
||||||
"The result type is not assignable to the the return type.",
|
"The result type is not assignable to the the return type.",
|
||||||
|
@ -26,6 +26,7 @@ import javax.lang.model.util.Types;
|
|||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Options;
|
import org.mapstruct.ap.model.Options;
|
||||||
|
import org.mapstruct.ap.util.TypeFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A processor which performs one task of the mapper generation, e.g. retrieving
|
* A processor which performs one task of the mapper generation, e.g. retrieving
|
||||||
@ -55,6 +56,8 @@ public interface ModelElementProcessor<P, R> {
|
|||||||
|
|
||||||
Elements getElementUtils();
|
Elements getElementUtils();
|
||||||
|
|
||||||
|
TypeFactory getTypeFactory();
|
||||||
|
|
||||||
Messager getMessager();
|
Messager getMessager();
|
||||||
|
|
||||||
Options getOptions();
|
Options getOptions();
|
||||||
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.processor;
|
|||||||
|
|
||||||
import org.mapstruct.ap.model.Annotation;
|
import org.mapstruct.ap.model.Annotation;
|
||||||
import org.mapstruct.ap.model.Mapper;
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.Type;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||||
@ -38,11 +37,11 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Annotation getTypeAnnotation() {
|
protected Annotation getTypeAnnotation() {
|
||||||
return new Annotation( new Type( "org.springframework.stereotype", "Component" ) );
|
return new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Annotation getMapperReferenceAnnotation() {
|
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" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,10 @@ import org.mapstruct.ap.model.Type;
|
|||||||
*/
|
*/
|
||||||
public class Executables {
|
public class Executables {
|
||||||
|
|
||||||
private final TypeUtil typeUtil;
|
private final TypeFactory typeFactory;
|
||||||
|
|
||||||
public Executables(TypeUtil typeUtil) {
|
public Executables(TypeFactory typeFactory) {
|
||||||
this.typeUtil = typeUtil;
|
this.typeFactory = typeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGetterMethod(ExecutableElement method) {
|
public boolean isGetterMethod(ExecutableElement method) {
|
||||||
@ -119,7 +119,7 @@ public class Executables {
|
|||||||
|
|
||||||
return new Parameter(
|
return new Parameter(
|
||||||
parameter.getSimpleName().toString(),
|
parameter.getSimpleName().toString(),
|
||||||
typeUtil.retrieveType( parameter.asType() ),
|
typeFactory.getType( parameter.asType() ),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ public class Executables {
|
|||||||
.add(
|
.add(
|
||||||
new Parameter(
|
new Parameter(
|
||||||
parameter.getSimpleName().toString(),
|
parameter.getSimpleName().toString(),
|
||||||
typeUtil.retrieveType( parameter.asType() ),
|
typeFactory.getType( parameter.asType() ),
|
||||||
MappingTargetPrism.getInstanceOn( parameter ) != null
|
MappingTargetPrism.getInstanceOn( parameter ) != null
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -143,6 +143,6 @@ public class Executables {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Type retrieveReturnType(ExecutableElement method) {
|
public Type retrieveReturnType(ExecutableElement method) {
|
||||||
return typeUtil.retrieveType( method.getReturnType() );
|
return typeFactory.getType( method.getReturnType() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,13 @@ import static javax.lang.model.util.ElementFilter.methodsIn;
|
|||||||
*/
|
*/
|
||||||
public class Filters {
|
public class Filters {
|
||||||
|
|
||||||
//TODO
|
private final Executables executables;
|
||||||
private static Executables executables = new Executables( null );
|
|
||||||
|
|
||||||
private Filters() {
|
public Filters(Executables executables) {
|
||||||
|
this.executables = executables;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ExecutableElement> getterMethodsIn(Iterable<? extends Element> elements) {
|
public List<ExecutableElement> getterMethodsIn(Iterable<? extends Element> elements) {
|
||||||
List<ExecutableElement> getterMethods = new LinkedList<ExecutableElement>();
|
List<ExecutableElement> getterMethods = new LinkedList<ExecutableElement>();
|
||||||
|
|
||||||
for ( ExecutableElement method : methodsIn( elements ) ) {
|
for ( ExecutableElement method : methodsIn( elements ) ) {
|
||||||
@ -50,7 +50,7 @@ public class Filters {
|
|||||||
return getterMethods;
|
return getterMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ExecutableElement> setterMethodsIn(Iterable<? extends Element> elements) {
|
public List<ExecutableElement> setterMethodsIn(Iterable<? extends Element> elements) {
|
||||||
List<ExecutableElement> setterMethods = new LinkedList<ExecutableElement>();
|
List<ExecutableElement> setterMethods = new LinkedList<ExecutableElement>();
|
||||||
|
|
||||||
for ( ExecutableElement method : methodsIn( elements ) ) {
|
for ( ExecutableElement method : methodsIn( elements ) ) {
|
||||||
|
192
processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java
Normal file
192
processor/src/main/java/org/mapstruct/ap/util/TypeFactory.java
Normal file
@ -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<String, Type> implementationTypes = new HashMap<String, Type>();
|
||||||
|
|
||||||
|
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<Type> getTypeParameters(TypeMirror mirror) {
|
||||||
|
if ( mirror.getKind() != TypeKind.DECLARED ) {
|
||||||
|
return java.util.Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclaredType declaredType = (DeclaredType) mirror;
|
||||||
|
ArrayList<Type> typeParameters = new ArrayList<Type>( 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 );
|
||||||
|
}
|
||||||
|
}
|
@ -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<Type> typeParameters = new ArrayList<Type>();
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,7 @@
|
|||||||
${resultName}.clear();
|
${resultName}.clear();
|
||||||
<#else>
|
<#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 -->
|
<#-- 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}</#if><<@includeModel object=resultType.typeParameters[0]/>> ${resultName} = new <#if resultType.iterableImplementationType??>${resultType.iterableImplementationType.name}<#else>${resultType.name}</#if><<@includeModel object=resultType.typeParameters[0]/>>();
|
<#if resultType.fullyQualifiedName == "java.lang.Iterable">${resultType.implementationType.name}<#else>${resultType.name}</#if><<@includeModel object=resultType.typeParameters[0]/>> ${resultName} = new <#if resultType.implementationType??>${resultType.implementationType.name}<#else>${resultType.name}</#if><<@includeModel object=resultType.typeParameters[0]/>>();
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) {
|
for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) {
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<#if existingInstanceMapping>
|
<#if existingInstanceMapping>
|
||||||
${resultName}.clear();
|
${resultName}.clear();
|
||||||
<#else>
|
<#else>
|
||||||
<@includeModel object=resultType /> ${resultName} = new <#if resultType.mapImplementationType??><@includeModel object=resultType.mapImplementationType /><#else><@includeModel object=resultType /></#if>();
|
<@includeModel object=resultType /> ${resultName} = new <#if resultType.implementationType??><@includeModel object=resultType.implementationType /><#else><@includeModel object=resultType /></#if>();
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
for ( Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>> ${entryVariableName} : ${sourceParameter.name}.entrySet() ) {
|
for ( Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>> ${entryVariableName} : ${sourceParameter.name}.entrySet() ) {
|
||||||
|
@ -18,4 +18,4 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
${type} ${name}
|
<@includeModel object=type/> ${name}
|
@ -32,9 +32,9 @@
|
|||||||
</#if>
|
</#if>
|
||||||
<#-- c) simply set -->
|
<#-- c) simply set -->
|
||||||
<#else>
|
<#else>
|
||||||
<#if targetType.collectionType == true>
|
<#if targetType.implementationType??>
|
||||||
if ( ${sourceBeanName}.${sourceAccessorName}() != null ) {
|
if ( ${sourceBeanName}.${sourceAccessorName}() != null ) {
|
||||||
${ext.targetBeanName}.${targetAccessorName}( new <#if targetType.collectionImplementationType??>${targetType.collectionImplementationType.name}<#else>${targetType.name}</#if><#if targetType.elementType??><${targetType.elementType.name}></#if>( ${sourceBeanName}.${sourceAccessorName}() ) );
|
${ext.targetBeanName}.${targetAccessorName}( new <#if targetType.implementationType??>${targetType.implementationType.name}<#else>${targetType.name}</#if><#if targetType.elementType??><${targetType.elementType.name}></#if>( ${sourceBeanName}.${sourceAccessorName}() ) );
|
||||||
}
|
}
|
||||||
<#else>
|
<#else>
|
||||||
${ext.targetBeanName}.${targetAccessorName}( ${sourceBeanName}.${sourceAccessorName}() );
|
${ext.targetBeanName}.${targetAccessorName}( ${sourceBeanName}.${sourceAccessorName}() );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user