From 192cfc893739f9ae7b5a02770d09685816bd5afa Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Sat, 2 Mar 2013 15:10:48 +0100 Subject: [PATCH] #1 Providing infrastructure for implicit conversions --- .../mapstruct/ap/MapperGenerationVisitor.java | 25 +++- .../mapstruct/ap/conversion/Conversion.java | 23 ++++ .../mapstruct/ap/conversion/Conversions.java | 98 +++++++++++++++ .../ap/conversion/IntLongConversion.java | 29 +++++ .../ap/conversion/IntStringConversion.java | 29 +++++ .../ap/conversion/ReverseConversion.java | 39 ++++++ .../mapstruct/ap/model/PropertyMapping.java | 26 +++- .../java/org/mapstruct/ap/model/Type.java | 24 ++++ .../main/resources/mapper-implementation.ftl | 24 +++- .../org/mapstruct/ap/test/ConversionTest.java | 119 ++++++++++++++++++ .../mapstruct/ap/test/conversion/Source.java | 65 ++++++++++ .../test/conversion/SourceTargetMapper.java | 35 ++++++ .../mapstruct/ap/test/conversion/Target.java | 65 ++++++++++ .../java/org/mapstruct/ap/test/model/Car.java | 9 ++ .../org/mapstruct/ap/test/model/CarDto.java | 9 ++ .../mapstruct/ap/test/model/CarMapper.java | 1 - 16 files changed, 611 insertions(+), 9 deletions(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/conversion/Conversion.java create mode 100644 processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java create mode 100644 processor/src/main/java/org/mapstruct/ap/conversion/IntLongConversion.java create mode 100644 processor/src/main/java/org/mapstruct/ap/conversion/IntStringConversion.java create mode 100644 processor/src/main/java/org/mapstruct/ap/conversion/ReverseConversion.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/ConversionTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/conversion/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/conversion/SourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/conversion/Target.java diff --git a/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java b/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java index 24158f26d..d6ec70618 100644 --- a/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java +++ b/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java @@ -41,6 +41,8 @@ import javax.lang.model.util.SimpleAnnotationValueVisitor6; import javax.lang.model.util.Types; import javax.tools.JavaFileObject; +import org.mapstruct.ap.conversion.Conversion; +import org.mapstruct.ap.conversion.Conversions; import org.mapstruct.ap.model.BeanMapping; import org.mapstruct.ap.model.Mapper; import org.mapstruct.ap.model.MappingMethod; @@ -52,7 +54,6 @@ import org.mapstruct.ap.model.source.Method; import org.mapstruct.ap.model.source.Parameter; import org.mapstruct.ap.writer.ModelWriter; - import static javax.lang.model.util.ElementFilter.methodsIn; public class MapperGenerationVisitor extends ElementKindVisitor6 { @@ -131,10 +132,14 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { Method propertyMappingMethod = getPropertyMappingMethod( methods, property ); Method reversePropertyMappingMethod = getReversePropertyMappingMethod( methods, property ); + Conversion conversion = Conversions.getConversion( property.getSourceType(), property.getTargetType() ); + propertyMappings.add( new PropertyMapping( property.getSourceName(), + property.getSourceType(), property.getTargetName(), + property.getTargetType(), property.getConverterType(), propertyMappingMethod != null ? new MappingMethod( propertyMappingMethod.getName(), @@ -143,6 +148,16 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { reversePropertyMappingMethod != null ? new MappingMethod( reversePropertyMappingMethod.getName(), reversePropertyMappingMethod.getParameterName() + ) : null, + conversion != null ? conversion.to( + mappingMethod.getParameterName() + "." + getAccessor( + property.getSourceName() + ) + ) : null, + conversion != null ? conversion.from( + reverseMappingMethod.getParameterName() + "." + getAccessor( + property.getTargetName() + ) ) : null ) ); @@ -168,6 +183,14 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { return mapper; } + private String getAccessor(String name) { + return "get" + capitalize( name ) + "()"; + } + + private String capitalize(String name) { + return name.substring( 0, 1 ).toUpperCase() + name.substring( 1 ); + } + private MappingMethod getElementMappingMethod(Iterable methods, Method method) { Method elementMappingMethod = null; for ( Method oneMethod : methods ) { diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/Conversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/Conversion.java new file mode 100644 index 000000000..b641fa988 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/conversion/Conversion.java @@ -0,0 +1,23 @@ +/** + * 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.conversion; + +public interface Conversion { + + String to(String sourcePropertyAccessor); + + String from(String targetPropertyAccessor); +} diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java b/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java new file mode 100644 index 000000000..9e7a5ca7d --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/conversion/Conversions.java @@ -0,0 +1,98 @@ +/** + * 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.conversion; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.mapstruct.ap.model.Type; + +import static org.mapstruct.ap.conversion.ReverseConversion.reverse; + +public class Conversions { + + private static ConcurrentMap conversions = new ConcurrentHashMap(); + + static { + register( int.class, Long.class, new IntLongConversion() ); + register( int.class, String.class, new IntStringConversion() ); + } + + private static void register(Class sourceType, Class targetType, Conversion conversion) { + conversions.put( Key.forClasses( sourceType, targetType ), conversion ); + conversions.put( Key.forClasses( targetType, sourceType ), reverse( conversion ) ); + } + + public static Conversion getConversion(Type sourceType, Type targetType) { + return conversions.get( new Key( sourceType, targetType ) ); + } + + private static class Key { + private final Type sourceType; + private final Type targetType; + + private static Key forClasses(Class sourceType, Class targetType) { + return new Key( Type.forClass( sourceType ), Type.forClass( targetType ) ); + } + + private Key(Type sourceType, Type targetType) { + this.sourceType = sourceType; + this.targetType = targetType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ( ( sourceType == null ) ? 0 : sourceType.hashCode() ); + result = prime * result + + ( ( targetType == null ) ? 0 : targetType.hashCode() ); + return result; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + Key other = (Key) obj; + if ( sourceType == null ) { + if ( other.sourceType != null ) { + return false; + } + } + else if ( !sourceType.equals( other.sourceType ) ) { + return false; + } + if ( targetType == null ) { + if ( other.targetType != null ) { + return false; + } + } + else if ( !targetType.equals( other.targetType ) ) { + return false; + } + return true; + } + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/IntLongConversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/IntLongConversion.java new file mode 100644 index 000000000..109ffb650 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/conversion/IntLongConversion.java @@ -0,0 +1,29 @@ +/** + * 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.conversion; + +public class IntLongConversion implements Conversion { + + @Override + public String to(String sourcePropertyAccessor) { + return "Long.valueOf( " + sourcePropertyAccessor + " )"; + } + + @Override + public String from(String targetPropertyAccessor) { + return targetPropertyAccessor + ".intValue()"; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/IntStringConversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/IntStringConversion.java new file mode 100644 index 000000000..3000d6bb4 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/conversion/IntStringConversion.java @@ -0,0 +1,29 @@ +/** + * 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.conversion; + +public class IntStringConversion implements Conversion { + + @Override + public String to(String sourcePropertyAccessor) { + return "String.valueOf( " + sourcePropertyAccessor + " )"; + } + + @Override + public String from(String targetPropertyAccessor) { + return "Integer.parseInt( " + targetPropertyAccessor + " )"; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/ReverseConversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/ReverseConversion.java new file mode 100644 index 000000000..a3570377d --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/conversion/ReverseConversion.java @@ -0,0 +1,39 @@ +/** + * 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.conversion; + +public class ReverseConversion implements Conversion { + + private Conversion conversion; + + public static ReverseConversion reverse(Conversion conversion) { + return new ReverseConversion( conversion ); + } + + private ReverseConversion(Conversion conversion) { + this.conversion = conversion; + } + + @Override + public String to(String sourcePropertyAccessor) { + return conversion.from( sourcePropertyAccessor ); + } + + @Override + public String from(String targetPropertyAccessor) { + return conversion.to( targetPropertyAccessor ); + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java index c1c4a14bb..b5c14efb6 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java @@ -18,27 +18,43 @@ package org.mapstruct.ap.model; public class PropertyMapping { private final String sourceName; + private final Type sourceType; private final String targetName; + private final Type targetType; private final Type converterType; private final MappingMethod mappingMethod; private final MappingMethod reverseMappingMethod; + private final String toConversion; + private final String fromConversion; - public PropertyMapping(String sourceName, String targetName, Type converterType, MappingMethod mappingMethod, MappingMethod reverseMappingMethod) { + public PropertyMapping(String sourceName, Type sourceType, String targetName, Type targetType, Type converterType, MappingMethod mappingMethod, MappingMethod reverseMappingMethod, String toConversion, String fromConversion) { this.sourceName = sourceName; + this.sourceType = sourceType; this.targetName = targetName; + this.targetType = targetType; this.converterType = converterType; this.mappingMethod = mappingMethod; this.reverseMappingMethod = reverseMappingMethod; + this.toConversion = toConversion; + this.fromConversion = fromConversion; } public String getSourceName() { return sourceName; } + public Type getSourceType() { + return sourceType; + } + public String getTargetName() { return targetName; } + public Type getTargetType() { + return targetType; + } + public Type getConverterType() { return converterType; } @@ -50,4 +66,12 @@ public class PropertyMapping { public MappingMethod getReverseMappingMethod() { return reverseMappingMethod; } + + public String getToConversion() { + return toConversion; + } + + public String getFromConversion() { + return fromConversion; + } } 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 8da437ef8..1a1217c2e 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Type.java @@ -15,6 +15,10 @@ */ package org.mapstruct.ap.model; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + /** * Represents the type of a bean property, parameter etc. * @@ -22,10 +26,26 @@ package org.mapstruct.ap.model; */ public class Type { + private final static Set primitiveTypeNames = new HashSet( + Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" ) + ); + private final String packageName; private final String name; private final Type elementType; + + public static Type forClass(Class clazz) { + Package pakkage = clazz.getPackage(); + + if ( pakkage != null ) { + return new Type( pakkage.getName(), clazz.getSimpleName() ); + } + else { + return new Type( clazz.getSimpleName() ); + } + } + public Type(String name) { this.packageName = null; this.name = name; @@ -56,6 +76,10 @@ public class Type { return elementType; } + public boolean isPrimitive() { + return packageName == null && primitiveTypeNames.contains( name ); + } + @Override public String toString() { if ( packageName == null ) { diff --git a/processor/src/main/resources/mapper-implementation.ftl b/processor/src/main/resources/mapper-implementation.ftl index b531dd76b..75b92a236 100644 --- a/processor/src/main/resources/mapper-implementation.ftl +++ b/processor/src/main/resources/mapper-implementation.ftl @@ -26,7 +26,6 @@ public class ${implementationName} implements ${interfaceName} { <#if beanMapping.iterableMapping == true> @Override public ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.mappingMethod.name}(${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.mappingMethod.parameterName}) { - ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.targetType.name?uncap_first} = new ${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}>(); for ( ${beanMapping.sourceType.elementType.name} ${beanMapping.sourceType.elementType.name?uncap_first} : ${beanMapping.mappingMethod.parameterName} ) { @@ -38,11 +37,18 @@ public class ${implementationName} implements ${interfaceName} { <#else> @Override public ${beanMapping.targetType.name} ${beanMapping.mappingMethod.name}(${beanMapping.sourceType.name} ${beanMapping.mappingMethod.parameterName}) { - ${beanMapping.targetType.name} ${beanMapping.targetType.name?uncap_first} = new ${beanMapping.targetType.name}(); <#list beanMapping.propertyMappings as propertyMapping> - <#if propertyMapping.converterType??> + <#if propertyMapping.toConversion??> + <#if propertyMapping.targetType.primitive == true> + if( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() != null ) { + ${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${propertyMapping.toConversion} ); + } + <#else> + ${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${propertyMapping.toConversion} ); + + <#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}() ) ); <#elseif propertyMapping.mappingMethod??> ${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${propertyMapping.mappingMethod.name}( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() ) ); @@ -56,11 +62,9 @@ public class ${implementationName} implements ${interfaceName} { <#if beanMapping.reverseMappingMethod??> - <#if beanMapping.iterableMapping == true> @Override public ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.reverseMappingMethod.name}(${beanMapping.targetType.name}<${beanMapping.targetType.elementType.name}> ${beanMapping.reverseMappingMethod.parameterName}) { - ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}> ${beanMapping.sourceType.name?uncap_first} = new ${beanMapping.sourceType.name}<${beanMapping.sourceType.elementType.name}>(); for ( ${beanMapping.targetType.elementType.name} ${beanMapping.targetType.elementType.name?uncap_first} : ${beanMapping.reverseMappingMethod.parameterName} ) { @@ -75,7 +79,15 @@ public class ${implementationName} implements ${interfaceName} { ${beanMapping.sourceType.name} ${beanMapping.sourceType.name?uncap_first} = new ${beanMapping.sourceType.name}(); <#list beanMapping.propertyMappings as propertyMapping> - <#if propertyMapping.converterType??> + <#if propertyMapping.fromConversion??> + <#if propertyMapping.sourceType.primitive == true> + if( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() != null ) { + ${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${propertyMapping.fromConversion} ); + } + <#else> + ${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${propertyMapping.fromConversion} ); + + <#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}() ) ); <#elseif propertyMapping.reverseMappingMethod??> ${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${propertyMapping.reverseMappingMethod.name}( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() ) ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/ConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/ConversionTest.java new file mode 100644 index 000000000..9232ed077 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/ConversionTest.java @@ -0,0 +1,119 @@ +/** + * 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; + +import java.io.File; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; + +import org.mapstruct.ap.test.conversion.Source; +import org.mapstruct.ap.test.conversion.SourceTargetMapper; +import org.mapstruct.ap.test.conversion.Target; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.fest.assertions.Assertions.assertThat; + +public class ConversionTest extends MapperTestBase { + + private DiagnosticCollector diagnostics; + + public ConversionTest() { + super( "mapstruct.jar" ); + } + + @BeforeMethod + public void generateMapperImplementation() { + diagnostics = new DiagnosticCollector(); + File[] sourceFiles = getSourceFiles( + Source.class, + Target.class, + SourceTargetMapper.class + ); + + boolean compilationSuccessful = compile( diagnostics, sourceFiles ); + + assertThat( compilationSuccessful ).describedAs( "Compilation failed: " + diagnostics.getDiagnostics() ) + .isTrue(); + } + + @Test + public void shouldApplyConversions() { + Source source = new Source(); + source.setFoo( 42 ); + source.setBar( 23L ); + source.setZip( 73 ); + + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) ); + assertThat( target.getBar() ).isEqualTo( 23 ); + assertThat( target.getZip() ).isEqualTo( "73" ); + } + + @Test + public void shouldHandleNulls() { + Source source = new Source(); + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 0 ) ); + assertThat( target.getBar() ).isEqualTo( 0 ); + assertThat( target.getZip() ).isEqualTo( "0" ); + } + + @Test + public void shouldApplyConversionsToMappedProperties() { + Source source = new Source(); + source.setQax( 42 ); + source.setBaz( 23L ); + + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getBaz() ).isEqualTo( Long.valueOf( 42 ) ); + assertThat( target.getQax() ).isEqualTo( 23 ); + } + + @Test + public void shouldApplyConversionsForReverseMapping() { + Target target = new Target(); + target.setFoo( 42L ); + target.setBar( 23 ); + target.setZip( "73" ); + + Source source = SourceTargetMapper.INSTANCE.targetToSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getFoo() ).isEqualTo( 42 ); + assertThat( source.getBar() ).isEqualTo( 23 ); + assertThat( source.getZip() ).isEqualTo( 73 ); + } + + @Test + public void shouldApplyConversionsToMappedPropertiesForReverseMapping() { + Target target = new Target(); + target.setQax( 42 ); + target.setBaz( 23L ); + + Source source = SourceTargetMapper.INSTANCE.targetToSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getBaz() ).isEqualTo( 42 ); + assertThat( source.getQax() ).isEqualTo( 23 ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/Source.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/Source.java new file mode 100644 index 000000000..aa0c7ba76 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/Source.java @@ -0,0 +1,65 @@ +/** + * 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.conversion; + +public class Source { + + private int foo; + private Long bar; + private int qax; + private Long baz; + private int zip; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } + + public Long getBar() { + return bar; + } + + public void setBar(Long bar) { + this.bar = bar; + } + + public int getQax() { + return qax; + } + + public void setQax(int qax) { + this.qax = qax; + } + + public Long getBaz() { + return baz; + } + + public void setBaz(Long baz) { + this.baz = baz; + } + + public int getZip() { + return zip; + } + + public void setZip(int zip) { + this.zip = zip; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/SourceTargetMapper.java new file mode 100644 index 000000000..424e34063 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/SourceTargetMapper.java @@ -0,0 +1,35 @@ +/** + * 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.conversion; + +import org.mapstruct.Mapper; +import org.mapstruct.Mappers; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; + +@Mapper +public interface SourceTargetMapper { + + public static SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + @Mappings({ + @Mapping(source = "qax", target = "baz"), + @Mapping(source = "baz", target = "qax") + }) + Target sourceToTarget(Source source); + + Source targetToSource(Target target); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/Target.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/Target.java new file mode 100644 index 000000000..3094d5de8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/Target.java @@ -0,0 +1,65 @@ +/** + * 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.conversion; + +public class Target { + + private Long foo; + private int bar; + private Long baz; + private int qax; + private String zip; + + public Long getFoo() { + return foo; + } + + public void setFoo(Long foo) { + this.foo = foo; + } + + public int getBar() { + return bar; + } + + public void setBar(int bar) { + this.bar = bar; + } + + public Long getBaz() { + return baz; + } + + public void setBaz(Long baz) { + this.baz = baz; + } + + public int getQax() { + return qax; + } + + public void setQax(int qax) { + this.qax = qax; + } + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/model/Car.java b/processor/src/test/java/org/mapstruct/ap/test/model/Car.java index 8661bd8b6..c24e74d97 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/model/Car.java +++ b/processor/src/test/java/org/mapstruct/ap/test/model/Car.java @@ -24,6 +24,7 @@ public class Car { private int yearOfManufacture; private Person driver; private ArrayList passengers; + private int price; public Car() { } @@ -75,4 +76,12 @@ public class Car { public void setPassengers(ArrayList passengers) { this.passengers = passengers; } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java b/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java index 7193a6cc0..74eb8226b 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java +++ b/processor/src/test/java/org/mapstruct/ap/test/model/CarDto.java @@ -24,6 +24,7 @@ public class CarDto { private String manufacturingYear; private PersonDto driver; private ArrayList passengers; + private Long price; public CarDto() { } @@ -75,4 +76,12 @@ public class CarDto { public void setPassengers(ArrayList passengers) { this.passengers = passengers; } + + public Long getPrice() { + return price; + } + + public void setPrice(Long price) { + this.price = price; + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java b/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java index 07d8e9dfc..de8943048 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/model/CarMapper.java @@ -22,7 +22,6 @@ import org.mapstruct.Mappers; import org.mapstruct.Mapping; import org.mapstruct.Mappings; - @Mapper public interface CarMapper {