#44 Enabling types with more than one type parameter

This commit is contained in:
Gunnar Morling 2013-07-11 21:58:53 +02:00
parent 7d26a3b43e
commit ac9859c38d
6 changed files with 65 additions and 49 deletions

View File

@ -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

View File

@ -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<Type> {
public class Type extends AbstractModelElement implements Comparable<Type> {
private static final Set<String> PRIMITIVE_TYPE_NAMES = new HashSet<String>(
Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" )
@ -54,7 +55,7 @@ public class Type implements Comparable<Type> {
private final String packageName;
private final String name;
private final Type elementType;
private final List<Type> typeParameters;
private final boolean isEnumType;
private final boolean isCollectionType;
private final boolean isIterableType;
@ -68,10 +69,10 @@ public class Type implements Comparable<Type> {
return new Type(
pakkage.getName(),
clazz.getSimpleName(),
null,
clazz.isEnum(),
Collection.class.isAssignableFrom( clazz ),
Iterable.class.isAssignableFrom( clazz )
Iterable.class.isAssignableFrom( clazz ),
Collections.<Type>emptyList()
);
}
else {
@ -80,21 +81,21 @@ public class Type implements Comparable<Type> {
}
public Type(String name) {
this( null, name, null, false, false, false );
this( null, name, false, false, false, Collections.<Type>emptyList() );
}
public Type(String packageName, String name) {
this( packageName, name, null, false, false, false );
this( packageName, name, false, false, false, Collections.<Type>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<Type> 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<Type> {
return name;
}
public Type getElementType() {
return elementType;
public List<Type> getTypeParameters() {
return typeParameters;
}
public boolean isPrimitive() {
@ -152,27 +153,17 @@ public class Type implements Comparable<Type> {
}
@Override
public String toString() {
if ( packageName == null ) {
return name;
}
else if ( elementType == null ) {
return packageName + "." + name;
}
else {
return packageName + "." + name + "<" + elementType + ">";
}
public Set<Type> 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<Type> {
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<Type> {
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;
}

View File

@ -356,8 +356,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
private MappingMethod getIterableMappingMethod(List<Method> 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<List<Metho
method.getTargetType(),
getMappingMethodReference(
methods,
method.getSourceType().getElementType(),
method.getTargetType().getElementType()
method.getSourceType().getTypeParameters().iterator().next(),
method.getTargetType().getTypeParameters().iterator().next()
),
conversion
);
@ -430,9 +430,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
Kind.ERROR,
String.format(
"Can't map property \"%s %s\" to \"%s %s\".",
property.getSourceType(),
property.getSourceType().getName(),
property.getSourceName(),
property.getTargetType(),
property.getTargetType().getName(),
property.getTargetName()
),
method.getExecutable()

View File

@ -18,7 +18,9 @@
*/
package org.mapstruct.ap.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
@ -43,20 +45,20 @@ public class TypeUtil {
}
public Type getType(DeclaredType type) {
Type elementType = null;
List<Type> typeParameters = new ArrayList<Type>();
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
);
}

View File

@ -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}</#if><${targetType.elementType.name}> ${targetType.name?uncap_first} = new <#if targetType.iterableImplementationType??>${targetType.iterableImplementationType.name}<#else>${targetType.name}</#if><${targetType.elementType.name}>();
<#if targetType.name == "Iterable" && targetType.packageName == "java.lang">${targetType.iterableImplementationType.name}<#else>${targetType.name}</#if><<@includeModel object=targetType.typeParameters[0]/>> ${targetType.name?uncap_first} = new <#if targetType.iterableImplementationType??>${targetType.iterableImplementationType.name}<#else>${targetType.name}</#if><<@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 @@
</#list>
</#if>
<#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} ) );
</#if>
}

View File

@ -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>, </#if></#list>></#if>