#12 Allowing delegation to other mapper classes

This commit is contained in:
Gunnar Morling 2013-04-07 13:06:35 +02:00
parent 8f4b45c4f2
commit 458718e346
18 changed files with 186 additions and 154 deletions

View File

@ -29,4 +29,5 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface Mapper { public @interface Mapper {
Class<?>[] uses() default { };
} }

View File

@ -15,15 +15,9 @@
*/ */
package org.mapstruct; package org.mapstruct;
import org.mapstruct.converter.Converter;
import org.mapstruct.converter.NoOpConverter;
public @interface Mapping { public @interface Mapping {
String source(); String source();
String target(); String target();
Class<? extends Converter<?, ?>> converter() default NoOpConverter.class;
} }

View File

@ -1,23 +0,0 @@
/**
* 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.converter;
public interface Converter<S, T> {
T from(S source);
S to(T target);
}

View File

@ -1,29 +0,0 @@
/**
* 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.converter;
public class NoOpConverter implements Converter<Object, Object> {
@Override
public Object from(Object source) {
return source;
}
@Override
public Object to(Object target) {
return target;
}
}

View File

@ -16,7 +16,6 @@
package org.mapstruct; package org.mapstruct;
import org.mapstruct.Mappers;
import org.mapstruct.test.model.Foo; import org.mapstruct.test.model.Foo;
import org.testng.annotations.Test; import org.testng.annotations.Test;

View File

@ -29,7 +29,9 @@ import javax.lang.model.element.Element;
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.element.VariableElement; import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementKindVisitor6; import javax.lang.model.util.ElementKindVisitor6;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
@ -91,18 +93,34 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
} }
private Mapper retrieveModel(TypeElement element) { private Mapper retrieveModel(TypeElement element) {
List<Method> methods = retrieveMethods( element ); List<Method> methods = retrieveMethods( null, element );
Set<Method> processedMethods = new HashSet<Method>(); List<BeanMapping> mappings = getMappings( methods );
List<BeanMapping> mappings = new ArrayList<BeanMapping>(); List<Type> usedMapperTypes = getUsedMapperTypes( element );
Mapper mapper = new Mapper(
elementUtils.getPackageOf( element ).getQualifiedName().toString(),
element.getSimpleName().toString(),
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
mappings,
usedMapperTypes
);
return mapper;
}
private List<BeanMapping> getMappings(List<Method> methods) {
Conversions conversions = new Conversions( elementUtils, typeUtils, typeUtil ); Conversions conversions = new Conversions( elementUtils, typeUtils, typeUtil );
List<BeanMapping> mappings = new ArrayList<BeanMapping>();
Set<Method> processedMethods = new HashSet<Method>();
for ( Method method : methods ) { for ( Method method : methods ) {
if ( processedMethods.contains( method ) ) { if ( processedMethods.contains( method ) ) {
continue; continue;
} }
MappingMethod mappingMethod = new MappingMethod( MappingMethod mappingMethod = new MappingMethod(
method.getDeclaringMapper(),
method.getName(), method.getName(),
method.getParameterName(), method.getParameterName(),
getElementMappingMethod( methods, method ) getElementMappingMethod( methods, method )
@ -114,6 +132,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
processedMethods.add( rawReverseMappingMethod ); processedMethods.add( rawReverseMappingMethod );
reverseMappingMethod = new MappingMethod( reverseMappingMethod = new MappingMethod(
rawReverseMappingMethod.getDeclaringMapper(),
rawReverseMappingMethod.getName(), rawReverseMappingMethod.getName(),
rawReverseMappingMethod.getParameterName(), rawReverseMappingMethod.getParameterName(),
getElementMappingMethod( methods, rawReverseMappingMethod ) getElementMappingMethod( methods, rawReverseMappingMethod )
@ -134,12 +153,13 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
property.getSourceType(), property.getSourceType(),
property.getTargetName(), property.getTargetName(),
property.getTargetType(), property.getTargetType(),
property.getConverterType(),
propertyMappingMethod != null ? new MappingMethod( propertyMappingMethod != null ? new MappingMethod(
propertyMappingMethod.getDeclaringMapper(),
propertyMappingMethod.getName(), propertyMappingMethod.getName(),
propertyMappingMethod.getParameterName() propertyMappingMethod.getParameterName()
) : null, ) : null,
reversePropertyMappingMethod != null ? new MappingMethod( reversePropertyMappingMethod != null ? new MappingMethod(
reversePropertyMappingMethod.getDeclaringMapper(),
reversePropertyMappingMethod.getName(), reversePropertyMappingMethod.getName(),
reversePropertyMappingMethod.getParameterName() reversePropertyMappingMethod.getParameterName()
) : null, ) : null,
@ -168,15 +188,16 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
mappings.add( mapping ); mappings.add( mapping );
} }
return mappings;
}
Mapper mapper = new Mapper( private List<Type> getUsedMapperTypes(TypeElement element) {
elementUtils.getPackageOf( element ).getQualifiedName().toString(), List<Type> usedMapperTypes = new LinkedList<Type>();
element.getSimpleName().toString(), MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
element.getSimpleName() + IMPLEMENTATION_SUFFIX, for ( TypeMirror usedMapper : mapperPrism.uses() ) {
mappings usedMapperTypes.add( typeUtil.retrieveType( usedMapper ) );
); }
return usedMapperTypes;
return mapper;
} }
private String getAccessor(String name) { private String getAccessor(String name) {
@ -196,6 +217,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
} }
} }
return elementMappingMethod == null ? null : new MappingMethod( return elementMappingMethod == null ? null : new MappingMethod(
elementMappingMethod.getDeclaringMapper(),
elementMappingMethod.getName(), elementMappingMethod.getName(),
elementMappingMethod.getParameterName() elementMappingMethod.getParameterName()
); );
@ -231,7 +253,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return null; return null;
} }
private List<Method> retrieveMethods(TypeElement element) { private List<Method> retrieveMethods(Type declaringMapper, Element element) {
List<Method> methods = new ArrayList<Method>(); List<Method> methods = new ArrayList<Method>();
for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) { for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) {
@ -241,6 +263,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
methods.add( methods.add(
new Method( new Method(
declaringMapper,
method.getSimpleName().toString(), method.getSimpleName().toString(),
parameter.getName(), parameter.getName(),
parameter.getType(), parameter.getType(),
@ -250,6 +273,21 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
); );
} }
List<Type> usedMapperTypes = new LinkedList<Type>();
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
if ( mapperPrism != null ) {
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
methods.addAll(
retrieveMethods(
typeUtil.retrieveType( usedMapper ),
( (DeclaredType) usedMapper ).asElement()
)
);
}
}
return methods; return methods;
} }
@ -291,8 +329,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
sourcePropertyName, sourcePropertyName,
retrieveReturnType( getterMethod ), retrieveReturnType( getterMethod ),
mapping != null ? mapping.getTargetName() : targetPropertyName, mapping != null ? mapping.getTargetName() : targetPropertyName,
retrieveParameter( setterMethod ).getType(), retrieveParameter( setterMethod ).getType()
mapping != null ? mapping.getConverterType() : null
) )
); );
} }
@ -320,12 +357,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
} }
private Mapping getMapping(MappingPrism mapping) { private Mapping getMapping(MappingPrism mapping) {
Type converterType = typeUtil.retrieveType( mapping.converter() ); return new Mapping( mapping.source(), mapping.target() );
return new Mapping(
mapping.source(),
mapping.target(),
converterType.getName().equals( "NoOpConverter" ) ? null : converterType
);
} }
private Parameter retrieveParameter(ExecutableElement method) { private Parameter retrieveParameter(ExecutableElement method) {

View File

@ -20,19 +20,18 @@ import java.util.List;
public class Mapper { public class Mapper {
private final String packageName; private final String packageName;
private final String interfaceName; private final String interfaceName;
private final String implementationName; private final String implementationName;
private final List<BeanMapping> beanMappings; private final List<BeanMapping> beanMappings;
private final List<Type> usedMapperTypes;
public Mapper(String packageName, String interfaceName, public Mapper(String packageName, String interfaceName,
String implementationName, List<BeanMapping> beanMappings) { String implementationName, List<BeanMapping> beanMappings, List<Type> usedMapperTypes) {
this.packageName = packageName; this.packageName = packageName;
this.interfaceName = interfaceName; this.interfaceName = interfaceName;
this.implementationName = implementationName; this.implementationName = implementationName;
this.beanMappings = beanMappings; this.beanMappings = beanMappings;
this.usedMapperTypes = usedMapperTypes;
} }
public String getPackageName() { public String getPackageName() {
@ -50,4 +49,8 @@ public class Mapper {
public List<BeanMapping> getBeanMappings() { public List<BeanMapping> getBeanMappings() {
return beanMappings; return beanMappings;
} }
public List<Type> getUsedMapperTypes() {
return usedMapperTypes;
}
} }

View File

@ -17,22 +17,29 @@ package org.mapstruct.ap.model;
public class MappingMethod { public class MappingMethod {
private final Type declaringMapper;
private final String name; private final String name;
private final String parameterName; private final String parameterName;
private final MappingMethod elementMappingMethod; private final MappingMethod elementMappingMethod;
public MappingMethod(String name, String parameterName) { public MappingMethod(Type declaringMapper, String name, String parameterName) {
this.declaringMapper = declaringMapper;
this.name = name; this.name = name;
this.parameterName = parameterName; this.parameterName = parameterName;
this.elementMappingMethod = null; this.elementMappingMethod = null;
} }
public MappingMethod(String name, String parameterName, MappingMethod elementMappingMethod) { public MappingMethod(Type declaringMapper, String name, String parameterName, MappingMethod elementMappingMethod) {
this.declaringMapper = declaringMapper;
this.name = name; this.name = name;
this.parameterName = parameterName; this.parameterName = parameterName;
this.elementMappingMethod = elementMappingMethod; this.elementMappingMethod = elementMappingMethod;
} }
public Type getDeclaringMapper() {
return declaringMapper;
}
public String getName() { public String getName() {
return name; return name;
} }
@ -44,4 +51,8 @@ public class MappingMethod {
public MappingMethod getElementMappingMethod() { public MappingMethod getElementMappingMethod() {
return elementMappingMethod; return elementMappingMethod;
} }
public boolean isGenerationRequired() {
return declaringMapper == null;
}
} }

View File

@ -21,18 +21,16 @@ public class PropertyMapping {
private final Type sourceType; private final Type sourceType;
private final String targetName; private final String targetName;
private final Type targetType; private final Type targetType;
private final Type converterType;
private final MappingMethod mappingMethod; private final MappingMethod mappingMethod;
private final MappingMethod reverseMappingMethod; private final MappingMethod reverseMappingMethod;
private final String toConversion; private final String toConversion;
private final String fromConversion; private final String fromConversion;
public PropertyMapping(String sourceName, Type sourceType, String targetName, Type targetType, Type converterType, MappingMethod mappingMethod, MappingMethod reverseMappingMethod, String toConversion, String fromConversion) { public PropertyMapping(String sourceName, Type sourceType, String targetName, Type targetType, MappingMethod mappingMethod, MappingMethod reverseMappingMethod, String toConversion, String fromConversion) {
this.sourceName = sourceName; this.sourceName = sourceName;
this.sourceType = sourceType; this.sourceType = sourceType;
this.targetName = targetName; this.targetName = targetName;
this.targetType = targetType; this.targetType = targetType;
this.converterType = converterType;
this.mappingMethod = mappingMethod; this.mappingMethod = mappingMethod;
this.reverseMappingMethod = reverseMappingMethod; this.reverseMappingMethod = reverseMappingMethod;
this.toConversion = toConversion; this.toConversion = toConversion;
@ -55,10 +53,6 @@ public class PropertyMapping {
return targetType; return targetType;
} }
public Type getConverterType() {
return converterType;
}
public MappingMethod getMappingMethod() { public MappingMethod getMappingMethod() {
return mappingMethod; return mappingMethod;
} }

View File

@ -23,15 +23,12 @@ public class MappedProperty {
private final Type sourceType; private final Type sourceType;
private final String targetName; private final String targetName;
private final Type targetType; private final Type targetType;
private final Type converterType;
public MappedProperty(String sourceName, Type sourceType, String targetName, public MappedProperty(String sourceName, Type sourceType, String targetName, Type targetType) {
Type targetType, Type converterType) {
this.sourceName = sourceName; this.sourceName = sourceName;
this.sourceType = sourceType; this.sourceType = sourceType;
this.targetName = targetName; this.targetName = targetName;
this.targetType = targetType; this.targetType = targetType;
this.converterType = converterType;
} }
public String getSourceName() { public String getSourceName() {
@ -50,12 +47,8 @@ public class MappedProperty {
return targetType; return targetType;
} }
public Type getConverterType() {
return converterType;
}
@Override @Override
public String toString() { public String toString() {
return sourceType + " " + sourceName + " <=> " + targetType + " " + targetName + " (" + ( converterType != null ? converterType : "no converter" ) + ")"; return sourceType + " " + sourceName + " <=> " + targetType + " " + targetName;
} }
} }

View File

@ -15,18 +15,14 @@
*/ */
package org.mapstruct.ap.model.source; package org.mapstruct.ap.model.source;
import org.mapstruct.ap.model.Type;
public class Mapping { public class Mapping {
private final String sourceName; private final String sourceName;
private final String targetName; private final String targetName;
private final Type converterType;
public Mapping(String sourceName, String targetName, Type converterType) { public Mapping(String sourceName, String targetName) {
this.sourceName = sourceName; this.sourceName = sourceName;
this.targetName = targetName; this.targetName = targetName;
this.converterType = converterType;
} }
public String getSourceName() { public String getSourceName() {
@ -36,8 +32,4 @@ public class Mapping {
public String getTargetName() { public String getTargetName() {
return targetName; return targetName;
} }
public Type getConverterType() {
return converterType;
}
} }

View File

@ -22,6 +22,7 @@ import org.mapstruct.ap.model.Type;
public class Method { public class Method {
private final Type declaringMapper;
private final String name; private final String name;
private final String parameterName; private final String parameterName;
private final Type sourceType; private final Type sourceType;
@ -29,6 +30,11 @@ public class Method {
private final List<MappedProperty> mappedProperties; private final List<MappedProperty> mappedProperties;
public Method(String name, String parameterName, Type sourceType, Type targetType, List<MappedProperty> mappedProperties) { public Method(String name, String parameterName, Type sourceType, Type targetType, List<MappedProperty> mappedProperties) {
this( null, name, parameterName, sourceType, targetType, mappedProperties );
}
public Method(Type declaringMapper, String name, String parameterName, Type sourceType, Type targetType, List<MappedProperty> mappedProperties) {
this.declaringMapper = declaringMapper;
this.name = name; this.name = name;
this.parameterName = parameterName; this.parameterName = parameterName;
this.sourceType = sourceType; this.sourceType = sourceType;
@ -36,6 +42,10 @@ public class Method {
this.mappedProperties = mappedProperties; this.mappedProperties = mappedProperties;
} }
public Type getDeclaringMapper() {
return declaringMapper;
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -20,6 +20,7 @@ package ${packageName};
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Generated; import javax.annotation.Generated;
import java.util.Date;
@Generated( @Generated(
value = "org.mapstruct.ap.MappingProcessor", value = "org.mapstruct.ap.MappingProcessor",
@ -27,7 +28,12 @@ import javax.annotation.Generated;
) )
public class ${implementationName} implements ${interfaceName} { public class ${implementationName} implements ${interfaceName} {
<#list usedMapperTypes as mapperType>
private final ${mapperType.name} ${mapperType.name?uncap_first} = new ${mapperType.name}();
</#list>
<#list beanMappings as beanMapping> <#list beanMappings as beanMapping>
<#if beanMapping.mappingMethod.generationRequired == true>
<#if beanMapping.iterableMapping == true> <#if beanMapping.iterableMapping == true>
@Override @Override
public ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.mappingMethod.name}(${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.mappingMethod.parameterName}) { public ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.mappingMethod.name}(${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.mappingMethod.parameterName}) {
@ -53,6 +59,7 @@ public class ${implementationName} implements ${interfaceName} {
${beanMapping.targetType.name} ${beanMapping.targetType.name?uncap_first} = new ${beanMapping.targetType.name}(); ${beanMapping.targetType.name} ${beanMapping.targetType.name?uncap_first} = new ${beanMapping.targetType.name}();
<#list beanMapping.propertyMappings as propertyMapping> <#list beanMapping.propertyMappings as propertyMapping>
<#-- primitive conversion -->
<#if propertyMapping.toConversion??> <#if propertyMapping.toConversion??>
<#if propertyMapping.targetType.primitive == true> <#if propertyMapping.targetType.primitive == true>
if( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() != null ) { if( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() != null ) {
@ -63,8 +70,9 @@ public class ${implementationName} implements ${interfaceName} {
</#if> </#if>
<#elseif propertyMapping.converterType??> <#elseif propertyMapping.converterType??>
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( new ${propertyMapping.converterType.name}().from( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() ) ); ${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( new ${propertyMapping.converterType.name}().from( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() ) );
<#-- invoke mapping method -->
<#elseif propertyMapping.mappingMethod??> <#elseif propertyMapping.mappingMethod??>
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${propertyMapping.mappingMethod.name}( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() ) ); ${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( <#if propertyMapping.mappingMethod.declaringMapper??>${propertyMapping.mappingMethod.declaringMapper.name?uncap_first}.</#if>${propertyMapping.mappingMethod.name}( ${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}() );
</#if> </#if>
@ -73,8 +81,10 @@ public class ${implementationName} implements ${interfaceName} {
return ${beanMapping.targetType.name?uncap_first}; return ${beanMapping.targetType.name?uncap_first};
} }
</#if> </#if>
</#if>
<#if beanMapping.reverseMappingMethod??> <#if beanMapping.reverseMappingMethod??>
<#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}) {
@ -110,8 +120,9 @@ public class ${implementationName} implements ${interfaceName} {
</#if> </#if>
<#elseif propertyMapping.converterType??> <#elseif propertyMapping.converterType??>
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( new ${propertyMapping.converterType.name}().to( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() ) ); ${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( new ${propertyMapping.converterType.name}().to( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() ) );
<#-- invoke mapping method -->
<#elseif propertyMapping.reverseMappingMethod??> <#elseif propertyMapping.reverseMappingMethod??>
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${propertyMapping.reverseMappingMethod.name}( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() ) ); ${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( <#if propertyMapping.reverseMappingMethod.declaringMapper??>${propertyMapping.reverseMappingMethod.declaringMapper.name?uncap_first}.</#if>${propertyMapping.reverseMappingMethod.name}( ${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}() );
</#if> </#if>
@ -121,6 +132,7 @@ public class ${implementationName} implements ${interfaceName} {
} }
</#if> </#if>
</#if> </#if>
</#if>
</#list> </#list>
} }

View File

@ -18,6 +18,7 @@ package org.mapstruct.ap.test;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import javax.tools.DiagnosticCollector; import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
@ -26,7 +27,7 @@ import org.mapstruct.ap.test.model.Car;
import org.mapstruct.ap.test.model.CarDto; import org.mapstruct.ap.test.model.CarDto;
import org.mapstruct.ap.test.model.CarMapper; import org.mapstruct.ap.test.model.CarMapper;
import org.mapstruct.ap.test.model.Category; import org.mapstruct.ap.test.model.Category;
import org.mapstruct.ap.test.model.IntToStringConverter; import org.mapstruct.ap.test.model.DateMapper;
import org.mapstruct.ap.test.model.Person; import org.mapstruct.ap.test.model.Person;
import org.mapstruct.ap.test.model.PersonDto; import org.mapstruct.ap.test.model.PersonDto;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
@ -51,8 +52,8 @@ public class CarMapperTest extends MapperTestBase {
Person.class, Person.class,
PersonDto.class, PersonDto.class,
CarMapper.class, CarMapper.class,
IntToStringConverter.class, Category.class,
Category.class DateMapper.class
); );
boolean compilationSuccessful = compile( diagnostics, sourceFiles ); boolean compilationSuccessful = compile( diagnostics, sourceFiles );
@ -69,7 +70,13 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldMapAttributeByName() { public void shouldMapAttributeByName() {
//given //given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() ); Car car = new Car(
"Morris",
2,
new GregorianCalendar( 1980, 0, 1 ).getTime(),
new Person( "Bob" ),
new ArrayList<Person>()
);
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -82,7 +89,13 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldMapReferenceAttribute() { public void shouldMapReferenceAttribute() {
//given //given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() ); Car car = new Car(
"Morris",
2,
new GregorianCalendar( 1980, 0, 1 ).getTime(),
new Person( "Bob" ),
new ArrayList<Person>()
);
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -110,7 +123,13 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldMapAttributeWithCustomMapping() { public void shouldMapAttributeWithCustomMapping() {
//given //given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() ); Car car = new Car(
"Morris",
2,
new GregorianCalendar( 1980, 0, 1 ).getTime(),
new Person( "Bob" ),
new ArrayList<Person>()
);
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -136,7 +155,13 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldApplyConverter() { public void shouldApplyConverter() {
//given //given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() ); Car car = new Car(
"Morris",
2,
new GregorianCalendar( 1980, 0, 1 ).getTime(),
new Person( "Bob" ),
new ArrayList<Person>()
);
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -156,14 +181,26 @@ public class CarMapperTest extends MapperTestBase {
//then //then
assertThat( car ).isNotNull(); assertThat( car ).isNotNull();
assertThat( car.getYearOfManufacture() ).isEqualTo( 1980 ); assertThat( car.getManufacturingDate() ).isEqualTo( new GregorianCalendar( 1980, 0, 1 ).getTime() );
} }
@Test @Test
public void shouldMapIterable() { public void shouldMapIterable() {
//given //given
Car car1 = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() ); Car car1 = new Car(
Car car2 = new Car( "Railton", 4, 1934, new Person( "Bill" ), new ArrayList<Person>() ); "Morris",
2,
new GregorianCalendar( 1980, 0, 1 ).getTime(),
new Person( "Bob" ),
new ArrayList<Person>()
);
Car car2 = new Car(
"Railton",
4,
new GregorianCalendar( 1934, 0, 1 ).getTime(),
new Person( "Bill" ),
new ArrayList<Person>()
);
//when //when
List<CarDto> dtos = CarMapper.INSTANCE.carsToCarDtos( new ArrayList<Car>( Arrays.asList( car1, car2 ) ) ); List<CarDto> dtos = CarMapper.INSTANCE.carsToCarDtos( new ArrayList<Car>( Arrays.asList( car1, car2 ) ) );
@ -198,12 +235,12 @@ public class CarMapperTest extends MapperTestBase {
assertThat( cars.get( 0 ).getMake() ).isEqualTo( "Morris" ); assertThat( cars.get( 0 ).getMake() ).isEqualTo( "Morris" );
assertThat( cars.get( 0 ).getNumberOfSeats() ).isEqualTo( 2 ); assertThat( cars.get( 0 ).getNumberOfSeats() ).isEqualTo( 2 );
assertThat( cars.get( 0 ).getYearOfManufacture() ).isEqualTo( 1980 ); assertThat( cars.get( 0 ).getManufacturingDate() ).isEqualTo( new GregorianCalendar( 1980, 0, 1 ).getTime() );
assertThat( cars.get( 0 ).getDriver().getName() ).isEqualTo( "Bob" ); assertThat( cars.get( 0 ).getDriver().getName() ).isEqualTo( "Bob" );
assertThat( cars.get( 1 ).getMake() ).isEqualTo( "Railton" ); assertThat( cars.get( 1 ).getMake() ).isEqualTo( "Railton" );
assertThat( cars.get( 1 ).getNumberOfSeats() ).isEqualTo( 4 ); assertThat( cars.get( 1 ).getNumberOfSeats() ).isEqualTo( 4 );
assertThat( cars.get( 1 ).getYearOfManufacture() ).isEqualTo( 1934 ); assertThat( cars.get( 1 ).getManufacturingDate() ).isEqualTo( new GregorianCalendar( 1934, 0, 1 ).getTime() );
assertThat( cars.get( 1 ).getDriver().getName() ).isEqualTo( "Bill" ); assertThat( cars.get( 1 ).getDriver().getName() ).isEqualTo( "Bill" );
} }
@ -213,7 +250,7 @@ public class CarMapperTest extends MapperTestBase {
Car car = new Car( Car car = new Car(
"Morris", "Morris",
2, 2,
1980, new GregorianCalendar( 1980, 0, 1 ).getTime(),
new Person( "Bob" ), new Person( "Bob" ),
new ArrayList<Person>( Arrays.asList( new Person( "Alice" ), new Person( "Bill" ) ) ) new ArrayList<Person>( Arrays.asList( new Person( "Alice" ), new Person( "Bill" ) ) )
); );

View File

@ -16,12 +16,13 @@
package org.mapstruct.ap.test.model; package org.mapstruct.ap.test.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
public class Car { public class Car {
private String make; private String make;
private int numberOfSeats; private int numberOfSeats;
private int yearOfManufacture; private Date manufacturingDate;
private Person driver; private Person driver;
private ArrayList<Person> passengers; private ArrayList<Person> passengers;
private int price; private int price;
@ -30,10 +31,10 @@ public class Car {
public Car() { public Car() {
} }
public Car(String make, int numberOfSeats, int yearOfManufacture, Person driver, ArrayList<Person> passengers) { public Car(String make, int numberOfSeats, Date manufacturingDate, Person driver, ArrayList<Person> passengers) {
this.make = make; this.make = make;
this.numberOfSeats = numberOfSeats; this.numberOfSeats = numberOfSeats;
this.yearOfManufacture = yearOfManufacture; this.manufacturingDate = manufacturingDate;
this.driver = driver; this.driver = driver;
this.passengers = passengers; this.passengers = passengers;
} }
@ -54,12 +55,12 @@ public class Car {
this.numberOfSeats = numberOfSeats; this.numberOfSeats = numberOfSeats;
} }
public int getYearOfManufacture() { public Date getManufacturingDate() {
return yearOfManufacture; return manufacturingDate;
} }
public void setYearOfManufacture(int yearOfManufacture) { public void setManufacturingDate(Date manufacturingDate) {
this.yearOfManufacture = yearOfManufacture; this.manufacturingDate = manufacturingDate;
} }
public Person getDriver() { public Person getDriver() {

View File

@ -22,14 +22,14 @@ import org.mapstruct.Mappers;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
@Mapper @Mapper(uses = DateMapper.class)
public interface CarMapper { public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class ); CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
@Mappings({ @Mappings({
@Mapping(source = "numberOfSeats", target = "seatCount"), @Mapping(source = "numberOfSeats", target = "seatCount"),
@Mapping(source = "yearOfManufacture", target = "manufacturingYear", converter = IntToStringConverter.class) @Mapping(source = "manufacturingDate", target = "manufacturingYear")
}) })
CarDto carToCarDto(Car car); CarDto carToCarDto(Car car);

View File

@ -15,17 +15,22 @@
*/ */
package org.mapstruct.ap.test.model; package org.mapstruct.ap.test.model;
import org.mapstruct.converter.Converter; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class IntToStringConverter implements Converter<Integer, String> { public class DateMapper {
@Override public String asString(Date date) {
public String from(Integer source) { return date != null ? new SimpleDateFormat( "yyyy" ).format( date ) : null;
return source != null ? source.toString() : null;
} }
@Override public Date asDate(String date) {
public Integer to(String target) { try {
return target != null ? Integer.valueOf( target ) : null; return date != null ? new SimpleDateFormat( "yyyy" ).parse( date ) : null;
}
catch ( ParseException e ) {
throw new RuntimeException( e );
}
} }
} }