22
33import com .squareup .javapoet .ClassName ;
44import com .squareup .javapoet .MethodSpec ;
5+ import com .squareup .javapoet .ParameterSpec ;
6+ import com .squareup .javapoet .TypeName ;
57import com .squareup .javapoet .TypeSpec ;
68
79import java .util .ArrayList ;
1618import javax .lang .model .element .Modifier ;
1719import javax .lang .model .element .TypeElement ;
1820import javax .lang .model .element .VariableElement ;
19- import javax .lang .model .type .TypeKind ;
2021import javax .lang .model .type .TypeMirror ;
2122import javax .lang .model .util .ElementFilter ;
2223import javax .tools .Diagnostic ;
@@ -34,12 +35,14 @@ static MapperGenerator create(TypeElement element, ProcessingEnvironment env) {
3435
3536 private final TypeElement element ;
3637 private final ProcessingEnvironment processingEnv ;
37- private List <Mapping > mappings ;
38+ private List <MappingInfo > mappings ;
39+ private List <MappingInfo > autoMappings ;
3840
3941 private MapperGenerator (TypeElement mapperElement , ProcessingEnvironment processingEnvironment ) {
4042 this .processingEnv = processingEnvironment ;
4143 this .element = mapperElement ;
4244 mappings = new ArrayList <>();
45+ autoMappings = new ArrayList <>();
4346 }
4447
4548 public TypeSpec generate () {
@@ -49,85 +52,93 @@ public TypeSpec generate() {
4952 .addModifiers (Modifier .PUBLIC )
5053 .addSuperinterface (ClassName .get (element ));
5154
52- for (Mapping mapping : mappings ) {
55+ for (MappingInfo mapping : mappings ) {
5356 MethodSpec methodSpec = generateMappingMethod (mapping );
5457 implBuilder .addMethod (methodSpec );
5558 }
5659
60+ for (MappingInfo autoMapping : autoMappings ) {
61+ MethodSpec methodSpec = generateMappingMethod (autoMapping );
62+ implBuilder .addMethod (methodSpec );
63+ }
64+
65+
5766 return implBuilder .build ();
5867 }
5968
6069 private void collectMappings () {
6170 for (ExecutableElement method : ElementFilter .methodsIn (element .getEnclosedElements ())) {
6271 try {
63- mappings .add (new Mapping (method ));
72+ mappings .add (new MappingInfo (method ));
6473 } catch (IllegalArgumentException exc ) {
6574 processingEnv .getMessager ().printMessage (Diagnostic .Kind .WARNING , exc .getMessage (), method );
6675 }
6776 }
6877 }
6978
70- private MethodSpec generateMappingMethod (Mapping mapping ) {
71- ExecutableElement constructorElement = getConstructorElement (mapping .target .toString ());
79+ private MethodSpec generateMappingMethod (MappingInfo mapping ) {
80+ ExecutableElement constructorElement = getConstructorElement (mapping .getTargetType () .toString ());
7281 List <? extends VariableElement > constructorParameters = constructorElement .getParameters ();
7382
74- Map <String , ExecutableElement > argumentGetters = getGetters (mapping .source .toString ());
83+ Map <String , ExecutableElement > argumentGetters = getGetters (mapping .getSourceType () .toString ());
7584
7685
7786 if (constructorParameters .size () != argumentGetters .size ()) {
78- processingEnv .getMessager ().printMessage (Diagnostic .Kind .MANDATORY_WARNING , "Target constructor have different arguments count" , mapping .method );
87+ processingEnv .getMessager ().printMessage (Diagnostic .Kind .MANDATORY_WARNING , "Target constructor have different arguments count" , mapping .getMethod () );
7988 }
8089
81- MethodSpec .Builder methodBuilder = MethodSpec .overriding (mapping .method );
90+
91+ MethodSpec .Builder methodBuilder = createMethodBuilder (mapping );
8292 StringBuilder statementBuilder = new StringBuilder ();
8393 statementBuilder
8494 .append ("return new " )
85- .append (mapping .target .toString ())
95+ .append (mapping .getTargetType () .toString ())
8696 .append ("(" );
8797
8898 String separator = "" ;
8999 for (VariableElement constructorParameter : constructorParameters ) {
90- String sourceFieldName = constructorParameter .getSimpleName ().toString ().toLowerCase ();
91- com .devindi .mapper .Mapping annotation = mapping .method .getAnnotation (com .devindi .mapper .Mapping .class );
92- if (annotation != null && annotation .target ().toLowerCase ().equals (constructorParameter .getSimpleName ().toString ().toLowerCase ())) {
93- sourceFieldName = annotation .source ();
94- }
95- Mappings mappings = mapping .method .getAnnotation (Mappings .class );
96- if (mappings != null ) {
97- for (com .devindi .mapper .Mapping fieldMapping : mappings .value ()) {
98- if (fieldMapping != null && fieldMapping .target ().toLowerCase ().equals (constructorParameter .getSimpleName ().toString ().toLowerCase ())) {
99- sourceFieldName = fieldMapping .source ();
100- }
101- }
102- }
100+ String sourceFieldName = mapping .getSourceFieldName (constructorParameter .getSimpleName ().toString ().toLowerCase ());
103101 ExecutableElement getter = argumentGetters .get (sourceFieldName .toLowerCase ());
104102 if (getter == null ) {
105103 processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , "Failed to find getter at source for target field" , constructorParameter );
106104 return null ;
107105 }
108106 if (!constructorParameter .asType ().equals (getter .getReturnType ())) {
109107 //getter and constructor parameter have different types
110- // TODO: 01.09.17 try to map/convert source field to target field
111- processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , "Getter return type and constructor argument type are different" , mapping .method );
108+ MappingInfo depMapping = findMapping (getter .getReturnType (), constructorParameter .asType ());
109+ if (depMapping == null ) {
110+ depMapping = new MappingInfo (getter .getReturnType (), constructorParameter .asType ());
111+ autoMappings .add (depMapping );
112+ }
113+ statementBuilder
114+ .append (separator )
115+ .append ('\n' )
116+ .append ("this." )
117+ .append (depMapping .getMethodName ())
118+ .append ("(" )
119+ .append (mapping .getSourceName ())
120+ .append ("." )
121+ .append (getter .getSimpleName ())
122+ .append ("()" )
123+ .append (")" );
124+ separator = "," ;
125+ } else {
126+ statementBuilder
127+ .append (separator )
128+ .append ('\n' )
129+ .append (mapping .getSourceName ())
130+ .append ("." )
131+ .append (getter .getSimpleName ())
132+ .append ("()" );
133+ separator = "," ;
112134 }
113-
114- statementBuilder
115- .append (separator )
116- .append ('\n' )
117- .append (mapping .method .getParameters ().get (0 ).getSimpleName ())
118- .append ("." )
119- .append (getter .getSimpleName ())
120- .append ("()" );
121- separator = "," ;
122135 }
123136
124137 statementBuilder
125138 .append ('\n' )
126139 .append (")" );
127140 methodBuilder .addStatement (statementBuilder .toString ());
128141
129-
130-
131142 return methodBuilder .build ();
132143 }
133144
@@ -151,24 +162,24 @@ private Map<String, ExecutableElement> getGetters(String className) {
151162 return gettersMap ;
152163 }
153164
154- private static class Mapping {
155- private final TypeMirror source ;
156- private final TypeMirror target ;
157- private final ExecutableElement method ;
158-
159- public Mapping (ExecutableElement method ) {
160- this .method = method ;
161- target = method .getReturnType ();
162- if (target .getKind ().equals (TypeKind .VOID )) {
163- throw new IllegalArgumentException ("Mapper method should return value. Method will be ignored" );
165+ private MappingInfo findMapping (TypeMirror source , TypeMirror target ) {
166+ for (MappingInfo mapping : mappings ) {
167+ if (mapping .getSourceType ().equals (source ) && mapping .getTargetType ().equals (target )) {
168+ return mapping ;
164169 }
165- List <? extends VariableElement > parameters = method .getParameters ();
166- if (parameters .size () != 1 ) {
167- throw new IllegalArgumentException ("Mapper method should have only 1 parameter. Method will be ignored" );
168- }
169- source = parameters .get (0 ).asType ();
170170 }
171+ return null ;
171172 }
172173
173-
174+ private MethodSpec .Builder createMethodBuilder (MappingInfo info ) {
175+ ExecutableElement method = info .getMethod ();
176+ if (method == null ) {
177+ MethodSpec .Builder builder = MethodSpec .methodBuilder (info .getMethodName ().toString ());
178+ builder .addModifiers (Modifier .PRIVATE );
179+ builder .returns (TypeName .get (info .getTargetType ()));
180+ builder .addParameter (ParameterSpec .builder (TypeName .get (info .getSourceType ()), "source" ).build ());
181+ return builder ;
182+ }
183+ return MethodSpec .overriding (method );
184+ }
174185}
0 commit comments