From ac9859c38dea538e10d0a917296186aeeea02428 Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Thu, 11 Jul 2013 21:58:53 +0200 Subject: [PATCH] #44 Enabling types with more than one type parameter --- .../java/org/mapstruct/ap/model/Mapper.java | 4 +- .../java/org/mapstruct/ap/model/Type.java | 57 ++++++++----------- .../ap/processor/MapperCreationProcessor.java | 12 ++-- .../java/org/mapstruct/ap/util/TypeUtil.java | 12 ++-- ...pstruct.ap.model.IterableMappingMethod.ftl | 8 +-- .../resources/org.mapstruct.ap.model.Type.ftl | 21 +++++++ 6 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.Type.ftl 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 309fcac1d..85e044c96 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java @@ -83,7 +83,9 @@ public class Mapper extends AbstractModelElement { addWithDependents( collection, typeToAdd.getCollectionImplementationType() ); addWithDependents( collection, typeToAdd.getIterableImplementationType() ); - addWithDependents( collection, typeToAdd.getElementType() ); + for ( Type type : typeToAdd.getTypeParameters() ) { + addWithDependents( collection, type ); + } } @Override 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 5068fda49..bdce555b8 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Type.java @@ -21,6 +21,7 @@ package org.mapstruct.ap.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -32,7 +33,7 @@ import java.util.concurrent.ConcurrentMap; * * @author Gunnar Morling */ -public class Type implements Comparable { +public class Type extends AbstractModelElement implements Comparable { private static final Set PRIMITIVE_TYPE_NAMES = new HashSet( Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" ) @@ -54,7 +55,7 @@ public class Type implements Comparable { private final String packageName; private final String name; - private final Type elementType; + private final List typeParameters; private final boolean isEnumType; private final boolean isCollectionType; private final boolean isIterableType; @@ -68,10 +69,10 @@ public class Type implements Comparable { return new Type( pakkage.getName(), clazz.getSimpleName(), - null, clazz.isEnum(), Collection.class.isAssignableFrom( clazz ), - Iterable.class.isAssignableFrom( clazz ) + Iterable.class.isAssignableFrom( clazz ), + Collections.emptyList() ); } else { @@ -80,21 +81,21 @@ public class Type implements Comparable { } public Type(String name) { - this( null, name, null, false, false, false ); + this( null, name, false, false, false, Collections.emptyList() ); } public Type(String packageName, String name) { - this( packageName, name, null, false, false, false ); + this( packageName, name, false, false, false, Collections.emptyList() ); } - public Type(String packageName, String name, Type elementType, boolean isEnumType, boolean isCollectionType, - boolean isIterableType) { + public Type(String packageName, String name, boolean isEnumType, boolean isCollectionType, + boolean isIterableType, List typeParameters) { this.packageName = packageName; this.name = name; - this.elementType = elementType; this.isEnumType = isEnumType; this.isCollectionType = isCollectionType; this.isIterableType = isIterableType; + this.typeParameters = typeParameters; if ( isCollectionType ) { collectionImplementationType = DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.get( packageName + "." + name ); @@ -119,8 +120,8 @@ public class Type implements Comparable { return name; } - public Type getElementType() { - return elementType; + public List getTypeParameters() { + return typeParameters; } public boolean isPrimitive() { @@ -152,27 +153,17 @@ public class Type implements Comparable { } @Override - public String toString() { - if ( packageName == null ) { - return name; - } - else if ( elementType == null ) { - return packageName + "." + name; - } - else { - return packageName + "." + name + "<" + elementType + ">"; - } + public Set getImportTypes() { + return Collections.emptySet(); } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result - + ( ( elementType == null ) ? 0 : elementType.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; } @@ -188,14 +179,6 @@ public class Type implements Comparable { return false; } Type other = (Type) obj; - if ( elementType == null ) { - if ( other.elementType != null ) { - return false; - } - } - else if ( !elementType.equals( other.elementType ) ) { - return false; - } if ( name == null ) { if ( other.name != null ) { return false; @@ -212,6 +195,14 @@ public class Type implements Comparable { 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; } 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 3a434e140..f04275677 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -356,8 +356,8 @@ public class MapperCreationProcessor implements ModelElementProcessor methods, Method method) { TypeConversion conversion = getIterableConversion( conversions, - method.getSourceType().getElementType(), - method.getTargetType().getElementType(), + method.getSourceType().getTypeParameters().iterator().next(), + method.getTargetType().getTypeParameters().iterator().next(), method.getIterableMapping() ); @@ -368,8 +368,8 @@ public class MapperCreationProcessor implements ModelElementProcessor typeParameters = new ArrayList(); boolean isIterableType = isIterableType( type ); - if ( isIterableType && !type.getTypeArguments().isEmpty() ) { - elementType = retrieveType( type.getTypeArguments().iterator().next() ); + for ( TypeMirror mirror : type.getTypeArguments() ) { + typeParameters.add( retrieveType( mirror ) ); } return new Type( elementUtils.getPackageOf( type.asElement() ).toString(), type.asElement().getSimpleName().toString(), - elementType, type.asElement().getKind() == ElementKind.ENUM, isCollectionType( type ), - isIterableType + isIterableType, + typeParameters ); } 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 a64a61287..50c2f2333 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl @@ -19,15 +19,15 @@ --> @Override - public ${targetType.name}<${targetType.elementType.name}> ${name}(${sourceType.name}<${sourceType.elementType.name}> ${parameterName}) { + public <@includeModel object=targetType/> ${name}(<@includeModel object=sourceType/> ${parameterName}) { if ( ${parameterName} == null ) { return null; } <#-- 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 targetType.name == "Iterable" && targetType.packageName == "java.lang">${targetType.iterableImplementationType.name}<#else>${targetType.name}<${targetType.elementType.name}> ${targetType.name?uncap_first} = new <#if targetType.iterableImplementationType??>${targetType.iterableImplementationType.name}<#else>${targetType.name}<${targetType.elementType.name}>(); + <#if targetType.name == "Iterable" && targetType.packageName == "java.lang">${targetType.iterableImplementationType.name}<#else>${targetType.name}<<@includeModel object=targetType.typeParameters[0]/>> ${targetType.name?uncap_first} = new <#if targetType.iterableImplementationType??>${targetType.iterableImplementationType.name}<#else>${targetType.name}<<@includeModel object=targetType.typeParameters[0]/>>(); - for ( ${sourceType.elementType.name} ${sourceType.elementType.name?uncap_first} : ${parameterName} ) { + for ( <@includeModel object=sourceType.typeParameters[0]/> ${sourceType.typeParameters[0].name?uncap_first} : ${parameterName} ) { <#if conversion??> <#if (conversion.exceptionTypes?size == 0) > ${targetType.name?uncap_first}.add( <@includeModel object=conversion/> ); @@ -42,7 +42,7 @@ <#else> - ${targetType.name?uncap_first}.add( ${elementMappingMethod.name}( ${sourceType.elementType.name?uncap_first} ) ); + ${targetType.name?uncap_first}.add( ${elementMappingMethod.name}( ${sourceType.typeParameters[0].name?uncap_first} ) ); } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.Type.ftl b/processor/src/main/resources/org.mapstruct.ap.model.Type.ftl new file mode 100644 index 000000000..69ea22046 --- /dev/null +++ b/processor/src/main/resources/org.mapstruct.ap.model.Type.ftl @@ -0,0 +1,21 @@ +<#-- + + 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. + +--> +${name}<#if (typeParameters?size > 0) ><<#list typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, > \ No newline at end of file