mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#6 Making primitive conversions usable for iterable types
This commit is contained in:
parent
321e1a3206
commit
ae4655a2ba
@ -178,12 +178,36 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isIterableMapping = method.getSourceType().isIterableType() && method.getTargetType()
|
||||||
|
.isIterableType();
|
||||||
|
|
||||||
|
String toConversionString = null;
|
||||||
|
String fromConversionString = null;
|
||||||
|
|
||||||
|
if ( isIterableMapping ) {
|
||||||
|
toConversionString = getIterableConversionString(
|
||||||
|
conversions,
|
||||||
|
method.getSourceType().getElementType(),
|
||||||
|
method.getTargetType().getElementType(),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
fromConversionString = getIterableConversionString(
|
||||||
|
conversions,
|
||||||
|
method.getTargetType().getElementType(),
|
||||||
|
method.getSourceType().getElementType(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
BeanMapping mapping = new BeanMapping(
|
BeanMapping mapping = new BeanMapping(
|
||||||
method.getSourceType(),
|
method.getSourceType(),
|
||||||
method.getTargetType(),
|
method.getTargetType(),
|
||||||
propertyMappings,
|
propertyMappings,
|
||||||
mappingMethod,
|
mappingMethod,
|
||||||
reverseMappingMethod
|
reverseMappingMethod,
|
||||||
|
toConversionString,
|
||||||
|
fromConversionString
|
||||||
);
|
);
|
||||||
|
|
||||||
mappings.add( mapping );
|
mappings.add( mapping );
|
||||||
@ -191,6 +215,19 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
return mappings;
|
return mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getIterableConversionString(Conversions conversions, Type sourceElementType, Type targetElementType, boolean isToConversion) {
|
||||||
|
Conversion conversion = conversions.getConversion( sourceElementType, targetElementType );
|
||||||
|
|
||||||
|
if ( conversion == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conversion.to(
|
||||||
|
Introspector.decapitalize( sourceElementType.getName() ),
|
||||||
|
targetElementType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private List<Type> getUsedMapperTypes(TypeElement element) {
|
private List<Type> getUsedMapperTypes(TypeElement element) {
|
||||||
List<Type> usedMapperTypes = new LinkedList<Type>();
|
List<Type> usedMapperTypes = new LinkedList<Type>();
|
||||||
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
|
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
|
||||||
|
@ -54,6 +54,9 @@ public class Conversions {
|
|||||||
if ( sourceType.isEnumType() && targetType.equals( typeUtil.getType( stringType ) ) ) {
|
if ( sourceType.isEnumType() && targetType.equals( typeUtil.getType( stringType ) ) ) {
|
||||||
sourceType = typeUtil.getType( enumType );
|
sourceType = typeUtil.getType( enumType );
|
||||||
}
|
}
|
||||||
|
else if ( targetType.isEnumType() && sourceType.equals( typeUtil.getType( stringType ) ) ) {
|
||||||
|
targetType = typeUtil.getType( enumType );
|
||||||
|
}
|
||||||
|
|
||||||
return conversions.get( new Key( sourceType, targetType ) );
|
return conversions.get( new Key( sourceType, targetType ) );
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,19 @@ public class BeanMapping {
|
|||||||
private final MappingMethod mappingMethod;
|
private final MappingMethod mappingMethod;
|
||||||
private final MappingMethod reverseMappingMethod;
|
private final MappingMethod reverseMappingMethod;
|
||||||
private final boolean isIterableMapping;
|
private final boolean isIterableMapping;
|
||||||
|
private final String toConversion;
|
||||||
|
private final String fromConversion;
|
||||||
|
|
||||||
public BeanMapping(Type sourceType, Type targetType, List<PropertyMapping> propertyMappings, MappingMethod mappingMethod,
|
public BeanMapping(Type sourceType, Type targetType, List<PropertyMapping> propertyMappings, MappingMethod mappingMethod,
|
||||||
MappingMethod reverseMappingMethod) {
|
MappingMethod reverseMappingMethod, String toConversion, String fromConversion) {
|
||||||
this.sourceType = sourceType;
|
this.sourceType = sourceType;
|
||||||
this.targetType = targetType;
|
this.targetType = targetType;
|
||||||
this.propertyMappings = propertyMappings;
|
this.propertyMappings = propertyMappings;
|
||||||
this.mappingMethod = mappingMethod;
|
this.mappingMethod = mappingMethod;
|
||||||
this.reverseMappingMethod = reverseMappingMethod;
|
this.reverseMappingMethod = reverseMappingMethod;
|
||||||
this.isIterableMapping = sourceType.isIterableType() && targetType.isIterableType();
|
this.isIterableMapping = sourceType.isIterableType() && targetType.isIterableType();
|
||||||
|
this.toConversion = toConversion;
|
||||||
|
this.fromConversion = fromConversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getSourceType() {
|
public Type getSourceType() {
|
||||||
@ -60,6 +64,14 @@ public class BeanMapping {
|
|||||||
return isIterableMapping;
|
return isIterableMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getToConversion() {
|
||||||
|
return toConversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFromConversion() {
|
||||||
|
return fromConversion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder( "BeanMapping {" );
|
StringBuilder sb = new StringBuilder( "BeanMapping {" );
|
||||||
@ -76,6 +88,8 @@ public class BeanMapping {
|
|||||||
|
|
||||||
sb.append( "\n mappingMethod=" + mappingMethod.toString().replaceAll( "\n", "\n " ) + ',' );
|
sb.append( "\n mappingMethod=" + mappingMethod.toString().replaceAll( "\n", "\n " ) + ',' );
|
||||||
sb.append( "\n reverseMappingMethod=" + reverseMappingMethod + ',' );
|
sb.append( "\n reverseMappingMethod=" + reverseMappingMethod + ',' );
|
||||||
|
sb.append( "\n toConversion=" + toConversion + ',' );
|
||||||
|
sb.append( "\n fromConversion=" + fromConversion + ',' );
|
||||||
sb.append( "\n isIterableMapping=" + isIterableMapping );
|
sb.append( "\n isIterableMapping=" + isIterableMapping );
|
||||||
sb.append( "\n}" );
|
sb.append( "\n}" );
|
||||||
|
|
||||||
|
@ -48,7 +48,11 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
<#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}>();
|
<#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} ) {
|
||||||
|
<#if beanMapping.toConversion??>
|
||||||
|
${beanMapping.targetType.name?uncap_first}.add( ${beanMapping.toConversion} );
|
||||||
|
<#else>
|
||||||
${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} ) );
|
||||||
|
</#if>
|
||||||
}
|
}
|
||||||
|
|
||||||
return ${beanMapping.targetType.name?uncap_first};
|
return ${beanMapping.targetType.name?uncap_first};
|
||||||
@ -94,6 +98,7 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
<#if beanMapping.reverseMappingMethod??>
|
<#if beanMapping.reverseMappingMethod??>
|
||||||
<#if beanMapping.reverseMappingMethod.generationRequired == true>
|
<#if beanMapping.reverseMappingMethod.generationRequired == true>
|
||||||
<#if beanMapping.iterableMapping == true>
|
<#if beanMapping.iterableMapping == true>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.reverseMappingMethod.name}(${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.reverseMappingMethod.parameterName}) {
|
public ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.reverseMappingMethod.name}(${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.reverseMappingMethod.parameterName}) {
|
||||||
if( ${beanMapping.reverseMappingMethod.parameterName} == null ) {
|
if( ${beanMapping.reverseMappingMethod.parameterName} == null ) {
|
||||||
@ -104,7 +109,11 @@ public class ${implementationName} implements ${interfaceName} {
|
|||||||
<#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}>();
|
<#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} ) {
|
||||||
|
<#if beanMapping.fromConversion??>
|
||||||
|
${beanMapping.sourceType.name?uncap_first}.add( ${beanMapping.fromConversion} );
|
||||||
|
<#else>
|
||||||
${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} ) );
|
||||||
|
</#if>
|
||||||
}
|
}
|
||||||
|
|
||||||
return ${beanMapping.sourceType.name?uncap_first};
|
return ${beanMapping.sourceType.name?uncap_first};
|
||||||
|
@ -17,6 +17,7 @@ package org.mapstruct.ap.test.collection;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ public class CollectionMappingTest extends MapperTestBase {
|
|||||||
return Arrays.<Class<?>>asList(
|
return Arrays.<Class<?>>asList(
|
||||||
Source.class,
|
Source.class,
|
||||||
Target.class,
|
Target.class,
|
||||||
|
Colour.class,
|
||||||
SourceTargetMapper.class
|
SourceTargetMapper.class
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -214,4 +216,52 @@ public class CollectionMappingTest extends MapperTestBase {
|
|||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
assertThat( target.getSet() ).containsOnly( 1, 2 );
|
assertThat( target.getSet() ).containsOnly( 1, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("6")
|
||||||
|
public void shouldMapIntegerSetToStringSet() {
|
||||||
|
Source source = new Source();
|
||||||
|
source.setAnotherIntegerSet( new HashSet<Integer>( Arrays.asList( 1, 2 ) ) );
|
||||||
|
|
||||||
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
|
assertThat( target ).isNotNull();
|
||||||
|
assertThat( target.getAnotherStringSet() ).containsOnly( "1", "2" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("6")
|
||||||
|
public void shouldReverseMapIntegerSetToStringSet() {
|
||||||
|
Target target = new Target();
|
||||||
|
target.setAnotherStringSet( new HashSet<String>( Arrays.asList( "1", "2" ) ) );
|
||||||
|
|
||||||
|
Source source = SourceTargetMapper.INSTANCE.targetToSource( target );
|
||||||
|
|
||||||
|
assertThat( source ).isNotNull();
|
||||||
|
assertThat( source.getAnotherIntegerSet() ).containsOnly( 1, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("6")
|
||||||
|
public void shouldMapSetOfEnumToStringSet() {
|
||||||
|
Source source = new Source();
|
||||||
|
source.setColours( EnumSet.of( Colour.BLUE, Colour.GREEN ) );
|
||||||
|
|
||||||
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
|
assertThat( target ).isNotNull();
|
||||||
|
assertThat( target.getColours() ).containsOnly( "BLUE", "GREEN" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("6")
|
||||||
|
public void shouldReverseMapSetOfEnumToStringSet() {
|
||||||
|
Target target = new Target();
|
||||||
|
target.setColours( new HashSet<String>( Arrays.asList( "BLUE", "GREEN" ) ) );
|
||||||
|
|
||||||
|
Source source = SourceTargetMapper.INSTANCE.targetToSource( target );
|
||||||
|
|
||||||
|
assertThat( source ).isNotNull();
|
||||||
|
assertThat( source.getColours() ).containsOnly( Colour.GREEN, Colour.BLUE );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
*
|
||||||
|
* 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.test.collection;
|
||||||
|
|
||||||
|
public enum Colour {
|
||||||
|
RED, GREEN, BLUE;
|
||||||
|
}
|
@ -35,6 +35,10 @@ public class Source {
|
|||||||
|
|
||||||
private Set<Integer> integerSet;
|
private Set<Integer> integerSet;
|
||||||
|
|
||||||
|
private Set<Integer> anotherIntegerSet;
|
||||||
|
|
||||||
|
private Set<Colour> colours;
|
||||||
|
|
||||||
public List<String> getStringList() {
|
public List<String> getStringList() {
|
||||||
return stringList;
|
return stringList;
|
||||||
}
|
}
|
||||||
@ -90,4 +94,20 @@ public class Source {
|
|||||||
public void setIntegerSet(Set<Integer> integerSet) {
|
public void setIntegerSet(Set<Integer> integerSet) {
|
||||||
this.integerSet = integerSet;
|
this.integerSet = integerSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Integer> getAnotherIntegerSet() {
|
||||||
|
return anotherIntegerSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnotherIntegerSet(Set<Integer> anotherIntegerSet) {
|
||||||
|
this.anotherIntegerSet = anotherIntegerSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Colour> getColours() {
|
||||||
|
return colours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColours(Set<Colour> colours) {
|
||||||
|
this.colours = colours;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.test.collection;
|
package org.mapstruct.ap.test.collection;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mappers;
|
import org.mapstruct.Mappers;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
@ -27,9 +29,18 @@ public interface SourceTargetMapper {
|
|||||||
|
|
||||||
@Mappings({
|
@Mappings({
|
||||||
@Mapping(source = "integerList", target = "integerCollection"),
|
@Mapping(source = "integerList", target = "integerCollection"),
|
||||||
@Mapping(source = "integerSet", target = "set")
|
@Mapping(source = "integerSet", target = "set"),
|
||||||
|
@Mapping(source = "anotherIntegerSet", target = "anotherStringSet")
|
||||||
})
|
})
|
||||||
Target sourceToTarget(Source source);
|
Target sourceToTarget(Source source);
|
||||||
|
|
||||||
Source targetToSource(Target target);
|
Source targetToSource(Target target);
|
||||||
|
|
||||||
|
Set<String> integerSetToStringSet(Set<Integer> integers);
|
||||||
|
|
||||||
|
Set<Integer> stringSetToIntegerSet(Set<String> strings);
|
||||||
|
|
||||||
|
Set<String> colourSetToStringSet(Set<Colour> colours);
|
||||||
|
|
||||||
|
Set<Colour> stringSetToColourSet(Set<String> colours);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,10 @@ public class Target {
|
|||||||
|
|
||||||
private Collection<Integer> integerCollection;
|
private Collection<Integer> integerCollection;
|
||||||
|
|
||||||
|
private Set<String> anotherStringSet;
|
||||||
|
|
||||||
|
private Set<String> colours;
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private Set set;
|
private Set set;
|
||||||
|
|
||||||
@ -93,4 +97,20 @@ public class Target {
|
|||||||
public void setSet(Set set) {
|
public void setSet(Set set) {
|
||||||
this.set = set;
|
this.set = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getAnotherStringSet() {
|
||||||
|
return anotherStringSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnotherStringSet(Set<String> anotherStringSet) {
|
||||||
|
this.anotherStringSet = anotherStringSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColours(Set<String> colours) {
|
||||||
|
this.colours = colours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getColours() {
|
||||||
|
return colours;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user