Skip to content

Commit d1d56e9

Browse files
committed
Support multi-bounded type variables and wildcards
1 parent c87cbeb commit d1d56e9

9 files changed

Lines changed: 61 additions & 37 deletions

File tree

AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/ActivityWithGenerics.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@
2626
@EActivity
2727
public class ActivityWithGenerics extends Activity {
2828

29-
// @UiThread
30-
// <T, S extends Number & List<String>> void emptyUiMethod(T param, S
31-
// param2) {
32-
// }
29+
@UiThread
30+
<T, S extends Number & List<String>> void emptyUiMethod(T param, S param2) {
31+
}
3332

3433
@UiThread
3534
<T, S extends Number> void emptyUiMethod(List<? extends T> param, List<? super S> param2) {

AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/GenericFragmentArguments.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.androidannotations.test;
1717

18+
import java.io.Closeable;
1819
import java.io.Serializable;
1920

2021
import org.androidannotations.annotations.EFragment;
@@ -24,7 +25,7 @@
2425
import android.app.Fragment;
2526

2627
@EFragment
27-
public class GenericFragmentArguments<S extends Serializable, P extends Account> extends Fragment {
28+
public class GenericFragmentArguments<S extends Serializable & Closeable, P extends Account> extends Fragment {
2829

2930
@FragmentArg
3031
S[] serializableArray;

AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/GenericFragmentArgsTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import static org.fest.assertions.api.Assertions.assertThat;
1919

20+
import java.io.Closeable;
21+
import java.io.IOException;
2022
import java.io.Serializable;
2123

2224
import org.junit.Test;
@@ -38,7 +40,7 @@ public void testParcelableArrayFragmentArgInjected() {
3840
Bundle bundle = new Bundle();
3941
bundle.putParcelableArray("parcelableArray", TEST_ARRAY);
4042

41-
GenericFragmentArguments<Serializable, Account> fragment = new GenericFragmentArguments_<Serializable, Account>();
43+
GenericFragmentArguments<CloseableSerializable, Account> fragment = new GenericFragmentArguments_<CloseableSerializable, Account>();
4244
fragment.setArguments(bundle);
4345

4446
assertThat(fragment.parcelableArray).isNull();
@@ -47,4 +49,11 @@ public void testParcelableArrayFragmentArgInjected() {
4749

4850
assertThat(fragment.parcelableArray).isEqualTo(TEST_ARRAY);
4951
}
52+
53+
private static class CloseableSerializable implements Closeable, Serializable {
54+
@Override
55+
public void close() throws IOException {
56+
57+
}
58+
}
5059
}

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import com.helger.jcodemodel.AbstractJType;
5858
import com.helger.jcodemodel.IJAnnotatable;
5959
import com.helger.jcodemodel.IJExpression;
60+
import com.helger.jcodemodel.IJGenerifiable;
6061
import com.helger.jcodemodel.IJStatement;
6162
import com.helger.jcodemodel.JAnnotationArrayMember;
6263
import com.helger.jcodemodel.JAnnotationUse;
@@ -68,6 +69,7 @@
6869
import com.helger.jcodemodel.JInvocation;
6970
import com.helger.jcodemodel.JMethod;
7071
import com.helger.jcodemodel.JMod;
72+
import com.helger.jcodemodel.JTypeVar;
7173
import com.helger.jcodemodel.JVar;
7274

7375
public class APTCodeModelHelper {
@@ -162,16 +164,32 @@ private Map<String, TypeMirror> getActualTypes(Types typeUtils, DeclaredType bas
162164
return Collections.emptyMap();
163165
}
164166

165-
public AbstractJClass typeBoundsToJClass(List<? extends TypeMirror> bounds) {
167+
public List<AbstractJClass> typeBoundsToJClass(List<? extends TypeMirror> bounds) {
166168
return typeBoundsToJClass(bounds, Collections.<String, TypeMirror>emptyMap());
167169
}
168170

169-
private AbstractJClass typeBoundsToJClass(List<? extends TypeMirror> bounds, Map<String, TypeMirror> actualTypes) {
171+
private List<AbstractJClass> typeBoundsToJClass(List<? extends TypeMirror> bounds, Map<String, TypeMirror> actualTypes) {
170172
if (bounds.isEmpty()) {
171-
return environment.getClasses().OBJECT;
173+
return Collections.singletonList(environment.getClasses().OBJECT);
172174
} else {
173-
// TODO resolve <T extends A&B> bounds
174-
return typeMirrorToJClass(bounds.get(0), actualTypes);
175+
List<AbstractJClass> jClassBounds = new ArrayList<>();
176+
177+
for (TypeMirror bound : bounds) {
178+
jClassBounds.add(typeMirrorToJClass(bound, actualTypes));
179+
}
180+
return jClassBounds;
181+
}
182+
}
183+
184+
private void addTypeBounds(IJGenerifiable generifiable, List<AbstractJClass> bounds, String name) {
185+
JTypeVar typeVar = null;
186+
187+
for (AbstractJClass bound : bounds) {
188+
if (typeVar == null) {
189+
typeVar = generifiable.generify(name, bound);
190+
} else {
191+
typeVar.bound(bound);
192+
}
175193
}
176194
}
177195

@@ -182,12 +200,13 @@ public JMethod overrideAnnotatedMethod(ExecutableElement executableElement, Gene
182200
Types typeUtils = environment.getProcessingEnvironment().getTypeUtils();
183201

184202
Map<String, TypeMirror> actualTypes = getActualTypes(typeUtils, baseClass, annotatedClass);
185-
Map<String, AbstractJClass> methodTypes = new LinkedHashMap<>();
203+
Map<String, List<AbstractJClass>> methodTypes = new LinkedHashMap<>();
186204

187205
for (TypeParameterElement typeParameter : executableElement.getTypeParameters()) {
188206
List<? extends TypeMirror> bounds = typeParameter.getBounds();
189-
AbstractJClass jClassBounds = typeBoundsToJClass(bounds, actualTypes);
190-
methodTypes.put(typeParameter.toString(), jClassBounds);
207+
208+
List<AbstractJClass> addedBounds = typeBoundsToJClass(bounds, actualTypes);
209+
methodTypes.put(typeParameter.toString(), addedBounds);
191210
}
192211

193212
actualTypes.keySet().removeAll(methodTypes.keySet());
@@ -206,8 +225,9 @@ public JMethod overrideAnnotatedMethod(ExecutableElement executableElement, Gene
206225
method.annotate(Override.class);
207226
}
208227

209-
for (Map.Entry<String, AbstractJClass> typeDeclaration : methodTypes.entrySet()) {
210-
method.generify(typeDeclaration.getKey(), typeDeclaration.getValue());
228+
for (Map.Entry<String, List<AbstractJClass>> typeDeclaration : methodTypes.entrySet()) {
229+
List<AbstractJClass> bounds = typeDeclaration.getValue();
230+
addTypeBounds(method, bounds, typeDeclaration.getKey());
211231
}
212232

213233
int i = 0;
@@ -227,10 +247,11 @@ public JMethod overrideAnnotatedMethod(ExecutableElement executableElement, Gene
227247
return method;
228248
}
229249

230-
public void generifyStaticHelper(JMethod staticHelper, TypeElement annotatedClass) {
231-
for (TypeParameterElement param : annotatedClass.getTypeParameters()) {
232-
AbstractJClass bounds = typeBoundsToJClass(param.getBounds());
233-
staticHelper.generify(param.getSimpleName().toString(), bounds);
250+
public void generify(IJGenerifiable generifiable, TypeElement fromTypeParameters) {
251+
for (TypeParameterElement param : fromTypeParameters.getTypeParameters()) {
252+
List<AbstractJClass> bounds = typeBoundsToJClass(param.getBounds());
253+
254+
addTypeBounds(generifiable, bounds, param.getSimpleName().toString());
234255
}
235256
}
236257

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/BaseGeneratedClassHolder.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import javax.annotation.processing.ProcessingEnvironment;
2929
import javax.lang.model.element.Element;
3030
import javax.lang.model.element.TypeElement;
31-
import javax.lang.model.element.TypeParameterElement;
3231

3332
import org.androidannotations.AndroidAnnotationsEnvironment;
3433
import org.androidannotations.helper.APTCodeModelHelper;
@@ -70,10 +69,7 @@ protected void setGeneratedClass() throws Exception {
7069
String generatedClassQualifiedName = annotatedComponentQualifiedName + classSuffix();
7170
generatedClass = getCodeModel()._class(PUBLIC | FINAL, generatedClassQualifiedName, EClassType.CLASS);
7271
}
73-
for (TypeParameterElement typeParam : annotatedElement.getTypeParameters()) {
74-
AbstractJClass bound = codeModelHelper.typeBoundsToJClass(typeParam.getBounds());
75-
generatedClass.generify(typeParam.getSimpleName().toString(), bound);
76-
}
72+
codeModelHelper.generify(generatedClass, annotatedElement);
7773
setExtends();
7874
codeModelHelper.copyNonAAAnnotations(generatedClass, annotatedElement.getAnnotationMirrors());
7975
}

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EBeanHolder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public void createFactoryMethod(boolean hasSingletonScope) {
8888

8989
JMethod factoryMethod = generatedClass.method(PUBLIC | STATIC, narrowedGeneratedClass, GET_INSTANCE_METHOD_NAME);
9090

91-
codeModelHelper.generifyStaticHelper(factoryMethod, annotatedElement);
91+
codeModelHelper.generify(factoryMethod, annotatedElement);
9292

9393
JVar factoryMethodContextParam = factoryMethod.param(getClasses().CONTEXT, "context");
9494

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EFragmentHolder.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.androidannotations.holder.ReceiverRegistrationDelegate.IntentFilterData;
3434

3535
import com.helger.jcodemodel.AbstractJClass;
36-
import com.helger.jcodemodel.IJGenerifiable;
3736
import com.helger.jcodemodel.JBlock;
3837
import com.helger.jcodemodel.JClassAlreadyExistsException;
3938
import com.helger.jcodemodel.JDefinedClass;
@@ -42,7 +41,6 @@
4241
import com.helger.jcodemodel.JFieldVar;
4342
import com.helger.jcodemodel.JMethod;
4443
import com.helger.jcodemodel.JMod;
45-
import com.helger.jcodemodel.JTypeVar;
4644
import com.helger.jcodemodel.JVar;
4745

4846
public class EFragmentHolder extends EComponentWithViewSupportHolder implements HasInstanceState, HasOptionsMenu, HasOnActivityResult, HasReceiverRegistration, HasPreferences {
@@ -133,7 +131,7 @@ private void setFragmentBuilder() throws JClassAlreadyExistsException {
133131

134132
narrowBuilderClass = narrow(fragmentBuilderClass);
135133

136-
generify(fragmentBuilderClass);
134+
codeModelHelper.generify(fragmentBuilderClass, annotatedElement);
137135
AbstractJClass superClass = getJClass(org.androidannotations.api.builder.FragmentBuilder.class);
138136
superClass = superClass.narrow(narrowBuilderClass, getAnnotatedClass());
139137
fragmentBuilderClass._extends(superClass);
@@ -155,16 +153,10 @@ private void setFragmentBuilderBuild() {
155153

156154
private void setFragmentBuilderCreate() {
157155
JMethod method = generatedClass.method(STATIC | PUBLIC, narrowBuilderClass, "builder");
158-
generify(method);
156+
codeModelHelper.generify(method, annotatedElement);
159157
method.body()._return(_new(narrowBuilderClass));
160158
}
161159

162-
private void generify(IJGenerifiable generifiable) {
163-
for (JTypeVar type : generatedClass.typeParams()) {
164-
generifiable.generify(type.name(), type._extends());
165-
}
166-
}
167-
168160
private void setOnCreateOptionsMenu() {
169161
JMethod method = generatedClass.method(PUBLIC, getCodeModel().VOID, "onCreateOptionsMenu");
170162
method.annotate(Override.class);

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EViewHolder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private void createConstructorAndBuilder() {
8282
JMethod copyConstructor = generatedClass.constructor(PUBLIC);
8383
JMethod staticHelper = generatedClass.method(PUBLIC | STATIC, generatedClass._extends(), "build");
8484

85-
codeModelHelper.generifyStaticHelper(staticHelper, getAnnotatedElement());
85+
codeModelHelper.generify(staticHelper, getAnnotatedElement());
8686

8787
JBlock body = copyConstructor.body();
8888
JInvocation superCall = body.invoke("super");

AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/ebean/SomeGenericBean.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.androidannotations.ebean;
1717

18+
import java.io.Serializable;
1819
import java.util.List;
1920

2021
import org.androidannotations.annotations.Background;
@@ -39,4 +40,9 @@ <N extends T> void someParameterizedMethod(List<? super N> lst, List<? extends N
3940
<U, S extends Number> void emptyUiMethod(List<? extends T> param, List<? super S> param2) {
4041
}
4142

43+
@UiThread
44+
<U, S extends Number & Serializable> void multipleBounds() {
45+
46+
}
47+
4248
}

0 commit comments

Comments
 (0)