1
1
/*
2
- * Copyright 2012-2018 the original author or authors.
2
+ * Copyright 2012-2019 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
21
21
import java .util .Collections ;
22
22
import java .util .EnumMap ;
23
23
import java .util .HashMap ;
24
+ import java .util .List ;
24
25
import java .util .Map ;
26
+ import java .util .Map .Entry ;
25
27
import java .util .regex .Pattern ;
26
28
import java .util .stream .Collectors ;
27
29
33
35
import javax .lang .model .type .PrimitiveType ;
34
36
import javax .lang .model .type .TypeKind ;
35
37
import javax .lang .model .type .TypeMirror ;
38
+ import javax .lang .model .type .TypeVariable ;
36
39
import javax .lang .model .util .SimpleTypeVisitor8 ;
37
40
import javax .lang .model .util .Types ;
41
+ import javax .tools .Diagnostic .Kind ;
38
42
39
43
/**
40
44
* Type Utilities.
@@ -73,18 +77,22 @@ class TypeUtils {
73
77
74
78
private final ProcessingEnvironment env ;
75
79
80
+ private final Types types ;
81
+
76
82
private final TypeExtractor typeExtractor ;
77
83
78
84
private final TypeMirror collectionType ;
79
85
80
86
private final TypeMirror mapType ;
81
87
88
+ private final Map <TypeElement , TypeDescriptor > typeDescriptors = new HashMap <>();
89
+
82
90
TypeUtils (ProcessingEnvironment env ) {
83
91
this .env = env ;
84
- Types types = env .getTypeUtils ();
85
- this .typeExtractor = new TypeExtractor (types );
86
- this .collectionType = getDeclaredType (types , Collection .class , 1 );
87
- this .mapType = getDeclaredType (types , Map .class , 2 );
92
+ this . types = env .getTypeUtils ();
93
+ this .typeExtractor = new TypeExtractor (this . types );
94
+ this .collectionType = getDeclaredType (this . types , Collection .class , 1 );
95
+ this .mapType = getDeclaredType (this . types , Map .class , 2 );
88
96
}
89
97
90
98
private TypeMirror getDeclaredType (Types types , Class <?> typeClass ,
@@ -115,14 +123,15 @@ public String getQualifiedName(Element element) {
115
123
/**
116
124
* Return the type of the specified {@link TypeMirror} including all its generic
117
125
* information.
126
+ * @param element the {@link TypeElement} in which this {@code type} is declared
118
127
* @param type the type to handle
119
128
* @return a representation of the type including all its generic information
120
129
*/
121
- public String getType (TypeMirror type ) {
130
+ public String getType (TypeElement element , TypeMirror type ) {
122
131
if (type == null ) {
123
132
return null ;
124
133
}
125
- return type .accept (this .typeExtractor , null );
134
+ return type .accept (this .typeExtractor , createTypeDescriptor ( element ) );
126
135
}
127
136
128
137
public boolean isCollectionOrMap (TypeMirror type ) {
@@ -160,11 +169,49 @@ private TypeKind getPrimitiveFor(TypeMirror type) {
160
169
return WRAPPER_TO_PRIMITIVE .get (type .toString ());
161
170
}
162
171
172
+ TypeDescriptor resolveTypeDescriptor (TypeElement element ) {
173
+ if (this .typeDescriptors .containsKey (element )) {
174
+ return this .typeDescriptors .get (element );
175
+ }
176
+ return createTypeDescriptor (element );
177
+ }
178
+
179
+ private TypeDescriptor createTypeDescriptor (TypeElement element ) {
180
+ TypeDescriptor descriptor = new TypeDescriptor ();
181
+ process (descriptor , element .asType ());
182
+ this .typeDescriptors .put (element , descriptor );
183
+ return descriptor ;
184
+ }
185
+
186
+ private void process (TypeDescriptor descriptor , TypeMirror type ) {
187
+ try {
188
+ if (type .getKind () == TypeKind .DECLARED ) {
189
+ DeclaredType declaredType = (DeclaredType ) type ;
190
+ DeclaredType freshType = (DeclaredType ) this .env .getElementUtils ()
191
+ .getTypeElement (this .types .asElement (type ).toString ()).asType ();
192
+ List <? extends TypeMirror > arguments = declaredType .getTypeArguments ();
193
+ for (int i = 0 ; i < arguments .size (); i ++) {
194
+ TypeMirror specificType = arguments .get (i );
195
+ TypeMirror signatureType = freshType .getTypeArguments ().get (i );
196
+ descriptor .registerIfNecessary (signatureType , specificType );
197
+ }
198
+ TypeElement element = (TypeElement ) this .types .asElement (type );
199
+ process (descriptor , element .getSuperclass ());
200
+ }
201
+ }
202
+ catch (Exception ex ) {
203
+ this .env .getMessager ().printMessage (Kind .WARNING ,
204
+ "Failed to generated type descriptor for " + type ,
205
+ this .types .asElement (type ));
206
+ }
207
+ }
208
+
163
209
/**
164
210
* A visitor that extracts the fully qualified name of a type, including generic
165
211
* information.
166
212
*/
167
- private static class TypeExtractor extends SimpleTypeVisitor8 <String , Void > {
213
+ private static class TypeExtractor
214
+ extends SimpleTypeVisitor8 <String , TypeDescriptor > {
168
215
169
216
private final Types types ;
170
217
@@ -173,34 +220,60 @@ private static class TypeExtractor extends SimpleTypeVisitor8<String, Void> {
173
220
}
174
221
175
222
@ Override
176
- public String visitDeclared (DeclaredType type , Void none ) {
223
+ public String visitDeclared (DeclaredType type , TypeDescriptor descriptor ) {
177
224
TypeElement enclosingElement = getEnclosingTypeElement (type );
178
- if (enclosingElement != null ) {
179
- return getQualifiedName (enclosingElement ) + "$"
180
- + type .asElement ().getSimpleName ();
181
- }
182
- String qualifiedName = getQualifiedName (type .asElement ());
225
+ String qualifiedName = determineQualifiedName (type , enclosingElement );
183
226
if (type .getTypeArguments ().isEmpty ()) {
184
227
return qualifiedName ;
185
228
}
186
229
StringBuilder name = new StringBuilder ();
187
230
name .append (qualifiedName );
188
231
name .append ("<" ).append (type .getTypeArguments ().stream ()
189
- .map (TypeMirror :: toString ).collect (Collectors .joining ("," )))
232
+ .map (( t ) -> visit ( t , descriptor ) ).collect (Collectors .joining ("," )))
190
233
.append (">" );
191
234
return name .toString ();
192
235
}
193
236
237
+ private String determineQualifiedName (DeclaredType type ,
238
+ TypeElement enclosingElement ) {
239
+ if (enclosingElement != null ) {
240
+ return getQualifiedName (enclosingElement ) + "$"
241
+ + type .asElement ().getSimpleName ();
242
+ }
243
+ return getQualifiedName (type .asElement ());
244
+ }
245
+
246
+ @ Override
247
+ public String visitTypeVariable (TypeVariable t , TypeDescriptor descriptor ) {
248
+ TypeMirror typeMirror = descriptor .resolveGeneric (t );
249
+ if (typeMirror != null ) {
250
+ if (typeMirror instanceof TypeVariable ) {
251
+ // Still unresolved, let's use upper bound
252
+ return visit (((TypeVariable ) typeMirror ).getUpperBound (), descriptor );
253
+ }
254
+ else {
255
+ return visit (typeMirror , descriptor );
256
+ }
257
+ }
258
+ // Unresolved generics, use upper bound
259
+ return visit (t .getUpperBound (), descriptor );
260
+ }
261
+
194
262
@ Override
195
- public String visitArray (ArrayType t , Void none ) {
196
- return t .getComponentType ().accept (this , none ) + "[]" ;
263
+ public String visitArray (ArrayType t , TypeDescriptor descriptor ) {
264
+ return t .getComponentType ().accept (this , descriptor ) + "[]" ;
197
265
}
198
266
199
267
@ Override
200
- public String visitPrimitive (PrimitiveType t , Void none ) {
268
+ public String visitPrimitive (PrimitiveType t , TypeDescriptor descriptor ) {
201
269
return this .types .boxedClass (t ).getQualifiedName ().toString ();
202
270
}
203
271
272
+ @ Override
273
+ protected String defaultAction (TypeMirror t , TypeDescriptor descriptor ) {
274
+ return t .toString ();
275
+ }
276
+
204
277
public String getQualifiedName (Element element ) {
205
278
if (element == null ) {
206
279
return null ;
@@ -230,4 +303,42 @@ private TypeElement getEnclosingTypeElement(TypeMirror type) {
230
303
231
304
}
232
305
306
+ /**
307
+ * Descriptor for a given type.
308
+ */
309
+ static class TypeDescriptor {
310
+
311
+ private final Map <TypeVariable , TypeMirror > generics = new HashMap <>();
312
+
313
+ public Map <TypeVariable , TypeMirror > getGenerics () {
314
+ return Collections .unmodifiableMap (this .generics );
315
+ }
316
+
317
+ public TypeMirror resolveGeneric (TypeVariable typeVariable ) {
318
+ return resolveGeneric (getParameterName (typeVariable ));
319
+ }
320
+
321
+ public TypeMirror resolveGeneric (String parameterName ) {
322
+ return this .generics .entrySet ().stream ()
323
+ .filter ((e ) -> getParameterName (e .getKey ()).equals (parameterName ))
324
+ .findFirst ().map (Entry ::getValue ).orElse (null );
325
+ }
326
+
327
+ private void registerIfNecessary (TypeMirror variable , TypeMirror resolution ) {
328
+ if (variable instanceof TypeVariable ) {
329
+ TypeVariable typeVariable = (TypeVariable ) variable ;
330
+ if (this .generics .keySet ().stream ()
331
+ .noneMatch ((candidate ) -> getParameterName (candidate )
332
+ .equals (getParameterName (typeVariable )))) {
333
+ this .generics .put (typeVariable , resolution );
334
+ }
335
+ }
336
+ }
337
+
338
+ private String getParameterName (TypeVariable typeVariable ) {
339
+ return typeVariable .asElement ().getSimpleName ().toString ();
340
+ }
341
+
342
+ }
343
+
233
344
}
0 commit comments