Skip to content

Commit 8f132d8

Browse files
committed
Merge pull request androidannotations#867 from Artyomcool/865_generic_beans_hierarchy
generic beans hierarchy
2 parents 29f88f0 + eb80ac3 commit 8f132d8

16 files changed

Lines changed: 294 additions & 50 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.sun.codemodel;
2+
3+
import java.util.Iterator;
4+
import java.util.List;
5+
6+
// TODO : At his time (01/2013), it is not possible to handle the
7+
// super bound because code model does not offer a way to model
8+
// statement like " ? super X"
9+
// (see http://java.net/jira/browse/CODEMODEL-11)
10+
//
11+
// This class is a hack against it.
12+
// So, if it will be fixed in code model - just remove this
13+
public class JSuperWildcard extends JClass {
14+
15+
private final JClass bound;
16+
17+
public JSuperWildcard(JClass bound) {
18+
super(bound.owner());
19+
this.bound = bound;
20+
}
21+
22+
public String name() {
23+
return "? super "+ bound.name();
24+
}
25+
26+
public String fullName() {
27+
return "? super "+ bound.fullName();
28+
}
29+
30+
public JPackage _package() {
31+
return null;
32+
}
33+
34+
/**
35+
* Returns the class bound of this variable.
36+
*
37+
* <p>
38+
* If no bound is given, this method returns {@link Object}.
39+
*/
40+
public JClass _extends() {
41+
if(bound !=null)
42+
return bound;
43+
else
44+
return owner().ref(Object.class);
45+
}
46+
47+
/**
48+
* Returns the interface bounds of this variable.
49+
*/
50+
public Iterator<JClass> _implements() {
51+
return bound._implements();
52+
}
53+
54+
public boolean isInterface() {
55+
return false;
56+
}
57+
58+
public boolean isAbstract() {
59+
return false;
60+
}
61+
62+
protected JClass substituteParams(JTypeVar[] variables, List<JClass> bindings) {
63+
JClass nb = bound.substituteParams(variables,bindings);
64+
if(nb== bound)
65+
return this;
66+
else
67+
return nb.wildcard();
68+
}
69+
70+
public void generate(JFormatter f) {
71+
if(bound._extends()==null)
72+
f.p("?"); // instead of "? extends Object"
73+
else
74+
f.p("? super").g(bound);
75+
}
76+
}

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/handler/BeanHandler.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import javax.annotation.processing.ProcessingEnvironment;
2323
import javax.lang.model.element.Element;
2424
import javax.lang.model.type.TypeMirror;
25+
import javax.lang.model.util.Types;
2526

2627
import org.androidannotations.annotations.Bean;
2728
import org.androidannotations.annotations.EBean;
@@ -60,6 +61,7 @@ public void process(Element element, EComponentHolder holder) throws Exception {
6061
TypeMirror elementType = annotationHelper.extractAnnotationClassParameter(element);
6162
if (elementType == null) {
6263
elementType = element.asType();
64+
elementType = holder.processingEnvironment().getTypeUtils().erasure(elementType);
6365
}
6466

6567
String fieldName = element.getSimpleName().toString();

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java‎

Lines changed: 94 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
import java.io.StringWriter;
1919
import java.lang.reflect.Field;
2020
import java.util.ArrayList;
21+
import java.util.Collections;
22+
import java.util.HashMap;
23+
import java.util.LinkedHashMap;
2124
import java.util.List;
25+
import java.util.Map;
2226

2327
import javax.lang.model.element.Element;
2428
import javax.lang.model.element.ExecutableElement;
@@ -31,6 +35,7 @@
3135
import javax.lang.model.type.TypeMirror;
3236
import javax.lang.model.type.WildcardType;
3337
import javax.lang.model.util.ElementFilter;
38+
import javax.lang.model.util.Types;
3439

3540
import org.androidannotations.holder.EComponentHolder;
3641
import org.androidannotations.holder.GeneratedClassHolder;
@@ -47,12 +52,17 @@
4752
import com.sun.codemodel.JMethod;
4853
import com.sun.codemodel.JMod;
4954
import com.sun.codemodel.JStatement;
55+
import com.sun.codemodel.JSuperWildcard;
5056
import com.sun.codemodel.JType;
5157
import com.sun.codemodel.JVar;
5258

5359
public 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;

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/holder/BaseGeneratedClassHolder.java‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@
2020

2121
import javax.annotation.processing.ProcessingEnvironment;
2222
import javax.lang.model.element.TypeElement;
23+
import javax.lang.model.element.TypeParameterElement;
24+
import javax.lang.model.util.Elements;
25+
import javax.lang.model.util.Types;
2326

27+
import org.androidannotations.helper.APTCodeModelHelper;
2428
import org.androidannotations.helper.ModelConstants;
29+
import org.androidannotations.logger.Logger;
30+
import org.androidannotations.logger.LoggerFactory;
2531
import org.androidannotations.process.ProcessHolder;
2632

2733
import com.sun.codemodel.ClassType;
@@ -34,18 +40,25 @@ public abstract class BaseGeneratedClassHolder implements GeneratedClassHolder {
3440
protected final ProcessHolder processHolder;
3541
protected JDefinedClass generatedClass;
3642
protected final TypeElement annotatedElement;
43+
protected final APTCodeModelHelper codeModelHelper;
3744

3845
public BaseGeneratedClassHolder(ProcessHolder processHolder, TypeElement annotatedElement) throws Exception {
3946
this.processHolder = processHolder;
4047
this.annotatedElement = annotatedElement;
48+
this.codeModelHelper = new APTCodeModelHelper();
4149
setGeneratedClass();
4250
}
4351

4452
protected void setGeneratedClass() throws Exception {
4553
String annotatedComponentQualifiedName = annotatedElement.getQualifiedName().toString();
46-
String subComponentQualifiedName = annotatedComponentQualifiedName + ModelConstants.GENERATION_SUFFIX;
47-
JClass annotatedComponent = codeModel().directClass(annotatedComponentQualifiedName);
54+
String subComponentQualifiedName = annotatedComponentQualifiedName + ModelConstants.GENERATION_SUFFIX;
55+
JClass annotatedComponent = codeModel().directClass(annotatedElement.asType().toString());
56+
4857
generatedClass = codeModel()._class(PUBLIC | FINAL, subComponentQualifiedName, ClassType.CLASS);
58+
for (TypeParameterElement typeParam : annotatedElement.getTypeParameters()) {
59+
JClass bound = codeModelHelper.typeBoundsToJClass(this, typeParam.getBounds());
60+
generatedClass.generify(typeParam.getSimpleName().toString(), bound);
61+
}
4962
generatedClass._extends(annotatedComponent);
5063
}
5164

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/holder/EComponentWithViewSupportHolder.java‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import org.androidannotations.api.view.HasViews;
3333
import org.androidannotations.api.view.OnViewChangedListener;
3434
import org.androidannotations.api.view.OnViewChangedNotifier;
35-
import org.androidannotations.helper.APTCodeModelHelper;
3635
import org.androidannotations.helper.ViewNotifierHelper;
3736
import org.androidannotations.process.ProcessHolder;
3837

@@ -47,7 +46,6 @@
4746

4847
public abstract class EComponentWithViewSupportHolder extends EComponentHolder {
4948

50-
private APTCodeModelHelper codeModelHelper;
5149
protected ViewNotifierHelper viewNotifierHelper;
5250
private JBlock onViewChangedBody;
5351
private JVar onViewChangedHasViewsParam;
@@ -60,7 +58,6 @@ public abstract class EComponentWithViewSupportHolder extends EComponentHolder {
6058

6159
public EComponentWithViewSupportHolder(ProcessHolder processHolder, TypeElement annotatedElement) throws Exception {
6260
super(processHolder, annotatedElement);
63-
codeModelHelper = new APTCodeModelHelper();
6461
viewNotifierHelper = new ViewNotifierHelper(this);
6562
}
6663

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/holder/EIntentServiceHolder.java‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import javax.lang.model.element.TypeElement;
2121

22-
import org.androidannotations.helper.APTCodeModelHelper;
2322
import org.androidannotations.helper.AndroidManifest;
2423
import org.androidannotations.process.ProcessHolder;
2524

@@ -31,8 +30,6 @@
3130

3231
public class EIntentServiceHolder extends EServiceHolder {
3332

34-
private APTCodeModelHelper codeModelHelper = new APTCodeModelHelper();
35-
3633
private JVar onHandleIntentIntent;
3734
private JMethod onHandleIntentMethod;
3835
private JBlock onHandleIntentBody;

0 commit comments

Comments
 (0)