1818import java .io .StringWriter ;
1919import java .lang .reflect .Field ;
2020import java .util .ArrayList ;
21+ import java .util .Collections ;
22+ import java .util .HashMap ;
23+ import java .util .LinkedHashMap ;
2124import java .util .List ;
25+ import java .util .Map ;
2226
2327import javax .lang .model .element .Element ;
2428import javax .lang .model .element .ExecutableElement ;
3135import javax .lang .model .type .TypeMirror ;
3236import javax .lang .model .type .WildcardType ;
3337import javax .lang .model .util .ElementFilter ;
38+ import javax .lang .model .util .Types ;
3439
3540import org .androidannotations .holder .EComponentHolder ;
3641import org .androidannotations .holder .GeneratedClassHolder ;
4752import com .sun .codemodel .JMethod ;
4853import com .sun .codemodel .JMod ;
4954import com .sun .codemodel .JStatement ;
55+ import com .sun .codemodel .JSuperWildcard ;
5056import com .sun .codemodel .JType ;
5157import com .sun .codemodel .JVar ;
5258
5359public class APTCodeModelHelper {
5460
5561 public JClass typeMirrorToJClass (TypeMirror type , GeneratedClassHolder holder ) {
62+ return typeMirrorToJClass (type , holder , Collections .<String , TypeMirror >emptyMap ());
63+ }
64+
65+ private JClass typeMirrorToJClass (TypeMirror type , GeneratedClassHolder holder , Map <String , TypeMirror > substitute ) {
5666
5767 if (type instanceof DeclaredType ) {
5868 DeclaredType declaredType = (DeclaredType ) type ;
@@ -65,38 +75,51 @@ public JClass typeMirrorToJClass(TypeMirror type, GeneratedClassHolder holder) {
6575
6676 List <JClass > typeArgumentJClasses = new ArrayList <JClass >();
6777 for (TypeMirror typeArgument : typeArguments ) {
68- typeArgumentJClasses .add (typeMirrorToJClass (typeArgument , holder ));
78+ typeArgumentJClasses .add (typeMirrorToJClass (typeArgument , holder , substitute ));
6979 }
7080 if (typeArgumentJClasses .size () > 0 ) {
7181 declaredClass = declaredClass .narrow (typeArgumentJClasses );
7282 }
7383
7484 return declaredClass ;
7585 } else if (type instanceof WildcardType ) {
76- // TODO : At his time (01/2013), it is not possible to handle the
77- // super bound because code model does not offer a way to model
78- // statement like " ? super X"
79- // (see http://java.net/jira/browse/CODEMODEL-11)
8086 WildcardType wildcardType = (WildcardType ) type ;
8187
88+ TypeMirror bound = wildcardType .getExtendsBound ();
89+ if (bound == null ) {
90+ bound = wildcardType .getSuperBound ();
91+ if (bound == null ) {
92+ return holder .classes ().OBJECT .wildcard ();
93+ }
94+ return superWildcard (typeMirrorToJClass (bound , holder , substitute ));
95+ }
96+
8297 TypeMirror extendsBound = wildcardType .getExtendsBound ();
8398
8499 if (extendsBound == null ) {
85100 return holder .classes ().OBJECT .wildcard ();
86101 } else {
87- return typeMirrorToJClass (extendsBound , holder ).wildcard ();
102+ return typeMirrorToJClass (extendsBound , holder , substitute ).wildcard ();
88103 }
89104 } else if (type instanceof ArrayType ) {
90105 ArrayType arrayType = (ArrayType ) type ;
91106
92- JClass refClass = typeMirrorToJClass (arrayType .getComponentType (), holder );
107+ JClass refClass = typeMirrorToJClass (arrayType .getComponentType (), holder , substitute );
93108
94109 return refClass .array ();
95110 } else {
111+ TypeMirror substituted = substitute .get (type .toString ());
112+ if (substituted != null && type != substituted ) {
113+ return typeMirrorToJClass (substituted , holder , substitute );
114+ }
96115 return holder .refClass (type .toString ());
97116 }
98117 }
99118
119+ private JClass superWildcard (final JClass bound ) {
120+ return new JSuperWildcard (bound );
121+ }
122+
100123 public static class Parameter {
101124 public final String name ;
102125 public final JClass jClass ;
@@ -107,15 +130,67 @@ public Parameter(String name, JClass jClass) {
107130 }
108131 }
109132
133+ private Map <String , TypeMirror > getActualTypes (Types typeUtils , DeclaredType baseClass , TypeMirror annotatedClass ) {
134+ List <TypeMirror > superTypes = new ArrayList <TypeMirror >();
135+ superTypes .add (annotatedClass );
136+ while (!superTypes .isEmpty ()) {
137+ TypeMirror x = superTypes .remove (0 );
138+ if (typeUtils .isSameType (typeUtils .erasure (x ), typeUtils .erasure (baseClass ))) {
139+ DeclaredType type = (DeclaredType ) x ;
140+ Map <String , TypeMirror > actualTypes = new HashMap <String , TypeMirror >();
141+ for (int i = 0 ; i < type .getTypeArguments ().size (); i ++) {
142+ TypeMirror actualArg = type .getTypeArguments ().get (i );
143+ TypeMirror formalArg = baseClass .getTypeArguments ().get (i );
144+ if (!typeUtils .isSameType (actualArg , formalArg )) {
145+ actualTypes .put (formalArg .toString (), actualArg );
146+ }
147+ }
148+ return actualTypes ;
149+ }
150+ superTypes .addAll (typeUtils .directSupertypes (x ));
151+ }
152+ return Collections .emptyMap ();
153+ }
154+
155+ public JClass typeBoundsToJClass (GeneratedClassHolder holder , List <? extends TypeMirror > bounds ) {
156+ return typeBoundsToJClass (holder , bounds , Collections .<String , TypeMirror >emptyMap ());
157+ }
158+
159+ private JClass typeBoundsToJClass (GeneratedClassHolder holder , List <? extends TypeMirror > bounds , Map <String , TypeMirror > actualTypes ) {
160+ if (bounds .isEmpty ()) {
161+ return holder .classes ().OBJECT ;
162+ } else {
163+ //TODO resolve <T extends A&B> bounds
164+ return typeMirrorToJClass (bounds .get (0 ), holder , actualTypes );
165+ }
166+ }
167+
110168 public JMethod overrideAnnotatedMethod (ExecutableElement executableElement , GeneratedClassHolder holder ) {
169+ TypeMirror annotatedClass = holder .getAnnotatedElement ().asType ();
170+ DeclaredType baseClass = (DeclaredType ) executableElement .getEnclosingElement ().asType ();
171+
172+ Types typeUtils = holder .processingEnvironment ().getTypeUtils ();
173+
174+ Map <String , TypeMirror > actualTypes = getActualTypes (typeUtils , baseClass , annotatedClass );
175+ Map <String , JClass > methodTypes = new LinkedHashMap <String , JClass >();
176+
177+ for (TypeParameterElement typeParameter : executableElement .getTypeParameters ()) {
178+ List <? extends TypeMirror > bounds = typeParameter .getBounds ();
179+ JClass jClassBounds = typeBoundsToJClass (holder , bounds , actualTypes );
180+ methodTypes .put (typeParameter .toString (), jClassBounds );
181+ }
182+
183+ actualTypes .keySet ().removeAll (methodTypes .keySet ());
111184
112185 String methodName = executableElement .getSimpleName ().toString ();
113- JClass returnType = typeMirrorToJClass (executableElement .getReturnType (), holder );
186+ JClass returnType = typeMirrorToJClass (executableElement .getReturnType (), holder , actualTypes );
114187
115188 List <Parameter > parameters = new ArrayList <Parameter >();
116- for (VariableElement parameter : executableElement .getParameters ()) {
117- String parameterName = parameter .getSimpleName ().toString ();
118- JClass parameterClass = typeMirrorToJClass (parameter .asType (), holder );
189+ for (int i = 0 ; i < executableElement .getParameters ().size (); i ++) {
190+ VariableElement parameter = executableElement .getParameters ().get (i );
191+
192+ String parameterName = parameter .getSimpleName ().toString ();
193+ JClass parameterClass = typeMirrorToJClass (parameter .asType (), holder , actualTypes );
119194 parameters .add (new Parameter (parameterName , parameterClass ));
120195 }
121196
@@ -128,32 +203,19 @@ public JMethod overrideAnnotatedMethod(ExecutableElement executableElement, Gene
128203 JMethod method = holder .getGeneratedClass ().method (JMod .PUBLIC , returnType , methodName );
129204 method .annotate (Override .class );
130205
131- for (VariableElement parameter : executableElement .getParameters ()) {
132- String parameterName = parameter .getSimpleName ().toString ();
133- JClass parameterClass = typeMirrorToJClass (parameter .asType (), holder );
134- method .param (JMod .FINAL , parameterClass , parameterName );
135- }
206+ for (Map .Entry <String , JClass > typeDeclaration : methodTypes .entrySet ()) {
207+ method .generify (typeDeclaration .getKey (), typeDeclaration .getValue ());
208+ }
209+
210+ for (Parameter parameter : parameters ) {
211+ method .param (JMod .FINAL , parameter .jClass , parameter .name );
212+ }
136213
137214 for (TypeMirror superThrownType : executableElement .getThrownTypes ()) {
138- JClass thrownType = typeMirrorToJClass (superThrownType , holder );
215+ JClass thrownType = typeMirrorToJClass (superThrownType , holder , actualTypes );
139216 method ._throws (thrownType );
140217 }
141218
142- for (TypeParameterElement typeParameter : executableElement .getTypeParameters ()) {
143- List <? extends TypeMirror > bounds = typeParameter .getBounds ();
144-
145- JClass jClassBounds ;
146- if (bounds .isEmpty ()) {
147- jClassBounds = holder .classes ().OBJECT ;
148- } else {
149- // Currently Codemodel can't generate generics with multiple
150- // classes like this <T extends Number & Serializable>.
151- // So we only take the first class
152- jClassBounds = typeMirrorToJClass (bounds .get (0 ), holder );
153- }
154- method .generify (typeParameter .toString (), jClassBounds );
155- }
156-
157219 callSuperMethod (method , holder , method .body ());
158220
159221 return method ;
0 commit comments