mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
Adding support for multiple bindings, adding converters
This commit is contained in:
parent
02006a90b7
commit
e07add7d43
@ -15,10 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package de.moapa.maple;
|
package de.moapa.maple;
|
||||||
|
|
||||||
|
import de.moapa.maple.converter.Converter;
|
||||||
|
import de.moapa.maple.converter.NoOpConverter;
|
||||||
|
|
||||||
public @interface Mapping {
|
public @interface Mapping {
|
||||||
|
|
||||||
String source();
|
String source();
|
||||||
|
|
||||||
String target();
|
String target();
|
||||||
|
|
||||||
|
Class<? extends Converter<?, ?>> converter() default NoOpConverter.class;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
22
core/src/main/java/de/moapa/maple/Mappings.java
Normal file
22
core/src/main/java/de/moapa/maple/Mappings.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012 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 de.moapa.maple;
|
||||||
|
|
||||||
|
|
||||||
|
public @interface Mappings {
|
||||||
|
|
||||||
|
Mapping[] value();
|
||||||
|
}
|
23
core/src/main/java/de/moapa/maple/converter/Converter.java
Normal file
23
core/src/main/java/de/moapa/maple/converter/Converter.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012 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 de.moapa.maple.converter;
|
||||||
|
|
||||||
|
public interface Converter<S, T> {
|
||||||
|
|
||||||
|
T from(S source);
|
||||||
|
|
||||||
|
S to(T target);
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012 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 de.moapa.maple.converter;
|
||||||
|
|
||||||
|
public class NoOpConverter implements Converter<Object, Object> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object from(Object source) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object to(Object target) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ package de.moapa.maple.ap;
|
|||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
@ -26,8 +27,13 @@ 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.TypeMirror;
|
||||||
import javax.lang.model.util.ElementKindVisitor6;
|
import javax.lang.model.util.ElementKindVisitor6;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.SimpleAnnotationValueVisitor6;
|
import javax.lang.model.util.SimpleAnnotationValueVisitor6;
|
||||||
|
import javax.lang.model.util.TypeKindVisitor6;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
import de.moapa.maple.ap.model.Binding;
|
import de.moapa.maple.ap.model.Binding;
|
||||||
@ -48,12 +54,24 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
|
|
||||||
private final static String MAPPING_ANNOTATION = "de.moapa.maple.Mapping";
|
private final static String MAPPING_ANNOTATION = "de.moapa.maple.Mapping";
|
||||||
|
|
||||||
|
private final static String MAPPINGS_ANNOTATION = "de.moapa.maple.Mappings";
|
||||||
|
|
||||||
|
private final static String CONVERTER_TYPE = "de.moapa.maple.converter.Converter";
|
||||||
|
|
||||||
private final ProcessingEnvironment processingEnvironment;
|
private final ProcessingEnvironment processingEnvironment;
|
||||||
|
|
||||||
private final Configuration configuration;
|
private final Configuration configuration;
|
||||||
|
|
||||||
|
private final Types typeUtils;
|
||||||
|
|
||||||
|
private final Elements elementUtils;
|
||||||
|
|
||||||
public MapperGenerationVisitor(ProcessingEnvironment processingEnvironment, Configuration configuration) {
|
public MapperGenerationVisitor(ProcessingEnvironment processingEnvironment, Configuration configuration) {
|
||||||
|
|
||||||
this.processingEnvironment = processingEnvironment;
|
this.processingEnvironment = processingEnvironment;
|
||||||
|
this.typeUtils = processingEnvironment.getTypeUtils();
|
||||||
|
this.elementUtils = processingEnvironment.getElementUtils();
|
||||||
|
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +104,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
private Mapper retrieveModel(TypeElement element) {
|
private Mapper retrieveModel(TypeElement element) {
|
||||||
|
|
||||||
return new Mapper(
|
return new Mapper(
|
||||||
processingEnvironment.getElementUtils().getPackageOf( element ).getQualifiedName().toString(),
|
elementUtils.getPackageOf( element ).getQualifiedName().toString(),
|
||||||
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
|
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
|
||||||
element.getSimpleName().toString(),
|
element.getSimpleName().toString(),
|
||||||
retrieveMethods( element )
|
retrieveMethods( element )
|
||||||
@ -128,6 +146,33 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
if ( MAPPING_ANNOTATION.equals( annotationName ) ) {
|
if ( MAPPING_ANNOTATION.equals( annotationName ) ) {
|
||||||
bindings.add( retrieveBinding( annotationMirror ) );
|
bindings.add( retrieveBinding( annotationMirror ) );
|
||||||
}
|
}
|
||||||
|
else if ( MAPPINGS_ANNOTATION.equals( annotationName ) ) {
|
||||||
|
bindings.addAll( retrieveBindings( annotationMirror ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Binding> retrieveBindings(AnnotationMirror annotationMirror) {
|
||||||
|
|
||||||
|
List<Binding> bindings = new ArrayList<Binding>();
|
||||||
|
|
||||||
|
for ( Entry<? extends ExecutableElement, ? extends AnnotationValue> oneAttribute : annotationMirror.getElementValues()
|
||||||
|
.entrySet() ) {
|
||||||
|
|
||||||
|
if ( oneAttribute.getKey().getSimpleName().contentEquals( "value" ) ) {
|
||||||
|
List<? extends AnnotationValue> values = oneAttribute.getValue()
|
||||||
|
.accept( new AnnotationValueListRetrievingVisitor(), null );
|
||||||
|
|
||||||
|
for ( AnnotationValue oneAnnotationValue : values ) {
|
||||||
|
AnnotationMirror oneAnnotation = oneAnnotationValue.accept(
|
||||||
|
new AnnotationRetrievingVisitor(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
bindings.add( retrieveBinding( oneAnnotation ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindings;
|
return bindings;
|
||||||
@ -137,19 +182,60 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
|
|
||||||
String sourcePropertyName = null;
|
String sourcePropertyName = null;
|
||||||
String targetPropertyName = null;
|
String targetPropertyName = null;
|
||||||
|
Type converterType = null;
|
||||||
|
Type sourceType = null;
|
||||||
|
Type targetType = null;
|
||||||
|
|
||||||
for ( Entry<? extends ExecutableElement, ? extends AnnotationValue> oneAttribute : annotationMirror.getElementValues()
|
for ( Entry<? extends ExecutableElement, ? extends AnnotationValue> oneAttribute : annotationMirror.getElementValues()
|
||||||
.entrySet() ) {
|
.entrySet() ) {
|
||||||
|
|
||||||
if ( oneAttribute.getKey().getSimpleName().contentEquals( "source" ) ) {
|
if ( oneAttribute.getKey().getSimpleName().contentEquals( "source" ) ) {
|
||||||
sourcePropertyName = oneAttribute.getValue().accept( new ValueRetrievingVisitor(), null );
|
sourcePropertyName = oneAttribute.getValue().accept( new StringValueRetrievingVisitor(), null );
|
||||||
}
|
}
|
||||||
else if ( oneAttribute.getKey().getSimpleName().contentEquals( "target" ) ) {
|
else if ( oneAttribute.getKey().getSimpleName().contentEquals( "target" ) ) {
|
||||||
targetPropertyName = oneAttribute.getValue().accept( new ValueRetrievingVisitor(), null );
|
targetPropertyName = oneAttribute.getValue().accept( new StringValueRetrievingVisitor(), null );
|
||||||
|
}
|
||||||
|
else if ( oneAttribute.getKey().getSimpleName().contentEquals( "converter" ) ) {
|
||||||
|
TypeMirror converterTypeMirror = oneAttribute.getValue()
|
||||||
|
.accept(
|
||||||
|
new TypeRetrievingVisitor(), null
|
||||||
|
);
|
||||||
|
|
||||||
|
converterType = getType( typeUtils.asElement( converterTypeMirror ) );
|
||||||
|
|
||||||
|
List<? extends TypeMirror> converterTypeParameters = getTypeParameters(
|
||||||
|
converterTypeMirror,
|
||||||
|
CONVERTER_TYPE
|
||||||
|
);
|
||||||
|
|
||||||
|
sourceType = getType( typeUtils.asElement( converterTypeParameters.get( 0 ) ) );
|
||||||
|
targetType = getType( typeUtils.asElement( converterTypeParameters.get( 1 ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Binding( sourcePropertyName, targetPropertyName );
|
return new Binding( sourceType, sourcePropertyName, targetType, targetPropertyName, converterType );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type getType(Element sourceTypeElement) {
|
||||||
|
return new Type(
|
||||||
|
elementUtils.getPackageOf( sourceTypeElement ).toString(),
|
||||||
|
sourceTypeElement.getSimpleName().toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: consider complete type hierarchy
|
||||||
|
private List<? extends TypeMirror> getTypeParameters(TypeMirror type, String superTypeName) {
|
||||||
|
|
||||||
|
for ( TypeMirror oneSuperType : typeUtils.directSupertypes( type ) ) {
|
||||||
|
String oneSuperTypeName = typeUtils.asElement( oneSuperType )
|
||||||
|
.accept( new NameDeterminationVisitor(), null );
|
||||||
|
|
||||||
|
if ( oneSuperTypeName.equals( superTypeName ) ) {
|
||||||
|
return oneSuperType.accept( new TypeParameterDeterminationVisitor(), null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Parameter retrieveParameter(ExecutableElement method) {
|
private Parameter retrieveParameter(ExecutableElement method) {
|
||||||
@ -161,31 +247,35 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VariableElement parameter = parameters.get( 0 );
|
||||||
|
|
||||||
return new Parameter(
|
return new Parameter(
|
||||||
parameters.get( 0 ).getSimpleName().toString(),
|
parameter.getSimpleName().toString(),
|
||||||
new Type(
|
new Type(
|
||||||
processingEnvironment.getElementUtils()
|
elementUtils.getPackageOf( parameter ).getQualifiedName().toString(),
|
||||||
.getPackageOf( parameters.get( 0 ) )
|
typeUtils.asElement( parameter.asType() ).getSimpleName().toString()
|
||||||
.getQualifiedName()
|
|
||||||
.toString(),
|
|
||||||
processingEnvironment.getTypeUtils()
|
|
||||||
.asElement( parameters.get( 0 ).asType() )
|
|
||||||
.getSimpleName()
|
|
||||||
.toString()
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type retrieveReturnType(ExecutableElement method) {
|
private Type retrieveReturnType(ExecutableElement method) {
|
||||||
|
|
||||||
Element returnTypeElement = processingEnvironment.getTypeUtils().asElement( method.getReturnType() );
|
Element returnTypeElement = typeUtils.asElement( method.getReturnType() );
|
||||||
|
|
||||||
return new Type(
|
return new Type(
|
||||||
processingEnvironment.getElementUtils().getPackageOf( returnTypeElement ).getQualifiedName().toString(),
|
elementUtils.getPackageOf( returnTypeElement ).getQualifiedName().toString(),
|
||||||
returnTypeElement.getSimpleName().toString()
|
returnTypeElement.getSimpleName().toString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TypeParameterDeterminationVisitor extends TypeKindVisitor6<List<? extends TypeMirror>, Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends TypeMirror> visitDeclared(DeclaredType type, Void p) {
|
||||||
|
return type.getTypeArguments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class NameDeterminationVisitor extends ElementKindVisitor6<String, Void> {
|
private static class NameDeterminationVisitor extends ElementKindVisitor6<String, Void> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -194,12 +284,37 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ValueRetrievingVisitor extends SimpleAnnotationValueVisitor6<String, Void> {
|
private static class StringValueRetrievingVisitor extends SimpleAnnotationValueVisitor6<String, Void> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitString(String value, Void p) {
|
public String visitString(String value, Void p) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TypeRetrievingVisitor
|
||||||
|
extends SimpleAnnotationValueVisitor6<TypeMirror, Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeMirror visitType(TypeMirror value, Void p) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AnnotationValueListRetrievingVisitor
|
||||||
|
extends SimpleAnnotationValueVisitor6<List<? extends AnnotationValue>, Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends AnnotationValue> visitArray(List<? extends AnnotationValue> value, Void p) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AnnotationRetrievingVisitor extends SimpleAnnotationValueVisitor6<AnnotationMirror, Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationMirror visitAnnotation(AnnotationMirror value, Void p) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,21 +17,42 @@ package de.moapa.maple.ap.model;
|
|||||||
|
|
||||||
public class Binding {
|
public class Binding {
|
||||||
|
|
||||||
|
private final Type sourceType;
|
||||||
|
|
||||||
private final String sourceProperty;
|
private final String sourceProperty;
|
||||||
|
|
||||||
|
private final Type targetType;
|
||||||
|
|
||||||
private final String targetProperty;
|
private final String targetProperty;
|
||||||
|
|
||||||
public Binding(String sourceProperty, String targetProperty) {
|
private final Type converterType;
|
||||||
|
|
||||||
|
public Binding(Type sourceType, String sourceProperty, Type targetType, String targetProperty, Type converterType) {
|
||||||
|
|
||||||
|
this.sourceType = sourceType;
|
||||||
this.sourceProperty = sourceProperty;
|
this.sourceProperty = sourceProperty;
|
||||||
|
this.targetType = targetType;
|
||||||
this.targetProperty = targetProperty;
|
this.targetProperty = targetProperty;
|
||||||
|
this.converterType = converterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getSourceType() {
|
||||||
|
return sourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSourceProperty() {
|
public String getSourceProperty() {
|
||||||
return sourceProperty;
|
return sourceProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
public String getTargetProperty() {
|
public String getTargetProperty() {
|
||||||
return targetProperty;
|
return targetProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getConverterType() {
|
||||||
|
return converterType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012 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 de.moapa.maple.ap.model;
|
||||||
|
|
||||||
|
public class Converter {
|
||||||
|
|
||||||
|
private final Type converterType;
|
||||||
|
private final Type sourceType;
|
||||||
|
private final Type targetType;
|
||||||
|
|
||||||
|
public Converter(Type converterType, Type sourceType, Type targetType) {
|
||||||
|
|
||||||
|
this.converterType = converterType;
|
||||||
|
this.sourceType = sourceType;
|
||||||
|
this.targetType = targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getConverterType() {
|
||||||
|
return converterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getSourceType() {
|
||||||
|
return sourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.moapa.maple.ap.model;
|
package de.moapa.maple.ap.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Mapper {
|
public class Mapper {
|
||||||
@ -27,11 +28,35 @@ public class Mapper {
|
|||||||
|
|
||||||
private final List<MapperMethod> mapperMethods;
|
private final List<MapperMethod> mapperMethods;
|
||||||
|
|
||||||
|
private final List<Converter> converters;
|
||||||
|
|
||||||
public Mapper(String packageName, String implementationType, String interfaceType, List<MapperMethod> mapperMethods) {
|
public Mapper(String packageName, String implementationType, String interfaceType, List<MapperMethod> mapperMethods) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.implementationType = implementationType;
|
this.implementationType = implementationType;
|
||||||
this.interfaceType = interfaceType;
|
this.interfaceType = interfaceType;
|
||||||
this.mapperMethods = mapperMethods;
|
this.mapperMethods = mapperMethods;
|
||||||
|
this.converters = collectConverters( mapperMethods );
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Converter> collectConverters(List<MapperMethod> mapperMethods) {
|
||||||
|
|
||||||
|
List<Converter> converters = new ArrayList<Converter>();
|
||||||
|
|
||||||
|
for ( MapperMethod oneMapperMethod : mapperMethods ) {
|
||||||
|
for ( Binding oneBinding : oneMapperMethod.getBindings() ) {
|
||||||
|
if ( oneBinding.getConverterType() != null ) {
|
||||||
|
converters.add(
|
||||||
|
new Converter(
|
||||||
|
oneBinding.getConverterType(),
|
||||||
|
oneBinding.getSourceType(),
|
||||||
|
oneBinding.getTargetType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return converters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
@ -49,4 +74,8 @@ public class Mapper {
|
|||||||
public List<MapperMethod> getMapperMethods() {
|
public List<MapperMethod> getMapperMethods() {
|
||||||
return mapperMethods;
|
return mapperMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Converter> getConverters() {
|
||||||
|
return converters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,14 @@
|
|||||||
-->
|
-->
|
||||||
package ${packageName};
|
package ${packageName};
|
||||||
|
|
||||||
|
import org.dozer.DozerConverter;
|
||||||
import org.dozer.DozerBeanMapper;
|
import org.dozer.DozerBeanMapper;
|
||||||
import org.dozer.loader.api.BeanMappingBuilder;
|
import org.dozer.loader.api.BeanMappingBuilder;
|
||||||
|
|
||||||
|
import de.moapa.maple.converter.Converter;
|
||||||
|
|
||||||
|
import static org.dozer.loader.api.FieldsMappingOptions.*;
|
||||||
|
|
||||||
public class ${implementationType} implements ${interfaceType} {
|
public class ${implementationType} implements ${interfaceType} {
|
||||||
|
|
||||||
private final DozerBeanMapper mapper;
|
private final DozerBeanMapper mapper;
|
||||||
@ -35,7 +40,7 @@ public class ${implementationType} implements ${interfaceType} {
|
|||||||
protected void configure() {
|
protected void configure() {
|
||||||
mapping( ${oneMethod.parameter.type.name}.class, ${oneMethod.returnType.name}.class )
|
mapping( ${oneMethod.parameter.type.name}.class, ${oneMethod.returnType.name}.class )
|
||||||
<#list oneMethod.bindings as oneBinding>
|
<#list oneMethod.bindings as oneBinding>
|
||||||
.fields("${oneBinding.sourceProperty}", "${oneBinding.targetProperty}")
|
.fields( "${oneBinding.sourceProperty}", "${oneBinding.targetProperty}"<#if oneBinding.converterType??>, customConverter( ${oneBinding.converterType.name}DozerAdapter.class )</#if> )
|
||||||
</#list>
|
</#list>
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -51,4 +56,25 @@ public class ${implementationType} implements ${interfaceType} {
|
|||||||
return mapper.map(${oneMethod.parameter.name}, ${oneMethod.returnType.name}.class);
|
return mapper.map(${oneMethod.parameter.name}, ${oneMethod.returnType.name}.class);
|
||||||
}
|
}
|
||||||
</#list>
|
</#list>
|
||||||
|
|
||||||
|
<#list converters as oneConverter>
|
||||||
|
public static class ${oneConverter.converterType.name}DozerAdapter extends DozerConverter<${oneConverter.sourceType.name}, ${oneConverter.targetType.name}> {
|
||||||
|
|
||||||
|
private final Converter<${oneConverter.sourceType.name}, ${oneConverter.targetType.name}> converter = new ${oneConverter.converterType.name}();
|
||||||
|
|
||||||
|
public ${oneConverter.converterType.name}DozerAdapter() {
|
||||||
|
super(${oneConverter.sourceType.name}.class, ${oneConverter.targetType.name}.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertTo(${oneConverter.sourceType.name} source, ${oneConverter.targetType.name} destination) {
|
||||||
|
return converter.from(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ${oneConverter.sourceType.name} convertFrom(${oneConverter.targetType.name} source, ${oneConverter.sourceType.name} destination) {
|
||||||
|
return converter.to(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</#list>
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import de.moapa.maple.ap.MappingProcessor;
|
|||||||
import de.moapa.maple.ap.test.model.Car;
|
import de.moapa.maple.ap.test.model.Car;
|
||||||
import de.moapa.maple.ap.test.model.CarDto;
|
import de.moapa.maple.ap.test.model.CarDto;
|
||||||
import de.moapa.maple.ap.test.model.CarMapper;
|
import de.moapa.maple.ap.test.model.CarMapper;
|
||||||
|
import de.moapa.maple.ap.test.model.IntToStringConverter;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
@ -83,7 +84,7 @@ public class CarMapperTest {
|
|||||||
public void generateMapperImplementation() {
|
public void generateMapperImplementation() {
|
||||||
|
|
||||||
diagnostics = new DiagnosticCollector<JavaFileObject>();
|
diagnostics = new DiagnosticCollector<JavaFileObject>();
|
||||||
File[] sourceFiles = getSourceFiles( Car.class, CarDto.class, CarMapper.class );
|
File[] sourceFiles = getSourceFiles( Car.class, CarDto.class, CarMapper.class, IntToStringConverter.class );
|
||||||
|
|
||||||
boolean compilationSuccessful = compile( diagnostics, sourceFiles );
|
boolean compilationSuccessful = compile( diagnostics, sourceFiles );
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ public class CarMapperTest {
|
|||||||
public void shouldMapAttributeByName() {
|
public void shouldMapAttributeByName() {
|
||||||
|
|
||||||
//given
|
//given
|
||||||
Car car = new Car( "Morris", 2 );
|
Car car = new Car( "Morris", 2, 1980 );
|
||||||
|
|
||||||
//when
|
//when
|
||||||
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
|
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
|
||||||
@ -115,7 +116,7 @@ public class CarMapperTest {
|
|||||||
public void shouldMapAttributeWithCustomMapping() {
|
public void shouldMapAttributeWithCustomMapping() {
|
||||||
|
|
||||||
//given
|
//given
|
||||||
Car car = new Car( "Morris", 2 );
|
Car car = new Car( "Morris", 2, 1980 );
|
||||||
|
|
||||||
//when
|
//when
|
||||||
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
|
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
|
||||||
@ -129,7 +130,7 @@ public class CarMapperTest {
|
|||||||
public void shouldConsiderCustomMappingForReverseMapping() {
|
public void shouldConsiderCustomMappingForReverseMapping() {
|
||||||
|
|
||||||
//given
|
//given
|
||||||
CarDto carDto = new CarDto( "Morris", 2 );
|
CarDto carDto = new CarDto( "Morris", 2, "1980" );
|
||||||
|
|
||||||
//when
|
//when
|
||||||
Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
|
Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
|
||||||
@ -139,6 +140,34 @@ public class CarMapperTest {
|
|||||||
assertThat( car.getNumberOfSeats() ).isEqualTo( carDto.getSeatCount() );
|
assertThat( car.getNumberOfSeats() ).isEqualTo( carDto.getSeatCount() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldApplyConverter() {
|
||||||
|
|
||||||
|
//given
|
||||||
|
Car car = new Car( "Morris", 2, 1980 );
|
||||||
|
|
||||||
|
//when
|
||||||
|
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertThat( carDto ).isNotNull();
|
||||||
|
assertThat( carDto.getManufacturingYear() ).isEqualTo( "1980" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldApplyConverterForReverseMapping() {
|
||||||
|
|
||||||
|
//given
|
||||||
|
CarDto carDto = new CarDto( "Morris", 2, "1980" );
|
||||||
|
|
||||||
|
//when
|
||||||
|
Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertThat( car ).isNotNull();
|
||||||
|
assertThat( car.getYearOfManufacture() ).isEqualTo( 1980 );
|
||||||
|
}
|
||||||
|
|
||||||
private File[] getSourceFiles(Class<?>... clazz) {
|
private File[] getSourceFiles(Class<?>... clazz) {
|
||||||
|
|
||||||
File[] sourceFiles = new File[clazz.length];
|
File[] sourceFiles = new File[clazz.length];
|
||||||
|
@ -21,12 +21,15 @@ public class Car {
|
|||||||
|
|
||||||
private int numberOfSeats;
|
private int numberOfSeats;
|
||||||
|
|
||||||
|
private int yearOfManufacture;
|
||||||
|
|
||||||
public Car() {
|
public Car() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Car(String make, int numberOfSeats) {
|
public Car(String make, int numberOfSeats, int yearOfManufacture) {
|
||||||
this.make = make;
|
this.make = make;
|
||||||
this.numberOfSeats = numberOfSeats;
|
this.numberOfSeats = numberOfSeats;
|
||||||
|
this.yearOfManufacture = yearOfManufacture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMake() {
|
public String getMake() {
|
||||||
@ -44,4 +47,12 @@ public class Car {
|
|||||||
public void setNumberOfSeats(int numberOfSeats) {
|
public void setNumberOfSeats(int numberOfSeats) {
|
||||||
this.numberOfSeats = numberOfSeats;
|
this.numberOfSeats = numberOfSeats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getYearOfManufacture() {
|
||||||
|
return yearOfManufacture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYearOfManufacture(int yearOfManufacture) {
|
||||||
|
this.yearOfManufacture = yearOfManufacture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,15 @@ public class CarDto {
|
|||||||
|
|
||||||
private int seatCount;
|
private int seatCount;
|
||||||
|
|
||||||
|
private String manufacturingYear;
|
||||||
|
|
||||||
public CarDto() {
|
public CarDto() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CarDto(String make, int seatCount) {
|
public CarDto(String make, int seatCount, String manufacturingYear) {
|
||||||
this.make = make;
|
this.make = make;
|
||||||
this.seatCount = seatCount;
|
this.seatCount = seatCount;
|
||||||
|
this.manufacturingYear = manufacturingYear;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMake() {
|
public String getMake() {
|
||||||
@ -44,4 +47,12 @@ public class CarDto {
|
|||||||
public void setSeatCount(int seatCount) {
|
public void setSeatCount(int seatCount) {
|
||||||
this.seatCount = seatCount;
|
this.seatCount = seatCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getManufacturingYear() {
|
||||||
|
return manufacturingYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManufacturingYear(String manufacturingYear) {
|
||||||
|
this.manufacturingYear = manufacturingYear;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,17 @@ package de.moapa.maple.ap.test.model;
|
|||||||
import de.moapa.maple.Mapper;
|
import de.moapa.maple.Mapper;
|
||||||
import de.moapa.maple.Mappers;
|
import de.moapa.maple.Mappers;
|
||||||
import de.moapa.maple.Mapping;
|
import de.moapa.maple.Mapping;
|
||||||
|
import de.moapa.maple.Mappings;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface CarMapper {
|
public interface CarMapper {
|
||||||
|
|
||||||
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
|
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
|
||||||
|
|
||||||
@Mapping(source = "numberOfSeats", target = "seatCount")
|
@Mappings({
|
||||||
|
@Mapping(source = "numberOfSeats", target = "seatCount"),
|
||||||
|
@Mapping(source = "yearOfManufacture", target = "manufacturingYear", converter = IntToStringConverter.class)
|
||||||
|
})
|
||||||
CarDto carToCarDto(Car car);
|
CarDto carToCarDto(Car car);
|
||||||
|
|
||||||
Car carDtoToCar(CarDto carDto);
|
Car carDtoToCar(CarDto carDto);
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012 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 de.moapa.maple.ap.test.model;
|
||||||
|
|
||||||
|
import de.moapa.maple.converter.Converter;
|
||||||
|
|
||||||
|
public class IntToStringConverter implements Converter<Integer, String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String from(Integer source) {
|
||||||
|
return source != null ? source.toString() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer to(String target) {
|
||||||
|
return target != null ? Integer.valueOf( target ) : null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user