diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/BundleHelper.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/BundleHelper.java index 644922775f..1402aa71dd 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/BundleHelper.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/BundleHelper.java @@ -23,11 +23,11 @@ import java.util.List; import java.util.Map; -import javax.lang.model.element.TypeElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; import org.androidannotations.holder.GeneratedClassHolder; @@ -86,12 +86,14 @@ public class BundleHelper { private String methodNameToSave; private String methodNameToRestore; + private TypeMirror upperBound; + public BundleHelper(AnnotationHelper helper, TypeMirror element) { annotationHelper = helper; this.element = element; String typeString = element.toString(); - TypeElement elementType = annotationHelper.typeElementFromQualifiedName(typeString); + TypeMirror type = element; if (METHOD_SUFFIX_BY_TYPE_NAME.containsKey(typeString)) { @@ -105,15 +107,18 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) { boolean hasTypeArguments = false; if (arrayType.getComponentType() instanceof DeclaredType) { DeclaredType declaredType = (DeclaredType) arrayType.getComponentType(); - typeString = declaredType.asElement().toString(); + type = declaredType; hasTypeArguments = declaredType.getTypeArguments().size() > 0; + } else if (arrayType.getComponentType().getKind() == TypeKind.TYPEVAR) { + type = arrayType.getComponentType(); + upperBound = getUpperBound(type); + restoreCallNeedCastStatement = true; + restoreCallNeedsSuppressWarning = true; } else { - typeString = arrayType.getComponentType().toString(); + type = arrayType.getComponentType(); } - elementType = annotationHelper.typeElementFromQualifiedName(typeString); - - if (isTypeParcelable(elementType)) { + if (isTypeParcelable(type)) { methodNameToSave = "put" + "ParcelableArray"; methodNameToRestore = "get" + "ParcelableArray"; @@ -135,11 +140,10 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) { TypeMirror typeArgument = typeArguments.get(0); if (typeArgument instanceof DeclaredType) { declaredType = (DeclaredType) typeArgument; - typeString = declaredType.asElement().toString(); - elementType = annotationHelper.typeElementFromQualifiedName(typeString); + type = declaredType; hasTypeArguments = declaredType.getTypeArguments().size() > 0; } - if (isTypeParcelable(elementType)) { + if (isTypeParcelable(type)) { methodNameToSave = "put" + "ParcelableArrayList"; methodNameToRestore = "get" + "ParcelableArrayList"; @@ -159,15 +163,10 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) { } else { - boolean hasTypeArguments = false; - if (element instanceof DeclaredType) { - DeclaredType declaredType = (DeclaredType) element; - typeString = declaredType.asElement().toString(); - elementType = annotationHelper.typeElementFromQualifiedName(typeString); - hasTypeArguments = declaredType.getTypeArguments().size() > 0; - } + boolean hasTypeArguments = element.getKind() == TypeKind.DECLARED && hasTypeArguments(element) || // + element.getKind() == TypeKind.TYPEVAR && hasTypeArguments(getUpperBound(element)); - if (isTypeParcelable(elementType)) { + if (isTypeParcelable(type)) { methodNameToSave = "put" + "Parcelable"; methodNameToRestore = "get" + "Parcelable"; } else { @@ -186,9 +185,19 @@ public String getMethodNameToSave() { return methodNameToSave; } - private boolean isTypeParcelable(TypeElement elementType) { - TypeElement parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE); - return elementType != null && annotationHelper.isSubtype(elementType, parcelableType); + private boolean isTypeParcelable(TypeMirror typeMirror) { + TypeMirror parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE).asType(); + return annotationHelper.isSubtype(typeMirror, parcelableType); + } + + private TypeMirror getUpperBound(TypeMirror type) { + TypeVariable typeVariable = (TypeVariable) type; + return typeVariable.getUpperBound(); + } + + private boolean hasTypeArguments(TypeMirror type) { + DeclaredType declaredType = (DeclaredType) type; + return declaredType.getTypeArguments().size() > 0; } public JExpression getExpressionToRestoreFromIntentOrBundle(JClass variableClass, JExpression intent, JExpression extras, JExpression extraKey, JMethod method, GeneratedClassHolder holder) { @@ -202,7 +211,12 @@ public JExpression getExpressionToRestoreFromIntentOrBundle(JClass variableClass public JExpression getExpressionToRestoreFromBundle(JClass variableClass, JExpression bundle, JExpression extraKey, JMethod method, GeneratedClassHolder holder) { JExpression expressionToRestore; if (methodNameToRestore.equals("getParcelableArray")) { - JClass erasure = variableClass.elementType().erasure().array(); + JClass erasure; + if (upperBound != null) { + erasure = codeModelHelper.typeMirrorToJClass(upperBound, holder).erasure().array(); + } else { + erasure = variableClass.elementType().erasure().array(); + } expressionToRestore = holder.refClass(org.androidannotations.api.bundle.BundleHelper.class).staticInvoke("getParcelableArray").arg(bundle).arg(extraKey).arg(erasure.dotclass()); } else { expressionToRestore = JExpr.invoke(bundle, methodNameToRestore).arg(extraKey); diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/ValidatorHelper.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/ValidatorHelper.java index 0a5bbc18be..f5a79c3ac5 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/ValidatorHelper.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/ValidatorHelper.java @@ -1034,47 +1034,20 @@ public void hasValidLogLevel(Element element, IsValid isValid) { } public void canBePutInABundle(Element element, IsValid isValid) { + TypeMirror typeMirror = element.asType(); String typeString = element.asType().toString(); if (!isKnownBundleCompatibleType(typeString)) { - if (element.asType() instanceof DeclaredType) { - - DeclaredType declaredType = (DeclaredType) element.asType(); - typeString = declaredType.asElement().toString(); - - } else if (element.asType() instanceof ArrayType) { + if (typeMirror instanceof ArrayType) { ArrayType arrayType = (ArrayType) element.asType(); - TypeMirror componentType = arrayType.getComponentType(); - - if (componentType instanceof DeclaredType) { - - DeclaredType declaredType = (DeclaredType) componentType; - typeString = declaredType.asElement().toString(); - - } else { - typeString = componentType.toString(); - } - - } else { - typeString = element.asType().toString(); - } - - TypeElement elementType = annotationHelper.typeElementFromQualifiedName(typeString); - - if (elementType == null) { - elementType = getArrayEnclosingType(typeString); - - if (elementType == null) { - annotationHelper.printAnnotationError(element, "Unrecognized type. Please let your attribute be primitive or implement Serializable or Parcelable"); - isValid.invalidate(); - } + typeMirror = arrayType.getComponentType(); } - if (elementType != null) { - TypeElement parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE); - TypeElement serializableType = annotationHelper.typeElementFromQualifiedName("java.io.Serializable"); - if (!annotationHelper.isSubtype(elementType, parcelableType) && !annotationHelper.isSubtype(elementType, serializableType)) { + if (typeMirror.getKind() != TypeKind.NONE) { + TypeMirror parcelableType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE).asType(); + TypeMirror serializableType = annotationHelper.typeElementFromQualifiedName("java.io.Serializable").asType(); + if (!annotationHelper.isSubtype(typeMirror, parcelableType) && !annotationHelper.isSubtype(typeMirror, serializableType)) { annotationHelper.printAnnotationError(element, "Unrecognized type. Please let your attribute be primitive or implement Serializable or Parcelable"); isValid.invalidate(); } diff --git a/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/GenericFragmentArguments.java b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/GenericFragmentArguments.java new file mode 100644 index 0000000000..df355cd67e --- /dev/null +++ b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/GenericFragmentArguments.java @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2010-2015 eBusiness Information, Excilys Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed To in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.androidannotations.test15; + +import java.io.Serializable; + +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.FragmentArg; + +import android.accounts.Account; +import android.app.Fragment; + +@EFragment +public class GenericFragmentArguments extends Fragment { + + @FragmentArg + S[] serializableArray; + + @FragmentArg + P[] parcelableArray; + + @FragmentArg + S serializable; + + @FragmentArg + P parcelable; + +} \ No newline at end of file diff --git a/AndroidAnnotations/functional-test-1-5/src/test/java/org/androidannotations/test15/GenericFragmentArgsTest.java b/AndroidAnnotations/functional-test-1-5/src/test/java/org/androidannotations/test15/GenericFragmentArgsTest.java new file mode 100644 index 0000000000..ae2d4cd3cf --- /dev/null +++ b/AndroidAnnotations/functional-test-1-5/src/test/java/org/androidannotations/test15/GenericFragmentArgsTest.java @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2010-2015 eBusiness Information, Excilys Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed To in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.androidannotations.test15; + +import static org.fest.assertions.api.Assertions.assertThat; + +import java.io.Serializable; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import android.accounts.Account; +import android.os.Bundle; + +@Config(shadows = CustomShadowBundle.class) +@RunWith(RobolectricTestRunner.class) +public class GenericFragmentArgsTest { + + private static final Account[] TEST_ARRAY = new Account[] { new Account("Android", "Annotations") }; + + @Test + public void testParcelableArrayFragmentArgInjected() { + Bundle bundle = new Bundle(); + bundle.putParcelableArray("parcelableArray", TEST_ARRAY); + + GenericFragmentArguments fragment = new GenericFragmentArguments_(); + fragment.setArguments(bundle); + + assertThat(fragment.parcelableArray).isNull(); + + fragment.onCreate(null); + + assertThat(fragment.parcelableArray).isEqualTo(TEST_ARRAY); + } +}