Adding support for mapping of reference attributes and lists; Removing Dozer-based implementation

This commit is contained in:
Gunnar Morling 2013-02-27 00:26:39 +01:00
parent 873e091975
commit 7fc0878673
44 changed files with 917 additions and 959 deletions

View File

@ -1,4 +1,4 @@
Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,12 +29,4 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface Mapper { public @interface Mapper {
/**
* Specifies the type of the mapper implementation to be generated.
* Currently supported values are {@code native} and {@code dozer}.
*
* @return The type of the mapper implementation to be generated.
*/
String value() default "";
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -17,88 +17,77 @@
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>de.moapa.maple</groupId> <groupId>de.moapa.maple</groupId>
<artifactId>maple-parent</artifactId> <artifactId>maple-parent</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Maple Parent</name> <name>Maple Parent</name>
<url>https://github.com/gunnarmorling/maple</url> <url>https://github.com/gunnarmorling/maple</url>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.14</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.3.2</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.freemarker</groupId>
<artifactId>slf4j-jdk14</artifactId> <artifactId>freemarker</artifactId>
<version>1.5.10</version> <version>2.3.14</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.3.1</version>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.testng</groupId> <groupId>${project.groupId}</groupId>
<artifactId>testng</artifactId> <artifactId>maple</artifactId>
<version>6.3.1</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> </dependencies>
<groupId>org.easytesting</groupId> </dependencyManagement>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
</dependency>
<dependency> <build>
<groupId>${project.groupId}</groupId> <pluginManagement>
<artifactId>maple</artifactId> <plugins>
<version>${project.version}</version> <plugin>
</dependency> <groupId>org.apache.maven.plugins</groupId>
</dependencies> <artifactId>maven-compiler-plugin</artifactId>
</dependencyManagement> <version>2.3.2</version>
<configuration>
<build> <source>1.6</source>
<pluginManagement> <target>1.6</target>
<plugins> </configuration>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>2.3.2</version> <artifactId>maven-dependency-plugin</artifactId>
<configuration> <version>2.4</version>
<source>1.6</source> </plugin>
<target>1.6</target> <plugin>
</configuration> <groupId>org.apache.maven.plugins</groupId>
</plugin> <artifactId>maven-surefire-plugin</artifactId>
<plugin> <version>2.12</version>
<groupId>org.apache.maven.plugins</groupId> </plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
</plugin>
<plugin> <plugin>
<groupId>com.mycila.maven-license-plugin</groupId> <groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId> <artifactId>maven-license-plugin</artifactId>
<version>1.9.0</version> <version>1.9.0</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<plugins> <plugins>
<plugin> <plugin>
<groupId>com.mycila.maven-license-plugin</groupId> <groupId>com.mycila.maven-license-plugin</groupId>
@ -115,7 +104,7 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -1,4 +1,4 @@
Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -36,17 +36,6 @@
<groupId>org.freemarker</groupId> <groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId> <artifactId>freemarker</artifactId>
</dependency> </dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.testng</groupId> <groupId>org.testng</groupId>
<artifactId>testng</artifactId> <artifactId>testng</artifactId>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,11 +15,12 @@
*/ */
package de.moapa.maple.ap; package de.moapa.maple.ap;
import java.beans.Introspector;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -37,19 +38,19 @@ 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.SimpleAnnotationValueVisitor6; import javax.lang.model.util.SimpleAnnotationValueVisitor6;
import javax.lang.model.util.TypeKindVisitor6;
import javax.lang.model.util.Types; 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.BeanMapping;
import de.moapa.maple.ap.model.Mapper; import de.moapa.maple.ap.model.Mapper;
import de.moapa.maple.ap.model.MapperMethod; import de.moapa.maple.ap.model.MappingMethod;
import de.moapa.maple.ap.model.Parameter; import de.moapa.maple.ap.model.PropertyMapping;
import de.moapa.maple.ap.model.Property;
import de.moapa.maple.ap.model.Type; import de.moapa.maple.ap.model.Type;
import de.moapa.maple.ap.writer.DozerModelWriter; import de.moapa.maple.ap.model.source.MappedProperty;
import de.moapa.maple.ap.model.source.Mapping;
import de.moapa.maple.ap.model.source.Method;
import de.moapa.maple.ap.model.source.Parameter;
import de.moapa.maple.ap.writer.ModelWriter; import de.moapa.maple.ap.writer.ModelWriter;
import de.moapa.maple.ap.writer.NativeModelWriter;
import static javax.lang.model.util.ElementFilter.methodsIn; import static javax.lang.model.util.ElementFilter.methodsIn;
@ -57,21 +58,14 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
private final static String IMPLEMENTATION_SUFFIX = "Impl"; private final static String IMPLEMENTATION_SUFFIX = "Impl";
private final static String MAPPER_ANNOTATION = "de.moapa.maple.Mapper";
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 MAPPINGS_ANNOTATION = "de.moapa.maple.Mappings";
private final static String CONVERTER_TYPE = "de.moapa.maple.converter.Converter";
private final static String DEFAULT_MAPPER_TYPE = "dozer";
private final ProcessingEnvironment processingEnvironment; private final ProcessingEnvironment processingEnvironment;
private final Types typeUtils; private final Types typeUtils;
private final Elements elementUtils; private final Elements elementUtils;
public MapperGenerationVisitor(ProcessingEnvironment processingEnvironment) { public MapperGenerationVisitor(ProcessingEnvironment processingEnvironment) {
this.processingEnvironment = processingEnvironment; this.processingEnvironment = processingEnvironment;
this.typeUtils = processingEnvironment.getTypeUtils(); this.typeUtils = processingEnvironment.getTypeUtils();
this.elementUtils = processingEnvironment.getElementUtils(); this.elementUtils = processingEnvironment.getElementUtils();
@ -79,7 +73,6 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
@Override @Override
public Void visitTypeAsInterface(TypeElement element, Void p) { public Void visitTypeAsInterface(TypeElement element, Void p) {
Mapper model = retrieveModel( element ); Mapper model = retrieveModel( element );
String sourceFileName = element.getQualifiedName() + IMPLEMENTATION_SUFFIX; String sourceFileName = element.getQualifiedName() + IMPLEMENTATION_SUFFIX;
@ -89,7 +82,6 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
} }
private void writeModelToSourceFile(String fileName, Mapper model) { private void writeModelToSourceFile(String fileName, Mapper model) {
JavaFileObject sourceFile; JavaFileObject sourceFile;
try { try {
sourceFile = processingEnvironment.getFiler().createSourceFile( fileName ); sourceFile = processingEnvironment.getFiler().createSourceFile( fileName );
@ -98,44 +90,142 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
throw new RuntimeException( e ); throw new RuntimeException( e );
} }
ModelWriter modelWriter = model.getMapperType() ModelWriter modelWriter = new ModelWriter( "mapper-implementation.ftl" );
.equals( "native" ) ? new NativeModelWriter() : new DozerModelWriter();
modelWriter.writeModel( sourceFile, model ); modelWriter.writeModel( sourceFile, model );
} }
private Mapper retrieveModel(TypeElement element) { private Mapper retrieveModel(TypeElement element) {
return new Mapper( List<Method> methods = retrieveMethods( element );
retrieveMapperType( element ), Set<Method> processedMethods = new HashSet<Method>();
List<BeanMapping> mappings = new ArrayList<BeanMapping>();
for ( Method method : methods ) {
if ( processedMethods.contains( method ) ) {
continue;
}
MappingMethod mappingMethod = new MappingMethod(
method.getName(),
method.getParameterName(),
getElementMappingMethod( methods, method )
);
MappingMethod reverseMappingMethod = null;
Method rawReverseMappingMethod = getReverseMappingMethod( methods, method );
if ( rawReverseMappingMethod != null ) {
processedMethods.add( rawReverseMappingMethod );
// MappingMethod reverseElementMappingMethod = rawReverseElementMappingMethod == null ? null : new MappingMethod(rawReverseElementMappingMethod.getName(), rawReverseElementMappingMethod.getParameterName() );
reverseMappingMethod = new MappingMethod(
rawReverseMappingMethod.getName(),
rawReverseMappingMethod.getParameterName(),
getElementMappingMethod( methods, rawReverseMappingMethod )
);
}
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
for ( MappedProperty property : method.getMappedProperties() ) {
Method propertyMappingMethod = getPropertyMappingMethod( methods, property );
Method reversePropertyMappingMethod = getReversePropertyMappingMethod( methods, property );
propertyMappings.add(
new PropertyMapping(
property.getSourceName(),
property.getTargetName(),
property.getConverterType(),
propertyMappingMethod != null ? new MappingMethod(
propertyMappingMethod.getName(),
propertyMappingMethod.getParameterName()
) : null,
reversePropertyMappingMethod != null ? new MappingMethod(
reversePropertyMappingMethod.getName(),
reversePropertyMappingMethod.getParameterName()
) : null
)
);
}
BeanMapping mapping = new BeanMapping(
method.getSourceType(),
method.getTargetType(),
propertyMappings,
mappingMethod,
reverseMappingMethod
);
mappings.add( mapping );
}
Mapper mapper = new Mapper(
elementUtils.getPackageOf( element ).getQualifiedName().toString(), elementUtils.getPackageOf( element ).getQualifiedName().toString(),
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
element.getSimpleName().toString(), element.getSimpleName().toString(),
retrieveMethods( element ) element.getSimpleName() + IMPLEMENTATION_SUFFIX,
mappings
);
return mapper;
}
private MappingMethod getElementMappingMethod(Iterable<Method> methods, Method method) {
Method elementMappingMethod = null;
for ( Method oneMethod : methods ) {
if ( oneMethod.getSourceType().equals( method.getSourceType().getElementType() ) ) {
elementMappingMethod = oneMethod;
break;
}
}
return elementMappingMethod == null ? null : new MappingMethod(
elementMappingMethod.getName(),
elementMappingMethod.getParameterName()
); );
} }
private String retrieveMapperType(TypeElement element) { private Method getPropertyMappingMethod(Iterable<Method> rawMethods, MappedProperty property) {
for ( Method oneMethod : rawMethods ) {
AnnotationMirror mapperAnnotation = getAnnotation( element, MAPPER_ANNOTATION ); if ( oneMethod.getSourceType().equals( property.getSourceType() ) && oneMethod.getTargetType()
String mapperType = getStringValue( mapperAnnotation, "value" ); .equals( property.getTargetType() ) ) {
return oneMethod;
return mapperType != null && !mapperType.isEmpty() ? mapperType : DEFAULT_MAPPER_TYPE; }
}
return null;
} }
private List<MapperMethod> retrieveMethods(TypeElement element) { private Method getReversePropertyMappingMethod(Iterable<Method> methods, MappedProperty property) {
for ( Method method : methods ) {
if ( method.getSourceType().equals( property.getTargetType() ) && method.getTargetType()
.equals( property.getSourceType() ) ) {
return method;
}
}
return null;
}
List<MapperMethod> methods = new ArrayList<MapperMethod>(); private Method getReverseMappingMethod(List<Method> rawMethods,
Method method) {
for ( Method oneMethod : rawMethods ) {
if ( oneMethod.reverses( method ) ) {
return oneMethod;
}
}
return null;
}
for ( ExecutableElement oneMethod : methodsIn( element.getEnclosedElements() ) ) { private List<Method> retrieveMethods(TypeElement element) {
List<Method> methods = new ArrayList<Method>();
for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) {
Parameter parameter = retrieveParameter( method );
Type returnType = retrieveReturnType( method );
List<MappedProperty> properties = retrieveMappedProperties( method );
Type returnType = retrieveReturnType( oneMethod );
Parameter parameter = retrieveParameter( oneMethod );
Map<String, Binding> bindings = retrieveBindings( oneMethod );
methods.add( methods.add(
new MapperMethod( new Method(
oneMethod.getSimpleName().toString(), method.getSimpleName().toString(),
parameter.getName(),
parameter.getType(),
returnType, returnType,
parameter, properties
bindings
) )
); );
} }
@ -143,11 +233,9 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return methods; return methods;
} }
private Map<String, Binding> retrieveBindings(ExecutableElement method) { private List<MappedProperty> retrieveMappedProperties(ExecutableElement method) {
Map<String, Binding> bindings = new LinkedHashMap<String, Binding>(); Map<String, Mapping> mappings = new HashMap<String, Mapping>();
retrieveDefaultBindings( method, bindings );
for ( AnnotationMirror annotationMirror : method.getAnnotationMirrors() ) { for ( AnnotationMirror annotationMirror : method.getAnnotationMirrors() ) {
@ -156,67 +244,59 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
.accept( new NameDeterminationVisitor(), null ); .accept( new NameDeterminationVisitor(), null );
if ( MAPPING_ANNOTATION.equals( annotationName ) ) { if ( MAPPING_ANNOTATION.equals( annotationName ) ) {
retrieveBinding( annotationMirror, bindings ); Mapping mapping = getMapping( annotationMirror );
mappings.put( mapping.getSourceName(), mapping );
} }
else if ( MAPPINGS_ANNOTATION.equals( annotationName ) ) { else if ( MAPPINGS_ANNOTATION.equals( annotationName ) ) {
retrieveBindings( annotationMirror, bindings ); mappings.putAll( getMappings( annotationMirror ) );
} }
} }
return bindings; return getMappedProperties( method, mappings );
} }
private void retrieveDefaultBindings(ExecutableElement method, Map<String, Binding> bindings) { private List<MappedProperty> getMappedProperties(ExecutableElement method, Map<String, Mapping> mappings) {
Element returnTypeElement = typeUtils.asElement( method.getReturnType() ); Element returnTypeElement = typeUtils.asElement( method.getReturnType() );
Set<Property> writableTargetProperties = new LinkedHashSet<Property>();
//collect writable properties of the target type
for ( ExecutableElement oneMethod : methodsIn( returnTypeElement.getEnclosedElements() ) ) {
if ( oneMethod.getSimpleName().toString().startsWith( "set" ) &&
oneMethod.getParameters().size() == 1 ) {
writableTargetProperties.add(
new Property(
retrieveParameter( oneMethod ).getType(),
oneMethod.getSimpleName().toString().substring( 3 )
)
);
}
}
//collect readable properties of the source type
Element parameterElement = typeUtils.asElement( method.getParameters().get( 0 ).asType() ); Element parameterElement = typeUtils.asElement( method.getParameters().get( 0 ).asType() );
Set<Property> readableSourceProperties = new LinkedHashSet<Property>(); List<MappedProperty> properties = new ArrayList<MappedProperty>();
for ( ExecutableElement oneMethod : methodsIn( parameterElement.getEnclosedElements() ) ) { for ( ExecutableElement getterMethod : getterMethodsIn( parameterElement.getEnclosedElements() ) ) {
//TODO: consider is/has
if ( oneMethod.getSimpleName().toString().startsWith( "get" ) &&
oneMethod.getParameters().isEmpty() &&
oneMethod.getReturnType().getKind() != TypeKind.VOID ) {
readableSourceProperties.add( String sourcePropertyName = Introspector.decapitalize(
new Property( getterMethod.getSimpleName()
retrieveReturnType( oneMethod ), .toString()
oneMethod.getSimpleName().toString().substring( 3 ) .substring( 3 )
) );
Mapping mapping = mappings.get( sourcePropertyName );
for ( ExecutableElement setterMethod : setterMethodsIn( returnTypeElement.getEnclosedElements() ) ) {
String targetPropertyName = Introspector.decapitalize(
setterMethod.getSimpleName()
.toString()
.substring( 3 )
); );
if ( targetPropertyName.equals( mapping != null ? mapping.getTargetName() : sourcePropertyName ) ) {
properties.add(
new MappedProperty(
sourcePropertyName,
retrieveReturnType( getterMethod ),
mapping != null ? mapping.getTargetName() : targetPropertyName,
retrieveParameter( setterMethod ).getType(),
mapping != null ? mapping.getConverterType() : null
)
);
}
} }
} }
writableTargetProperties.retainAll( readableSourceProperties ); return properties;
for ( Property oneWritableProperty : writableTargetProperties ) {
bindings.put(
oneWritableProperty.getName(),
new Binding( oneWritableProperty.getName(), oneWritableProperty.getName() )
);
}
} }
private void retrieveBindings(AnnotationMirror annotationMirror, Map<String, Binding> bindings) { private Map<String, Mapping> getMappings(AnnotationMirror annotationMirror) {
Map<String, Mapping> mappings = new HashMap<String, Mapping>();
List<? extends AnnotationValue> values = getAnnotationValueListValue( annotationMirror, "value" ); List<? extends AnnotationValue> values = getAnnotationValueListValue( annotationMirror, "value" );
@ -225,62 +305,41 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
new AnnotationRetrievingVisitor(), new AnnotationRetrievingVisitor(),
null null
); );
retrieveBinding( oneAnnotation, bindings ); Mapping mapping = getMapping( oneAnnotation );
mappings.put( mapping.getSourceName(), mapping );
} }
return mappings;
} }
private void retrieveBinding(AnnotationMirror annotationMirror, Map<String, Binding> bindings) { private Mapping getMapping(AnnotationMirror annotationMirror) {
String sourcePropertyName = getStringValue( annotationMirror, "source" ); String sourcePropertyName = getStringValue( annotationMirror, "source" );
String targetPropertyName = getStringValue( annotationMirror, "target" ); String targetPropertyName = getStringValue( annotationMirror, "target" );
TypeMirror converterTypeMirror = getTypeMirrorValue( annotationMirror, "converter" ); TypeMirror converterTypeMirror = getTypeMirrorValue( annotationMirror, "converter" );
Type converterType = null; Type converterType = null;
Type sourceType = null;
Type targetType = null;
if ( converterTypeMirror != null ) { if ( converterTypeMirror != null ) {
converterType = getType( typeUtils.asElement( converterTypeMirror ) ); converterType = getType( (DeclaredType) converterTypeMirror );
List<? extends TypeMirror> converterTypeParameters = getTypeParameters(
converterTypeMirror,
CONVERTER_TYPE
);
sourceType = getType( typeUtils.asElement( converterTypeParameters.get( 0 ) ) );
targetType = getType( typeUtils.asElement( converterTypeParameters.get( 1 ) ) );
} }
bindings.put( return new Mapping( sourcePropertyName, targetPropertyName, converterType );
sourcePropertyName,
new Binding( sourceType, sourcePropertyName, targetType, targetPropertyName, converterType )
);
} }
private Type getType(Element sourceTypeElement) { private Type getType(DeclaredType type) {
Type elementType = null;
if ( !type.getTypeArguments().isEmpty() ) {
elementType = retrieveType( type.getTypeArguments().iterator().next() );
}
return new Type( return new Type(
elementUtils.getPackageOf( sourceTypeElement ).toString(), elementUtils.getPackageOf( type.asElement() ).toString(),
sourceTypeElement.getSimpleName().toString() type.asElement().getSimpleName().toString(),
elementType
); );
} }
//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) {
List<? extends VariableElement> parameters = method.getParameters(); List<? extends VariableElement> parameters = method.getParameters();
if ( parameters.size() != 1 ) { if ( parameters.size() != 1 ) {
@ -302,30 +361,14 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
} }
private Type retrieveType(TypeMirror mirror) { private Type retrieveType(TypeMirror mirror) {
if ( mirror.getKind() == TypeKind.DECLARED ) { if ( mirror.getKind() == TypeKind.DECLARED ) {
return getType( ( (DeclaredType) mirror ).asElement() ); return getType( ( (DeclaredType) mirror ) );
} }
else { else {
return new Type( null, mirror.toString() ); return new Type( null, mirror.toString() );
} }
} }
private AnnotationMirror getAnnotation(TypeElement element, String annotationName) {
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
if ( annotationName.equals(
annotationMirror.getAnnotationType().asElement().accept( new NameDeterminationVisitor(), null )
) ) {
return annotationMirror;
}
}
return null;
}
private String getStringValue(AnnotationMirror annotationMirror, String attributeName) { private String getStringValue(AnnotationMirror annotationMirror, String attributeName) {
for ( Entry<? extends ExecutableElement, ? extends AnnotationValue> oneAttribute : annotationMirror.getElementValues() for ( Entry<? extends ExecutableElement, ? extends AnnotationValue> oneAttribute : annotationMirror.getElementValues()
@ -365,14 +408,39 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return null; return null;
} }
private static class TypeParameterDeterminationVisitor extends TypeKindVisitor6<List<? extends TypeMirror>, Void> { private List<ExecutableElement> getterMethodsIn(Iterable<? extends Element> elements) {
List<ExecutableElement> getterMethods = new LinkedList<ExecutableElement>();
@Override for ( ExecutableElement method : methodsIn( elements ) ) {
public List<? extends TypeMirror> visitDeclared(DeclaredType type, Void p) { //TODO: consider is/has
return type.getTypeArguments(); String name = method.getSimpleName().toString();
if ( name.startsWith( "get" ) && name.length() > 3 && method.getParameters()
.isEmpty() && method.getReturnType().getKind() != TypeKind.VOID ) {
getterMethods.add( method );
}
} }
return getterMethods;
} }
private List<ExecutableElement> setterMethodsIn(Iterable<? extends Element> elements) {
List<ExecutableElement> setterMethods = new LinkedList<ExecutableElement>();
for ( ExecutableElement method : methodsIn( elements ) ) {
//TODO: consider is/has
String name = method.getSimpleName().toString();
if ( name.startsWith( "set" ) && name.length() > 3 && method.getParameters()
.size() == 1 && method.getReturnType().getKind() == TypeKind.VOID ) {
setterMethods.add( method );
}
}
return setterMethods;
}
private static class NameDeterminationVisitor extends ElementKindVisitor6<String, Void> { private static class NameDeterminationVisitor extends ElementKindVisitor6<String, Void> {
@Override @Override

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -0,0 +1,74 @@
/**
* 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 de.moapa.maple.ap.model;
import java.util.List;
public class BeanMapping {
private final Type sourceType;
private final Type targetType;
private final List<PropertyMapping> propertyMappings;
private final MappingMethod mappingMethod;
private final MappingMethod reverseMappingMethod;
private final boolean isIterableMapping;
public BeanMapping(Type sourceType, Type targetType, List<PropertyMapping> propertyMappings, MappingMethod mappingMethod,
MappingMethod reverseMappingMethod) {
this.sourceType = sourceType;
this.targetType = targetType;
this.propertyMappings = propertyMappings;
this.mappingMethod = mappingMethod;
this.reverseMappingMethod = reverseMappingMethod;
this.isIterableMapping = mappingMethod.getElementMappingMethod() != null;
}
public Type getSourceType() {
return sourceType;
}
public Type getTargetType() {
return targetType;
}
public List<PropertyMapping> getPropertyMappings() {
return propertyMappings;
}
public MappingMethod getMappingMethod() {
return mappingMethod;
}
public MappingMethod getReverseMappingMethod() {
return reverseMappingMethod;
}
public boolean getIterableMapping() {
return isIterableMapping;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append( sourceType );
stringBuilder.append( " <=> " );
stringBuilder.append( targetType );
return stringBuilder.toString();
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,69 +15,39 @@
*/ */
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 {
private final String mapperType;
private final String packageName; private final String packageName;
private final String implementationType;
private final String interfaceType;
private final List<MapperMethod> mapperMethods;
private final List<Converter> converters;
public Mapper(String mapperType, String packageName, String implementationType, String interfaceType, List<MapperMethod> mapperMethods) { private final String interfaceName;
this.mapperType = mapperType;
private final String implementationName;
private final List<BeanMapping> beanMappings;
public Mapper(String packageName, String interfaceName,
String implementationName, List<BeanMapping> beanMappings) {
this.packageName = packageName; this.packageName = packageName;
this.implementationType = implementationType; this.interfaceName = interfaceName;
this.interfaceType = interfaceType; this.implementationName = implementationName;
this.mapperMethods = mapperMethods; this.beanMappings = beanMappings;
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().values() ) {
if ( oneBinding.getConverterType() != null ) {
converters.add(
new Converter(
oneBinding.getConverterType(),
oneBinding.getSourceType(),
oneBinding.getTargetType()
)
);
}
}
}
return converters;
}
public String getMapperType() {
return mapperType;
} }
public String getPackageName() { public String getPackageName() {
return packageName; return packageName;
} }
public String getImplementationType() { public String getInterfaceName() {
return implementationType; return interfaceName;
} }
public String getInterfaceType() { public String getImplementationName() {
return interfaceType; return implementationName;
} }
public List<MapperMethod> getMapperMethods() { public List<BeanMapping> getBeanMappings() {
return mapperMethods; return beanMappings;
}
public List<Converter> getConverters() {
return converters;
} }
} }

View File

@ -1,64 +0,0 @@
/**
* 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;
import java.util.Map;
public class MapperMethod {
private final String name;
private final Type returnType;
private final Parameter parameter;
/**
* Bindings for the properties of this method's converted object. Keyed by
* property name of the source type.
*/
private final Map<String, Binding> bindings;
public MapperMethod(String name, Type returnType, Parameter parameter, Map<String, Binding> bindings) {
this.name = name;
this.returnType = returnType;
this.parameter = parameter;
this.bindings = bindings;
}
public String getName() {
return name;
}
public Type getReturnType() {
return returnType;
}
public Parameter getParameter() {
return parameter;
}
public Map<String, Binding> getBindings() {
return bindings;
}
public boolean getNonDefaultBindingExisting() {
for ( Binding oneBinding : bindings.values() ) {
if ( !oneBinding.isDefault() ) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,47 @@
/**
* 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 de.moapa.maple.ap.model;
public class MappingMethod {
private final String name;
private final String parameterName;
private final MappingMethod elementMappingMethod;
public MappingMethod(String name, String parameterName) {
this.name = name;
this.parameterName = parameterName;
this.elementMappingMethod = null;
}
public MappingMethod(String name, String parameterName, MappingMethod elementMappingMethod) {
this.name = name;
this.parameterName = parameterName;
this.elementMappingMethod = elementMappingMethod;
}
public String getName() {
return name;
}
public String getParameterName() {
return parameterName;
}
public MappingMethod getElementMappingMethod() {
return elementMappingMethod;
}
}

View File

@ -1,85 +0,0 @@
/**
* 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;
/**
* Represents a property of a Java bean.
*
* @author Gunnar Morling
*/
public class Property {
private final Type type;
private final String name;
public Property(Type type, String name) {
this.type = type;
this.name = name;
}
public Type getType() {
return type;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Property [type=" + type + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
result = prime * result + ( ( type == null ) ? 0 : type.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;
}
Property other = (Property) obj;
if ( name == null ) {
if ( other.name != null ) {
return false;
}
}
else if ( !name.equals( other.name ) ) {
return false;
}
if ( type == null ) {
if ( other.type != null ) {
return false;
}
}
else if ( !type.equals( other.type ) ) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,53 @@
/**
* 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 de.moapa.maple.ap.model;
public class PropertyMapping {
private final String sourceName;
private final String targetName;
private final Type converterType;
private final MappingMethod mappingMethod;
private final MappingMethod reverseMappingMethod;
public PropertyMapping(String sourceName, String targetName, Type converterType, MappingMethod mappingMethod, MappingMethod reverseMappingMethod) {
this.sourceName = sourceName;
this.targetName = targetName;
this.converterType = converterType;
this.mappingMethod = mappingMethod;
this.reverseMappingMethod = reverseMappingMethod;
}
public String getSourceName() {
return sourceName;
}
public String getTargetName() {
return targetName;
}
public Type getConverterType() {
return converterType;
}
public MappingMethod getMappingMethod() {
return mappingMethod;
}
public MappingMethod getReverseMappingMethod() {
return reverseMappingMethod;
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,12 +23,25 @@ package de.moapa.maple.ap.model;
public class Type { public class Type {
private final String packageName; private final String packageName;
private final String name; private final String name;
private final Type elementType;
public Type(String name) {
this.packageName = null;
this.name = name;
this.elementType = null;
}
public Type(String packageName, String name) { public Type(String packageName, String name) {
this.packageName = packageName; this.packageName = packageName;
this.name = name; this.name = name;
this.elementType = null;
}
public Type(String packageName, String name, Type elementType) {
this.packageName = packageName;
this.name = name;
this.elementType = elementType;
} }
public String getPackageName() { public String getPackageName() {
@ -39,15 +52,29 @@ public class Type {
return name; return name;
} }
public Type getElementType() {
return elementType;
}
@Override @Override
public String toString() { public String toString() {
return "Type [packageName=" + packageName + ", name=" + name + "]"; if ( packageName == null ) {
return name;
}
else if ( elementType == null ) {
return packageName + "." + name;
}
else {
return packageName + "." + name + "<" + elementType + ">";
}
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result
+ ( ( elementType == null ) ? 0 : elementType.hashCode() );
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() ); result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
result = prime * result result = prime * result
+ ( ( packageName == null ) ? 0 : packageName.hashCode() ); + ( ( packageName == null ) ? 0 : packageName.hashCode() );
@ -66,6 +93,14 @@ public class Type {
return false; return false;
} }
Type other = (Type) obj; Type other = (Type) obj;
if ( elementType == null ) {
if ( other.elementType != null ) {
return false;
}
}
else if ( !elementType.equals( other.elementType ) ) {
return false;
}
if ( name == null ) { if ( name == null ) {
if ( other.name != null ) { if ( other.name != null ) {
return false; return false;

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,50 +13,49 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.moapa.maple.ap.model; package de.moapa.maple.ap.model.source;
public class Binding { import de.moapa.maple.ap.model.Type;
public class MappedProperty {
private final String sourceName;
private final Type sourceType; private final Type sourceType;
private final String sourceProperty; private final String targetName;
private final Type targetType; private final Type targetType;
private final String targetProperty;
private final Type converterType; private final Type converterType;
public Binding(String sourceProperty, String targetProperty) { public MappedProperty(String sourceName, Type sourceType, String targetName,
this( null, sourceProperty, null, targetProperty, null ); Type targetType, Type converterType) {
this.sourceName = sourceName;
this.sourceType = sourceType;
this.targetName = targetName;
this.targetType = targetType;
this.converterType = converterType;
} }
public Binding(Type sourceType, String sourceProperty, Type targetType, String targetProperty, Type converterType) { public String getSourceName() {
return sourceName;
this.sourceType = sourceType;
this.sourceProperty = sourceProperty;
this.targetType = targetType;
this.targetProperty = targetProperty;
this.converterType = converterType;
} }
public Type getSourceType() { public Type getSourceType() {
return sourceType; return sourceType;
} }
public String getSourceProperty() { public String getTargetName() {
return sourceProperty; return targetName;
} }
public Type getTargetType() { public Type getTargetType() {
return targetType; return targetType;
} }
public String getTargetProperty() {
return targetProperty;
}
public Type getConverterType() { public Type getConverterType() {
return converterType; return converterType;
} }
public boolean isDefault() { @Override
return !sourceProperty.equals( targetProperty ) || ( sourceType != null && !sourceType.equals( targetType ) ) ? false : true; public String toString() {
return sourceType + " " + sourceName + " <=> " + targetType + " " + targetName + " (" + ( converterType != null ? converterType : "no converter" ) + ")";
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,30 +13,31 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.moapa.maple.ap.model; package de.moapa.maple.ap.model.source;
public class Converter { import de.moapa.maple.ap.model.Type;
public class Mapping {
private final String sourceName;
private final String targetName;
private final Type converterType; private final Type converterType;
private final Type sourceType;
private final Type targetType;
public Converter(Type converterType, Type sourceType, Type targetType) {
public Mapping(String sourceName, String targetName, Type converterType) {
this.sourceName = sourceName;
this.targetName = targetName;
this.converterType = converterType; this.converterType = converterType;
this.sourceType = sourceType; }
this.targetType = targetType;
public String getSourceName() {
return sourceName;
}
public String getTargetName() {
return targetName;
} }
public Type getConverterType() { public Type getConverterType() {
return converterType; return converterType;
} }
public Type getSourceType() {
return sourceType;
}
public Type getTargetType() {
return targetType;
}
} }

View File

@ -0,0 +1,72 @@
/**
* 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 de.moapa.maple.ap.model.source;
import java.util.List;
import de.moapa.maple.ap.model.Type;
public class Method {
private final String name;
private final String parameterName;
private final Type sourceType;
private final Type targetType;
private final List<MappedProperty> mappedProperties;
public Method(String name, String parameterName, Type sourceType, Type targetType, List<MappedProperty> mappedProperties) {
this.name = name;
this.parameterName = parameterName;
this.sourceType = sourceType;
this.targetType = targetType;
this.mappedProperties = mappedProperties;
}
public String getName() {
return name;
}
public String getParameterName() {
return parameterName;
}
public Type getSourceType() {
return sourceType;
}
public Type getTargetType() {
return targetType;
}
public List<MappedProperty> getMappedProperties() {
return mappedProperties;
}
public boolean reverses(Method method) {
return
equals( sourceType, method.getTargetType() ) &&
equals( targetType, method.getSourceType() );
}
private boolean equals(Object o1, Object o2) {
return (o1 == null && o2 == null) || (o1 != null) && o1.equals( o2 );
}
@Override
public String toString() {
return targetType + " " + name + "(" + sourceType + " " + parameterName + ")";
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.moapa.maple.ap.model; package de.moapa.maple.ap.model.source;
import de.moapa.maple.ap.model.Type;
public class Parameter { public class Parameter {

View File

@ -1,58 +0,0 @@
/**
* 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.writer;
import java.io.BufferedWriter;
import javax.tools.JavaFileObject;
import de.moapa.maple.ap.model.Mapper;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
public class DozerModelWriter implements ModelWriter {
private final static String TEMPLATE_NAME = "dozer-mapper-implementation.ftl";
private static final Configuration configuration;
static {
configuration = new Configuration();
configuration.setClassForTemplateLoading( DozerModelWriter.class, "/" );
configuration.setObjectWrapper( new DefaultObjectWrapper() );
}
@Override
public void writeModel(JavaFileObject sourceFile, Mapper model) {
try {
BufferedWriter writer = new BufferedWriter( sourceFile.openWriter() );
Template template = configuration.getTemplate( TEMPLATE_NAME );
template.process( model, writer );
writer.flush();
writer.close();
}
catch ( RuntimeException e ) {
throw e;
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,11 +15,44 @@
*/ */
package de.moapa.maple.ap.writer; package de.moapa.maple.ap.writer;
import java.io.BufferedWriter;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
import de.moapa.maple.ap.model.Mapper; import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
public interface ModelWriter { public class ModelWriter {
void writeModel(JavaFileObject sourceFile, Mapper model); private static final Configuration configuration;
private final String templateName;
static {
configuration = new Configuration();
configuration.setClassForTemplateLoading( ModelWriter.class, "/" );
configuration.setObjectWrapper( new DefaultObjectWrapper() );
}
public ModelWriter(String templateName) {
this.templateName = templateName;
}
public void writeModel(JavaFileObject sourceFile, Object model) {
try {
BufferedWriter writer = new BufferedWriter( sourceFile.openWriter() );
Template template = configuration.getTemplate( templateName );
template.process( model, writer );
writer.flush();
writer.close();
}
catch ( RuntimeException e ) {
throw e;
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
} }

View File

@ -1,58 +0,0 @@
/**
* 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.writer;
import java.io.BufferedWriter;
import javax.tools.JavaFileObject;
import de.moapa.maple.ap.model.Mapper;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
public class NativeModelWriter implements ModelWriter {
private final static String TEMPLATE_NAME = "native-mapper-implementation.ftl";
private static final Configuration configuration;
static {
configuration = new Configuration();
configuration.setClassForTemplateLoading( NativeModelWriter.class, "/" );
configuration.setObjectWrapper( new DefaultObjectWrapper() );
}
@Override
public void writeModel(JavaFileObject sourceFile, Mapper model) {
try {
BufferedWriter writer = new BufferedWriter( sourceFile.openWriter() );
Template template = configuration.getTemplate( TEMPLATE_NAME );
template.process( model, writer );
writer.flush();
writer.close();
}
catch ( RuntimeException e ) {
throw e;
}
catch ( Exception e ) {
throw new RuntimeException( e );
}
}
}

View File

@ -1,80 +0,0 @@
<#--
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 ${packageName};
import org.dozer.DozerConverter;
import org.dozer.DozerBeanMapper;
import org.dozer.loader.api.BeanMappingBuilder;
import de.moapa.maple.converter.Converter;
import static org.dozer.loader.api.FieldsMappingOptions.*;
public class ${implementationType} implements ${interfaceType} {
private final DozerBeanMapper mapper;
public ${implementationType}() {
mapper = new DozerBeanMapper();
BeanMappingBuilder builder = null;
<#list mapperMethods as oneMethod>
<#if oneMethod.nonDefaultBindingExisting>
builder = new BeanMappingBuilder() {
protected void configure() {
mapping( ${oneMethod.parameter.type.name}.class, ${oneMethod.returnType.name}.class )
<#list oneMethod.bindings?values as oneBinding>
.fields( "${oneBinding.sourceProperty}", "${oneBinding.targetProperty}"<#if oneBinding.converterType??>, customConverter( ${oneBinding.converterType.name}DozerAdapter.class )</#if> )
</#list>
;
}
};
mapper.addMapping( builder );
</#if>
</#list>
}
<#list mapperMethods as oneMethod>
public ${oneMethod.returnType.name} ${oneMethod.name}(${oneMethod.parameter.type.name} ${oneMethod.parameter.name}) {
return mapper.map(${oneMethod.parameter.name}, ${oneMethod.returnType.name}.class);
}
</#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>
}

View File

@ -0,0 +1,93 @@
<#--
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 ${packageName};
import java.util.ArrayList;
import java.util.List;
public class ${implementationName} implements ${interfaceName} {
<#list beanMappings as beanMapping>
<#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} ) {
${beanMapping.targetType.name?uncap_first}.add( ${beanMapping.mappingMethod.elementMappingMethod.name}( ${beanMapping.sourceType.elementType.name?uncap_first} ) );
}
return ${beanMapping.targetType.name?uncap_first};
}
<#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??>
${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}() ) );
<#else>
${beanMapping.targetType.name?uncap_first}.set${propertyMapping.targetName?cap_first}( ${beanMapping.mappingMethod.parameterName}.get${propertyMapping.sourceName?cap_first}() );
</#if>
</#list>
return ${beanMapping.targetType.name?uncap_first};
}
</#if>
<#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} ) {
${beanMapping.sourceType.name?uncap_first}.add( ${beanMapping.reverseMappingMethod.elementMappingMethod.name}( ${beanMapping.targetType.elementType.name?uncap_first} ) );
}
return ${beanMapping.sourceType.name?uncap_first};
}
<#else>
@Override
public ${beanMapping.sourceType.name} ${beanMapping.reverseMappingMethod.name}(${beanMapping.targetType.name} ${beanMapping.reverseMappingMethod.parameterName}) {
${beanMapping.sourceType.name} ${beanMapping.sourceType.name?uncap_first} = new ${beanMapping.sourceType.name}();
<#list beanMapping.propertyMappings as propertyMapping>
<#if 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}() ) );
<#else>
${beanMapping.sourceType.name?uncap_first}.set${propertyMapping.sourceName?cap_first}( ${beanMapping.reverseMappingMethod.parameterName}.get${propertyMapping.targetName?cap_first}() );
</#if>
</#list>
return ${beanMapping.sourceType.name?uncap_first};
}
</#if>
</#if>
</#list>
}

View File

@ -1,38 +0,0 @@
<#--
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 ${packageName};
public class ${implementationType} implements ${interfaceType} {
<#list mapperMethods as oneMethod>
public ${oneMethod.returnType.name} ${oneMethod.name}(${oneMethod.parameter.type.name} ${oneMethod.parameter.name}) {
${oneMethod.returnType.name} convertedObject = new ${oneMethod.returnType.name}();
<#list oneMethod.bindings?values as oneBinding>
<#if oneBinding.converterType??>
convertedObject.set${oneBinding.targetProperty?cap_first}( new ${oneBinding.converterType.name}().from( ${oneMethod.parameter.name}.get${oneBinding.sourceProperty?cap_first}() ) );
<#else>
convertedObject.set${oneBinding.targetProperty?cap_first}( ${oneMethod.parameter.name}.get${oneBinding.sourceProperty?cap_first}() );
</#if>
</#list>
return convertedObject;
}
</#list>
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,13 +16,16 @@
package de.moapa.maple.ap.test; package de.moapa.maple.ap.test;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.DiagnosticCollector; import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
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.IntToStringConverter; import de.moapa.maple.ap.test.model.IntToStringConverter;
import de.moapa.maple.ap.test.model.CarMapper;
import de.moapa.maple.ap.test.model.Person; import de.moapa.maple.ap.test.model.Person;
import de.moapa.maple.ap.test.model.PersonDto; import de.moapa.maple.ap.test.model.PersonDto;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
@ -35,12 +38,11 @@ public class CarMapperTest extends MapperTestBase {
private DiagnosticCollector<JavaFileObject> diagnostics; private DiagnosticCollector<JavaFileObject> diagnostics;
public CarMapperTest() { public CarMapperTest() {
super( "maple.jar", "dozer.jar", "slf4j-api.jar", "slf4j-jdk14.jar" ); super( "maple.jar" );
} }
@BeforeMethod @BeforeMethod
public void generateMapperImplementation() { public void generateMapperImplementation() {
diagnostics = new DiagnosticCollector<JavaFileObject>(); diagnostics = new DiagnosticCollector<JavaFileObject>();
File[] sourceFiles = getSourceFiles( File[] sourceFiles = getSourceFiles(
Car.class, Car.class,
@ -59,15 +61,13 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldProvideMapperInstance() throws Exception { public void shouldProvideMapperInstance() throws Exception {
assertThat( CarMapper.INSTANCE ).isNotNull(); assertThat( CarMapper.INSTANCE ).isNotNull();
} }
@Test @Test
public void shouldMapAttributeByName() { public void shouldMapAttributeByName() {
//given //given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() );
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -79,9 +79,8 @@ 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" ) ); Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() );
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -94,9 +93,8 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldReverseMapReferenceAttribute() { public void shouldReverseMapReferenceAttribute() {
//given //given
CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ), new ArrayList<PersonDto>() );
//when //when
Car car = CarMapper.INSTANCE.carDtoToCar( carDto ); Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
@ -109,9 +107,8 @@ 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" ) ); Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() );
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -123,9 +120,8 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldConsiderCustomMappingForReverseMapping() { public void shouldConsiderCustomMappingForReverseMapping() {
//given //given
CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ), new ArrayList<PersonDto>() );
//when //when
Car car = CarMapper.INSTANCE.carDtoToCar( carDto ); Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
@ -137,9 +133,8 @@ 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" ) ); Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() );
//when //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
@ -151,9 +146,8 @@ public class CarMapperTest extends MapperTestBase {
@Test @Test
public void shouldApplyConverterForReverseMapping() { public void shouldApplyConverterForReverseMapping() {
//given //given
CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ), new ArrayList<PersonDto>() );
//when //when
Car car = CarMapper.INSTANCE.carDtoToCar( carDto ); Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
@ -162,4 +156,96 @@ public class CarMapperTest extends MapperTestBase {
assertThat( car ).isNotNull(); assertThat( car ).isNotNull();
assertThat( car.getYearOfManufacture() ).isEqualTo( 1980 ); assertThat( car.getYearOfManufacture() ).isEqualTo( 1980 );
} }
@Test
public void shouldMapIterable() {
//given
Car car1 = new Car( "Morris", 2, 1980, new Person( "Bob" ), new ArrayList<Person>() );
Car car2 = new Car( "Railton", 4, 1934, new Person( "Bill" ), new ArrayList<Person>() );
//when
List<CarDto> dtos = CarMapper.INSTANCE.carsToCarDtos( new ArrayList<Car>( Arrays.asList( car1, car2 ) ) );
//then
assertThat( dtos ).isNotNull();
assertThat( dtos ).hasSize( 2 );
assertThat( dtos.get( 0 ).getMake() ).isEqualTo( "Morris" );
assertThat( dtos.get( 0 ).getSeatCount() ).isEqualTo( 2 );
assertThat( dtos.get( 0 ).getManufacturingYear() ).isEqualTo( "1980" );
assertThat( dtos.get( 0 ).getDriver().getName() ).isEqualTo( "Bob" );
assertThat( dtos.get( 1 ).getMake() ).isEqualTo( "Railton" );
assertThat( dtos.get( 1 ).getSeatCount() ).isEqualTo( 4 );
assertThat( dtos.get( 1 ).getManufacturingYear() ).isEqualTo( "1934" );
assertThat( dtos.get( 1 ).getDriver().getName() ).isEqualTo( "Bill" );
}
@Test
public void shouldReverseMapIterable() {
//given
CarDto car1 = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ), new ArrayList<PersonDto>() );
CarDto car2 = new CarDto( "Railton", 4, "1934", new PersonDto( "Bill" ), new ArrayList<PersonDto>() );
//when
List<Car> cars = CarMapper.INSTANCE.carDtosToCars( new ArrayList<CarDto>( Arrays.asList( car1, car2 ) ) );
//then
assertThat( cars ).isNotNull();
assertThat( cars ).hasSize( 2 );
assertThat( cars.get( 0 ).getMake() ).isEqualTo( "Morris" );
assertThat( cars.get( 0 ).getNumberOfSeats() ).isEqualTo( 2 );
assertThat( cars.get( 0 ).getYearOfManufacture() ).isEqualTo( 1980 );
assertThat( cars.get( 0 ).getDriver().getName() ).isEqualTo( "Bob" );
assertThat( cars.get( 1 ).getMake() ).isEqualTo( "Railton" );
assertThat( cars.get( 1 ).getNumberOfSeats() ).isEqualTo( 4 );
assertThat( cars.get( 1 ).getYearOfManufacture() ).isEqualTo( 1934 );
assertThat( cars.get( 1 ).getDriver().getName() ).isEqualTo( "Bill" );
}
@Test
public void shouldMapIterableAttribute() {
//given
Car car = new Car(
"Morris",
2,
1980,
new Person( "Bob" ),
new ArrayList<Person>( Arrays.asList( new Person( "Alice" ), new Person( "Bill" ) ) )
);
//when
CarDto dto = CarMapper.INSTANCE.carToCarDto( car );
//then
assertThat( dto ).isNotNull();
assertThat( dto.getPassengers() ).hasSize( 2 );
assertThat( dto.getPassengers().get( 0 ).getName() ).isEqualTo( "Alice" );
assertThat( dto.getPassengers().get( 1 ).getName() ).isEqualTo( "Bill" );
}
@Test
public void shouldReverseMapIterableAttribute() {
//given
CarDto carDto = new CarDto(
"Morris",
2,
"1980",
new PersonDto( "Bob" ),
new ArrayList<PersonDto>( Arrays.asList( new PersonDto( "Alice" ), new PersonDto( "Bill" ) ) )
);
//when
Car car = CarMapper.INSTANCE.carDtoToCar( carDto );
//then
assertThat( car ).isNotNull();
assertThat( car.getPassengers() ).hasSize( 2 );
assertThat( car.getPassengers().get( 0 ).getName() ).isEqualTo( "Alice" );
assertThat( car.getPassengers().get( 1 ).getName() ).isEqualTo( "Bill" );
}
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,165 +0,0 @@
/**
* 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;
import java.io.File;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
import de.moapa.maple.ap.test.model.Car;
import de.moapa.maple.ap.test.model.CarDto;
import de.moapa.maple.ap.test.model.IntToStringConverter;
import de.moapa.maple.ap.test.model.NativeCarMapper;
import de.moapa.maple.ap.test.model.Person;
import de.moapa.maple.ap.test.model.PersonDto;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.fest.assertions.Assertions.assertThat;
public class NativeCarMapperTest extends MapperTestBase {
private DiagnosticCollector<JavaFileObject> diagnostics;
public NativeCarMapperTest() {
super( "maple.jar" );
}
@BeforeMethod
public void generateMapperImplementation() {
diagnostics = new DiagnosticCollector<JavaFileObject>();
File[] sourceFiles = getSourceFiles(
Car.class,
CarDto.class,
Person.class,
PersonDto.class,
NativeCarMapper.class,
IntToStringConverter.class
);
boolean compilationSuccessful = compile( diagnostics, sourceFiles );
assertThat( compilationSuccessful ).describedAs( "Compilation failed: " + diagnostics.getDiagnostics() )
.isTrue();
}
@Test
public void shouldProvideMapperInstance() throws Exception {
assertThat( NativeCarMapper.INSTANCE ).isNotNull();
}
@Test
public void shouldMapAttributeByName() {
//given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) );
//when
CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car );
//then
assertThat( carDto ).isNotNull();
assertThat( carDto.getMake() ).isEqualTo( car.getMake() );
}
@Test(enabled = false)
public void shouldMapReferenceAttribute() {
//given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) );
//when
CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car );
//then
assertThat( carDto ).isNotNull();
assertThat( carDto.getDriver() ).isNotNull();
assertThat( carDto.getDriver().getName() ).isEqualTo( "Bob" );
}
@Test(enabled = false)
public void shouldReverseMapReferenceAttribute() {
//given
CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) );
//when
Car car = NativeCarMapper.INSTANCE.carDtoToCar( carDto );
//then
assertThat( car ).isNotNull();
assertThat( car.getDriver() ).isNotNull();
assertThat( car.getDriver().getName() ).isEqualTo( "Bob" );
}
@Test
public void shouldMapAttributeWithCustomMapping() {
//given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) );
//when
CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car );
//then
assertThat( carDto ).isNotNull();
assertThat( carDto.getSeatCount() ).isEqualTo( car.getNumberOfSeats() );
}
@Test(enabled = false)
public void shouldConsiderCustomMappingForReverseMapping() {
//given
CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) );
//when
Car car = NativeCarMapper.INSTANCE.carDtoToCar( carDto );
//then
assertThat( car ).isNotNull();
assertThat( car.getNumberOfSeats() ).isEqualTo( carDto.getSeatCount() );
}
@Test
public void shouldApplyConverter() {
//given
Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) );
//when
CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car );
//then
assertThat( carDto ).isNotNull();
assertThat( carDto.getManufacturingYear() ).isEqualTo( "1980" );
}
@Test(enabled = false)
public void shouldApplyConverterForReverseMapping() {
//given
CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) );
//when
Car car = NativeCarMapper.INSTANCE.carDtoToCar( carDto );
//then
assertThat( car ).isNotNull();
assertThat( car.getYearOfManufacture() ).isEqualTo( 1980 );
}
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,21 +15,25 @@
*/ */
package de.moapa.maple.ap.test.model; package de.moapa.maple.ap.test.model;
import java.util.ArrayList;
public class Car { public class Car {
private String make; private String make;
private int numberOfSeats; private int numberOfSeats;
private int yearOfManufacture; private int yearOfManufacture;
private Person driver; private Person driver;
private ArrayList<Person> passengers;
public Car() { public Car() {
} }
public Car(String make, int numberOfSeats, int yearOfManufacture, Person driver) { public Car(String make, int numberOfSeats, int yearOfManufacture, Person driver, ArrayList<Person> passengers) {
this.make = make; this.make = make;
this.numberOfSeats = numberOfSeats; this.numberOfSeats = numberOfSeats;
this.yearOfManufacture = yearOfManufacture; this.yearOfManufacture = yearOfManufacture;
this.driver = driver; this.driver = driver;
this.passengers = passengers;
} }
public String getMake() { public String getMake() {
@ -63,4 +67,12 @@ public class Car {
public void setDriver(Person driver) { public void setDriver(Person driver) {
this.driver = driver; this.driver = driver;
} }
public ArrayList<Person> getPassengers() {
return passengers;
}
public void setPassengers(ArrayList<Person> passengers) {
this.passengers = passengers;
}
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,21 +15,25 @@
*/ */
package de.moapa.maple.ap.test.model; package de.moapa.maple.ap.test.model;
import java.util.ArrayList;
public class CarDto { public class CarDto {
private String make; private String make;
private int seatCount; private int seatCount;
private String manufacturingYear; private String manufacturingYear;
private PersonDto driver; private PersonDto driver;
private ArrayList<PersonDto> passengers;
public CarDto() { public CarDto() {
} }
public CarDto(String make, int seatCount, String manufacturingYear, PersonDto driver) { public CarDto(String make, int seatCount, String manufacturingYear, PersonDto driver, ArrayList<PersonDto> passengers) {
this.make = make; this.make = make;
this.seatCount = seatCount; this.seatCount = seatCount;
this.manufacturingYear = manufacturingYear; this.manufacturingYear = manufacturingYear;
this.driver = driver; this.driver = driver;
this.passengers = passengers;
} }
public String getMake() { public String getMake() {
@ -63,4 +67,12 @@ public class CarDto {
public void setDriver(PersonDto driver) { public void setDriver(PersonDto driver) {
this.driver = driver; this.driver = driver;
} }
public ArrayList<PersonDto> getPassengers() {
return passengers;
}
public void setPassengers(ArrayList<PersonDto> passengers) {
this.passengers = passengers;
}
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,6 +15,8 @@
*/ */
package de.moapa.maple.ap.test.model; package de.moapa.maple.ap.test.model;
import java.util.ArrayList;
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;
@ -32,4 +34,16 @@ public interface CarMapper {
CarDto carToCarDto(Car car); CarDto carToCarDto(Car car);
Car carDtoToCar(CarDto carDto); Car carDtoToCar(CarDto carDto);
ArrayList<CarDto> carsToCarDtos(ArrayList<Car> cars);
ArrayList<Car> carDtosToCars(ArrayList<CarDto> carDtos);
PersonDto personToPersonDto(Person person);
Person personDtoToPerson(PersonDto personDto);
ArrayList<PersonDto> personsToPersonDtos(ArrayList<Person> persons);
ArrayList<Person> personDtosToPersons(ArrayList<PersonDto> personDtos);
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,35 +0,0 @@
/**
* 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.Mapper;
import de.moapa.maple.Mappers;
import de.moapa.maple.Mapping;
import de.moapa.maple.Mappings;
@Mapper("native")
public interface NativeCarMapper {
NativeCarMapper INSTANCE = Mappers.getMapper( NativeCarMapper.class );
@Mappings({
@Mapping(source = "numberOfSeats", target = "seatCount"),
@Mapping(source = "yearOfManufacture", target = "manufacturingYear", converter = IntToStringConverter.class)
})
CarDto carToCarDto(Car car);
Car carDtoToCar(CarDto carDto);
}

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.