mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#6 Support mapping of java.lang.Iterable
This commit is contained in:
parent
07c1009c6b
commit
d404775519
@ -33,7 +33,7 @@ public class BeanMapping {
|
|||||||
this.propertyMappings = propertyMappings;
|
this.propertyMappings = propertyMappings;
|
||||||
this.mappingMethod = mappingMethod;
|
this.mappingMethod = mappingMethod;
|
||||||
this.reverseMappingMethod = reverseMappingMethod;
|
this.reverseMappingMethod = reverseMappingMethod;
|
||||||
this.isIterableMapping = mappingMethod.getElementMappingMethod() != null;
|
this.isIterableMapping = sourceType.isIterableType() && targetType.isIterableType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getSourceType() {
|
public Type getSourceType() {
|
||||||
@ -56,7 +56,7 @@ public class BeanMapping {
|
|||||||
return reverseMappingMethod;
|
return reverseMappingMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getIterableMapping() {
|
public boolean isIterableMapping() {
|
||||||
return isIterableMapping;
|
return isIterableMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,20 +35,26 @@ public class Type {
|
|||||||
Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" )
|
Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" )
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private final static ConcurrentMap<String, Type> defaultIterableImplementationTypes = new ConcurrentHashMap<String, Type>();
|
||||||
private final static ConcurrentMap<String, Type> defaultCollectionImplementationTypes = new ConcurrentHashMap<String, Type>();
|
private final static ConcurrentMap<String, Type> defaultCollectionImplementationTypes = new ConcurrentHashMap<String, Type>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
defaultCollectionImplementationTypes.put( List.class.getName(), forClass( ArrayList.class ) );
|
defaultCollectionImplementationTypes.put( List.class.getName(), forClass( ArrayList.class ) );
|
||||||
defaultCollectionImplementationTypes.put( Set.class.getName(), forClass( HashSet.class ) );
|
defaultCollectionImplementationTypes.put( Set.class.getName(), forClass( HashSet.class ) );
|
||||||
defaultCollectionImplementationTypes.put( Collection.class.getName(), forClass( ArrayList.class ) );
|
defaultCollectionImplementationTypes.put( Collection.class.getName(), forClass( ArrayList.class ) );
|
||||||
|
|
||||||
|
defaultIterableImplementationTypes.put( Iterable.class.getName(), forClass( ArrayList.class ) );
|
||||||
|
defaultIterableImplementationTypes.putAll( defaultCollectionImplementationTypes );
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String packageName;
|
private final String packageName;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Type elementType;
|
private final Type elementType;
|
||||||
private final boolean isEnumType;
|
private final boolean isEnumType;
|
||||||
private final Type implementingType;
|
|
||||||
private final boolean isCollectionType;
|
private final boolean isCollectionType;
|
||||||
|
private final boolean isIterableType;
|
||||||
|
private final Type collectionImplementationType;
|
||||||
|
private final Type iterableImplementationType;
|
||||||
|
|
||||||
public static Type forClass(Class<?> clazz) {
|
public static Type forClass(Class<?> clazz) {
|
||||||
Package pakkage = clazz.getPackage();
|
Package pakkage = clazz.getPackage();
|
||||||
@ -59,7 +65,8 @@ public class Type {
|
|||||||
clazz.getSimpleName(),
|
clazz.getSimpleName(),
|
||||||
null,
|
null,
|
||||||
clazz.isEnum(),
|
clazz.isEnum(),
|
||||||
Collection.class.isAssignableFrom( clazz )
|
Collection.class.isAssignableFrom( clazz ),
|
||||||
|
Iterable.class.isAssignableFrom( clazz )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -68,16 +75,30 @@ public class Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Type(String name) {
|
public Type(String name) {
|
||||||
this( null, name, null, false, false );
|
this( null, name, null, false, false, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type(String packageName, String name, Type elementType, boolean isEnumType, boolean isCollectionType) {
|
public Type(String packageName, String name, Type elementType, boolean isEnumType, boolean isCollectionType, boolean isIterableType) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.elementType = elementType;
|
this.elementType = elementType;
|
||||||
this.isEnumType = isEnumType;
|
this.isEnumType = isEnumType;
|
||||||
implementingType = defaultCollectionImplementationTypes.get( packageName + "." + name );
|
|
||||||
this.isCollectionType = isCollectionType;
|
this.isCollectionType = isCollectionType;
|
||||||
|
this.isIterableType = isIterableType;
|
||||||
|
|
||||||
|
if ( isCollectionType ) {
|
||||||
|
collectionImplementationType = defaultCollectionImplementationTypes.get( packageName + "." + name );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
collectionImplementationType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isIterableType ) {
|
||||||
|
iterableImplementationType = defaultIterableImplementationTypes.get( packageName + "." + name );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iterableImplementationType = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
@ -100,14 +121,22 @@ public class Type {
|
|||||||
return isEnumType;
|
return isEnumType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getImplementingType() {
|
public Type getCollectionImplementationType() {
|
||||||
return implementingType;
|
return collectionImplementationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getIterableImplementationType() {
|
||||||
|
return iterableImplementationType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCollectionType() {
|
public boolean isCollectionType() {
|
||||||
return isCollectionType;
|
return isCollectionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIterableType() {
|
||||||
|
return isIterableType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if ( packageName == null ) {
|
if ( packageName == null ) {
|
||||||
|
@ -29,18 +29,21 @@ public class TypeUtil {
|
|||||||
|
|
||||||
private final Elements elementUtils;
|
private final Elements elementUtils;
|
||||||
private final Types typeUtils;
|
private final Types typeUtils;
|
||||||
private TypeMirror collectionType;
|
private final TypeMirror collectionType;
|
||||||
|
private final TypeMirror iterableType;
|
||||||
|
|
||||||
public TypeUtil(Elements elementUtils, Types typeUtils) {
|
public TypeUtil(Elements elementUtils, Types typeUtils) {
|
||||||
this.elementUtils = elementUtils;
|
this.elementUtils = elementUtils;
|
||||||
this.typeUtils = typeUtils;
|
this.typeUtils = typeUtils;
|
||||||
collectionType = elementUtils.getTypeElement( Collection.class.getCanonicalName() ).asType();
|
collectionType = elementUtils.getTypeElement( Collection.class.getCanonicalName() ).asType();
|
||||||
|
iterableType = elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getType(DeclaredType type) {
|
public Type getType(DeclaredType type) {
|
||||||
Type elementType = null;
|
Type elementType = null;
|
||||||
|
|
||||||
if ( isIterableType( type ) && !type.getTypeArguments().isEmpty() ) {
|
boolean isIterableType = isIterableType( type );
|
||||||
|
if ( isIterableType && !type.getTypeArguments().isEmpty() ) {
|
||||||
elementType = retrieveType( type.getTypeArguments().iterator().next() );
|
elementType = retrieveType( type.getTypeArguments().iterator().next() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,13 +52,17 @@ public class TypeUtil {
|
|||||||
type.asElement().getSimpleName().toString(),
|
type.asElement().getSimpleName().toString(),
|
||||||
elementType,
|
elementType,
|
||||||
type.asElement().getKind() == ElementKind.ENUM,
|
type.asElement().getKind() == ElementKind.ENUM,
|
||||||
typeUtils.isAssignable( typeUtils.erasure( type ), typeUtils.erasure( collectionType ) )
|
isCollectionType( type ),
|
||||||
|
isIterableType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIterableType(DeclaredType type) {
|
private boolean isIterableType(DeclaredType type) {
|
||||||
TypeMirror iterableType = typeUtils.getDeclaredType( elementUtils.getTypeElement( Iterable.class.getCanonicalName() ) );
|
return typeUtils.isAssignable( typeUtils.erasure( type ), typeUtils.erasure( iterableType ) );
|
||||||
return typeUtils.isSubtype( type, iterableType );
|
}
|
||||||
|
|
||||||
|
private boolean isCollectionType(DeclaredType type) {
|
||||||
|
return typeUtils.isAssignable( typeUtils.erasure( type ), typeUtils.erasure( collectionType ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type retrieveType(TypeMirror mirror) {
|
public Type retrieveType(TypeMirror mirror) {
|
||||||
|
@ -44,12 +44,13 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.targetType.name?uncap_first} = new <#if beanMapping.targetType.implementingType??>${beanMapping.targetType.implementingType.name}<#else>${beanMapping.targetType.name}</#if><${beanMapping.targetType.elementType.name}>();
|
<#-- 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 beanMapping.targetType.name == "Iterable" && beanMapping.targetType.packageName == "java.lang">${beanMapping.targetType.iterableImplementationType.name}<#else>${beanMapping.targetType.name}</#if><${beanMapping.targetType.elementType.name}> ${beanMapping.targetType.name?uncap_first} = new <#if beanMapping.targetType.iterableImplementationType??>${beanMapping.targetType.iterableImplementationType.name}<#else>${beanMapping.targetType.name}</#if><${beanMapping.targetType.elementType.name}>();
|
||||||
|
|
||||||
for ( ${beanMapping.sourceType.elementType.name} ${beanMapping.sourceType.elementType.name?uncap_first} : ${beanMapping.mappingMethod.parameterName} ) {
|
for ( ${beanMapping.sourceType.elementType.name} ${beanMapping.sourceType.elementType.name?uncap_first} : ${beanMapping.mappingMethod.parameterName} ) {
|
||||||
${beanMapping.targetType.name?uncap_first}.add( ${beanMapping.mappingMethod.elementMappingMethod.name}( ${beanMapping.sourceType.elementType.name?uncap_first} ) );
|
${beanMapping.targetType.name?uncap_first}.add( ${beanMapping.mappingMethod.elementMappingMethod.name}( ${beanMapping.sourceType.elementType.name?uncap_first} ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ${beanMapping.targetType.name?uncap_first};
|
return ${beanMapping.targetType.name?uncap_first};
|
||||||
}
|
}
|
||||||
<#else>
|
<#else>
|
||||||
@ -77,7 +78,7 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
<#else>
|
<#else>
|
||||||
<#if propertyMapping.targetType.collectionType == true>
|
<#if propertyMapping.targetType.collectionType == true>
|
||||||
if ( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() != null ) {
|
if ( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() != null ) {
|
||||||
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( new <#if propertyMapping.targetType.implementingType??>${propertyMapping.targetType.implementingType.name}<#else>${propertyMapping.targetType.name}</#if><#if propertyMapping.targetType.elementType??><${propertyMapping.targetType.elementType.name}></#if>( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() ) );
|
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( new <#if propertyMapping.targetType.collectionImplementationType??>${propertyMapping.targetType.collectionImplementationType.name}<#else>${propertyMapping.targetType.name}</#if><#if propertyMapping.targetType.elementType??><${propertyMapping.targetType.elementType.name}></#if>( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() ) );
|
||||||
}
|
}
|
||||||
<#else>
|
<#else>
|
||||||
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() );
|
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() );
|
||||||
@ -99,7 +100,8 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.sourceType.name?uncap_first} = new <#if beanMapping.sourceType.implementingType??>${beanMapping.sourceType.implementingType.name}<#else>${beanMapping.sourceType.name}</#if><${beanMapping.sourceType.elementType.name}>();
|
<#-- 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 beanMapping.sourceType.name == "Iterable" && beanMapping.sourceType.packageName == "java.lang">${beanMapping.sourceType.iterableImplementationType.name}<#else>${beanMapping.sourceType.name}</#if><${beanMapping.sourceType.elementType.name}> ${beanMapping.sourceType.name?uncap_first} = new <#if beanMapping.sourceType.iterableImplementationType??>${beanMapping.sourceType.iterableImplementationType.name}<#else>${beanMapping.sourceType.name}</#if><${beanMapping.sourceType.elementType.name}>();
|
||||||
|
|
||||||
for ( ${beanMapping.targetType.elementType.name} ${beanMapping.targetType.elementType.name?uncap_first} : ${beanMapping.reverseMappingMethod.parameterName} ) {
|
for ( ${beanMapping.targetType.elementType.name} ${beanMapping.targetType.elementType.name?uncap_first} : ${beanMapping.reverseMappingMethod.parameterName} ) {
|
||||||
${beanMapping.sourceType.name?uncap_first}.add( ${beanMapping.reverseMappingMethod.elementMappingMethod.name}( ${beanMapping.targetType.elementType.name?uncap_first} ) );
|
${beanMapping.sourceType.name?uncap_first}.add( ${beanMapping.reverseMappingMethod.elementMappingMethod.name}( ${beanMapping.targetType.elementType.name?uncap_first} ) );
|
||||||
@ -132,7 +134,7 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
<#else>
|
<#else>
|
||||||
<#if propertyMapping.sourceType.collectionType == true>
|
<#if propertyMapping.sourceType.collectionType == true>
|
||||||
if ( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() != null ) {
|
if ( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() != null ) {
|
||||||
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( new <#if propertyMapping.sourceType.implementingType??>${propertyMapping.sourceType.implementingType.name}<#else>${propertyMapping.sourceType.name}</#if><#if propertyMapping.sourceType.elementType??><${propertyMapping.sourceType.elementType.name}></#if>( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() ) );
|
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( new <#if propertyMapping.sourceType.collectionImplementationType??>${propertyMapping.sourceType.collectionImplementationType.name}<#else>${propertyMapping.sourceType.name}</#if><#if propertyMapping.sourceType.elementType??><${propertyMapping.sourceType.elementType.name}></#if>( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() ) );
|
||||||
}
|
}
|
||||||
<#else>
|
<#else>
|
||||||
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() );
|
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() );
|
||||||
|
@ -70,4 +70,15 @@ public class DefaultCollectionImplementationTest extends MapperTestBase {
|
|||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
assertThat( target.getFooCollection() ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
|
assertThat( target.getFooCollection() ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("6")
|
||||||
|
public void shouldUseDefaultImplementationForIterable() {
|
||||||
|
Source source = new Source();
|
||||||
|
source.setFooIterable( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) );
|
||||||
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
|
assertThat( target ).isNotNull();
|
||||||
|
assertThat( target.getFooIterable() ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ public class Source {
|
|||||||
|
|
||||||
private Collection<SourceFoo> fooCollection;
|
private Collection<SourceFoo> fooCollection;
|
||||||
|
|
||||||
|
private Iterable<SourceFoo> fooIterable;
|
||||||
|
|
||||||
public List<SourceFoo> getFooList() {
|
public List<SourceFoo> getFooList() {
|
||||||
return fooList;
|
return fooList;
|
||||||
}
|
}
|
||||||
@ -50,4 +52,12 @@ public class Source {
|
|||||||
public void setFooCollection(Collection<SourceFoo> fooCollection) {
|
public void setFooCollection(Collection<SourceFoo> fooCollection) {
|
||||||
this.fooCollection = fooCollection;
|
this.fooCollection = fooCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterable<SourceFoo> getFooIterable() {
|
||||||
|
return fooIterable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFooIterable(Iterable<SourceFoo> fooIterable) {
|
||||||
|
this.fooIterable = fooIterable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.test.collection.defaultimplementation;
|
package org.mapstruct.ap.test.collection.defaultimplementation;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -37,4 +36,6 @@ public interface SourceTargetMapper {
|
|||||||
Set<TargetFoo> sourceFoosToTargetFoos(Set<SourceFoo> foos);
|
Set<TargetFoo> sourceFoosToTargetFoos(Set<SourceFoo> foos);
|
||||||
|
|
||||||
Collection<TargetFoo> sourceFoosToTargetFoos(Collection<SourceFoo> foos);
|
Collection<TargetFoo> sourceFoosToTargetFoos(Collection<SourceFoo> foos);
|
||||||
|
|
||||||
|
Iterable<TargetFoo> sourceFoosToTargetFoos(Iterable<SourceFoo> foos);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ public class Target {
|
|||||||
|
|
||||||
private Collection<TargetFoo> fooCollection;
|
private Collection<TargetFoo> fooCollection;
|
||||||
|
|
||||||
|
private Iterable<TargetFoo> fooIterable;
|
||||||
|
|
||||||
public List<TargetFoo> getFooList() {
|
public List<TargetFoo> getFooList() {
|
||||||
return fooList;
|
return fooList;
|
||||||
}
|
}
|
||||||
@ -50,4 +52,12 @@ public class Target {
|
|||||||
public void setFooCollection(Collection<TargetFoo> fooCollection) {
|
public void setFooCollection(Collection<TargetFoo> fooCollection) {
|
||||||
this.fooCollection = fooCollection;
|
this.fooCollection = fooCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterable<TargetFoo> getFooIterable() {
|
||||||
|
return fooIterable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFooIterable(Iterable<TargetFoo> fooIterable) {
|
||||||
|
this.fooIterable = fooIterable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user