Skip to content

Commit 72d344d

Browse files
committed
Merge pull request androidannotations#1445 from WonderCsabo/1444_genericFragmentArg
Support @FragmentArg on fields with type variable type
2 parents 26b22a5 + a233925 commit 72d344d

4 files changed

Lines changed: 134 additions & 56 deletions

File tree

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

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
import java.util.List;
2424
import java.util.Map;
2525

26-
import javax.lang.model.element.TypeElement;
2726
import javax.lang.model.type.ArrayType;
2827
import javax.lang.model.type.DeclaredType;
2928
import javax.lang.model.type.TypeKind;
3029
import javax.lang.model.type.TypeMirror;
30+
import javax.lang.model.type.TypeVariable;
3131

3232
import org.androidannotations.holder.GeneratedClassHolder;
3333

@@ -86,12 +86,14 @@ public class BundleHelper {
8686
private String methodNameToSave;
8787
private String methodNameToRestore;
8888

89+
private TypeMirror upperBound;
90+
8991
public BundleHelper(AnnotationHelper helper, TypeMirror element) {
9092
annotationHelper = helper;
9193
this.element = element;
9294

9395
String typeString = element.toString();
94-
TypeElement elementType = annotationHelper.typeElementFromQualifiedName(typeString);
96+
TypeMirror type = element;
9597

9698
if (METHOD_SUFFIX_BY_TYPE_NAME.containsKey(typeString)) {
9799

@@ -105,15 +107,18 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) {
105107
boolean hasTypeArguments = false;
106108
if (arrayType.getComponentType() instanceof DeclaredType) {
107109
DeclaredType declaredType = (DeclaredType) arrayType.getComponentType();
108-
typeString = declaredType.asElement().toString();
110+
type = declaredType;
109111
hasTypeArguments = declaredType.getTypeArguments().size() > 0;
112+
} else if (arrayType.getComponentType().getKind() == TypeKind.TYPEVAR) {
113+
type = arrayType.getComponentType();
114+
upperBound = getUpperBound(type);
115+
restoreCallNeedCastStatement = true;
116+
restoreCallNeedsSuppressWarning = true;
110117
} else {
111-
typeString = arrayType.getComponentType().toString();
118+
type = arrayType.getComponentType();
112119
}
113120

114-
elementType = annotationHelper.typeElementFromQualifiedName(typeString);
115-
116-
if (isTypeParcelable(elementType)) {
121+
if (isTypeParcelable(type)) {
117122
methodNameToSave = "put" + "ParcelableArray";
118123
methodNameToRestore = "get" + "ParcelableArray";
119124

@@ -135,11 +140,10 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) {
135140
TypeMirror typeArgument = typeArguments.get(0);
136141
if (typeArgument instanceof DeclaredType) {
137142
declaredType = (DeclaredType) typeArgument;
138-
typeString = declaredType.asElement().toString();
139-
elementType = annotationHelper.typeElementFromQualifiedName(typeString);
143+
type = declaredType;
140144
hasTypeArguments = declaredType.getTypeArguments().size() > 0;
141145
}
142-
if (isTypeParcelable(elementType)) {
146+
if (isTypeParcelable(type)) {
143147
methodNameToSave = "put" + "ParcelableArrayList";
144148
methodNameToRestore = "get" + "ParcelableArrayList";
145149

@@ -159,15 +163,10 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) {
159163

160164
} else {
161165

162-
boolean hasTypeArguments = false;
163-
if (element instanceof DeclaredType) {
164-
DeclaredType declaredType = (DeclaredType) element;
165-
typeString = declaredType.asElement().toString();
166-
elementType = annotationHelper.typeElementFromQualifiedName(typeString);
167-
hasTypeArguments = declaredType.getTypeArguments().size() > 0;
168-
}
166+
boolean hasTypeArguments = element.getKind() == TypeKind.DECLARED && hasTypeArguments(element) || //
167+
element.getKind() == TypeKind.TYPEVAR && hasTypeArguments(getUpperBound(element));
169168

170-
if (isTypeParcelable(elementType)) {
169+
if (isTypeParcelable(type)) {
171170
methodNameToSave = "put" + "Parcelable";
172171
methodNameToRestore = "get" + "Parcelable";
173172
} else {
@@ -186,9 +185,19 @@ public String getMethodNameToSave() {
186185
return methodNameToSave;
187186
}
188187

189-
private boolean isTypeParcelable(TypeElement elementType) {
190-
TypeElement parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE);
191-
return elementType != null && annotationHelper.isSubtype(elementType, parcelableType);
188+
private boolean isTypeParcelable(TypeMirror typeMirror) {
189+
TypeMirror parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE).asType();
190+
return annotationHelper.isSubtype(typeMirror, parcelableType);
191+
}
192+
193+
private TypeMirror getUpperBound(TypeMirror type) {
194+
TypeVariable typeVariable = (TypeVariable) type;
195+
return typeVariable.getUpperBound();
196+
}
197+
198+
private boolean hasTypeArguments(TypeMirror type) {
199+
DeclaredType declaredType = (DeclaredType) type;
200+
return declaredType.getTypeArguments().size() > 0;
192201
}
193202

194203
public JExpression getExpressionToRestoreFromIntentOrBundle(JClass variableClass, JExpression intent, JExpression extras, JExpression extraKey, JMethod method, GeneratedClassHolder holder) {
@@ -202,7 +211,12 @@ public JExpression getExpressionToRestoreFromIntentOrBundle(JClass variableClass
202211
public JExpression getExpressionToRestoreFromBundle(JClass variableClass, JExpression bundle, JExpression extraKey, JMethod method, GeneratedClassHolder holder) {
203212
JExpression expressionToRestore;
204213
if (methodNameToRestore.equals("getParcelableArray")) {
205-
JClass erasure = variableClass.elementType().erasure().array();
214+
JClass erasure;
215+
if (upperBound != null) {
216+
erasure = codeModelHelper.typeMirrorToJClass(upperBound, holder).erasure().array();
217+
} else {
218+
erasure = variableClass.elementType().erasure().array();
219+
}
206220
expressionToRestore = holder.refClass(org.androidannotations.api.bundle.BundleHelper.class).staticInvoke("getParcelableArray").arg(bundle).arg(extraKey).arg(erasure.dotclass());
207221
} else {
208222
expressionToRestore = JExpr.invoke(bundle, methodNameToRestore).arg(extraKey);

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

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,47 +1040,20 @@ public void hasValidLogLevel(Element element, IsValid isValid) {
10401040
}
10411041

10421042
public void canBePutInABundle(Element element, IsValid isValid) {
1043+
TypeMirror typeMirror = element.asType();
10431044
String typeString = element.asType().toString();
10441045

10451046
if (!isKnownBundleCompatibleType(typeString)) {
10461047

1047-
if (element.asType() instanceof DeclaredType) {
1048-
1049-
DeclaredType declaredType = (DeclaredType) element.asType();
1050-
typeString = declaredType.asElement().toString();
1051-
1052-
} else if (element.asType() instanceof ArrayType) {
1048+
if (typeMirror instanceof ArrayType) {
10531049
ArrayType arrayType = (ArrayType) element.asType();
1054-
TypeMirror componentType = arrayType.getComponentType();
1055-
1056-
if (componentType instanceof DeclaredType) {
1057-
1058-
DeclaredType declaredType = (DeclaredType) componentType;
1059-
typeString = declaredType.asElement().toString();
1060-
1061-
} else {
1062-
typeString = componentType.toString();
1063-
}
1064-
1065-
} else {
1066-
typeString = element.asType().toString();
1067-
}
1068-
1069-
TypeElement elementType = annotationHelper.typeElementFromQualifiedName(typeString);
1070-
1071-
if (elementType == null) {
1072-
elementType = getArrayEnclosingType(typeString);
1073-
1074-
if (elementType == null) {
1075-
annotationHelper.printAnnotationError(element, "Unrecognized type. Please let your attribute be primitive or implement Serializable or Parcelable");
1076-
isValid.invalidate();
1077-
}
1050+
typeMirror = arrayType.getComponentType();
10781051
}
10791052

1080-
if (elementType != null) {
1081-
TypeElement parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE);
1082-
TypeElement serializableType = annotationHelper.typeElementFromQualifiedName("java.io.Serializable");
1083-
if (!annotationHelper.isSubtype(elementType, parcelableType) && !annotationHelper.isSubtype(elementType, serializableType)) {
1053+
if (typeMirror.getKind() != TypeKind.NONE) {
1054+
TypeMirror parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE).asType();
1055+
TypeMirror serializableType = annotationHelper.typeElementFromQualifiedName("java.io.Serializable").asType();
1056+
if (!annotationHelper.isSubtype(typeMirror, parcelableType) && !annotationHelper.isSubtype(typeMirror, serializableType)) {
10841057
annotationHelper.printAnnotationError(element, "Unrecognized type. Please let your attribute be primitive or implement Serializable or Parcelable");
10851058
isValid.invalidate();
10861059
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (C) 2010-2015 eBusiness Information, Excilys Group
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.test15;
17+
18+
import java.io.Serializable;
19+
20+
import org.androidannotations.annotations.EFragment;
21+
import org.androidannotations.annotations.FragmentArg;
22+
23+
import android.accounts.Account;
24+
import android.app.Fragment;
25+
26+
@EFragment
27+
public class GenericFragmentArguments<S extends Serializable, P extends Account> extends Fragment {
28+
29+
@FragmentArg
30+
S[] serializableArray;
31+
32+
@FragmentArg
33+
P[] parcelableArray;
34+
35+
@FragmentArg
36+
S serializable;
37+
38+
@FragmentArg
39+
P parcelable;
40+
41+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright (C) 2010-2015 eBusiness Information, Excilys Group
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.test15;
17+
18+
import static org.fest.assertions.api.Assertions.assertThat;
19+
20+
import java.io.Serializable;
21+
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.robolectric.RobolectricTestRunner;
25+
import org.robolectric.annotation.Config;
26+
27+
import android.accounts.Account;
28+
import android.os.Bundle;
29+
30+
@Config(shadows = CustomShadowBundle.class)
31+
@RunWith(RobolectricTestRunner.class)
32+
public class GenericFragmentArgsTest {
33+
34+
private static final Account[] TEST_ARRAY = new Account[] { new Account("Android", "Annotations") };
35+
36+
@Test
37+
public void testParcelableArrayFragmentArgInjected() {
38+
Bundle bundle = new Bundle();
39+
bundle.putParcelableArray("parcelableArray", TEST_ARRAY);
40+
41+
GenericFragmentArguments<Serializable, Account> fragment = new GenericFragmentArguments_<Serializable, Account>();
42+
fragment.setArguments(bundle);
43+
44+
assertThat(fragment.parcelableArray).isNull();
45+
46+
fragment.onCreate(null);
47+
48+
assertThat(fragment.parcelableArray).isEqualTo(TEST_ARRAY);
49+
}
50+
}

0 commit comments

Comments
 (0)