Skip to content

Commit cbfa3e6

Browse files
committed
Fix for getParcelableArray ClassCastException
1 parent e608029 commit cbfa3e6

8 files changed

Lines changed: 84 additions & 10 deletions

File tree

‎AndroidAnnotations/androidannotations-api/META-INF/MANIFEST.MF‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Export-Package: org.androidannotations.annotations,
99
org.androidannotations.annotations.sharedpreferences,
1010
org.androidannotations.api,
1111
org.androidannotations.api.builder,
12+
org.androidannotations.api.bundle,
1213
org.androidannotations.api.rest,
1314
org.androidannotations.api.roboguice,
1415
org.androidannotations.api.sharedpreferences,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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.api.bundle;
17+
18+
import java.lang.reflect.Array;
19+
20+
import android.os.Bundle;
21+
import android.os.Parcelable;
22+
23+
/**
24+
* Utility class for working with {@link Bundle} objects.
25+
*/
26+
public class BundleHelper {
27+
28+
private BundleHelper() {
29+
30+
}
31+
32+
/**
33+
* This method extracts a {@link Parcelable} array from the {@link Bundle},
34+
* and returns it in an array whose type is the exact {@link Parcelable}
35+
* subclass. This is needed because {@link Bundle#getParcelable(String)}
36+
* returns an array of {@link Parcelable}, and we would get
37+
* {@link ClassCastException} when we assign it to {@link Parcelable}
38+
* subclass arrays.
39+
*
40+
* For more info, see <a
41+
* href="https://github.com/excilys/androidannotations/issues/1208">this</a>
42+
* url.
43+
*
44+
* @param bundle
45+
* the bundle holding the array which is extracted
46+
* @param key
47+
* the array is associated with this key
48+
* @param type
49+
* the desired type of the returned array
50+
* @return a {@link Parcelable} subclass typed array which holds the objects
51+
* from {@link Bundle#getParcelableArray(String)} or
52+
* <code>null</code> if {@link Bundle#getParcelableArray(String)}
53+
* returned <code>null</code> for the key
54+
*/
55+
@SuppressWarnings("unchecked")
56+
public static <T extends Parcelable> T[] getParcelableArray(Bundle bundle, String key, Class<T[]> type) {
57+
Parcelable[] value = bundle.getParcelableArray(key);
58+
if (value == null) {
59+
return null;
60+
}
61+
Object copy = Array.newInstance(type.getComponentType(), value.length);
62+
System.arraycopy(value, 0, copy, 0, value.length);
63+
return (T[]) copy;
64+
}
65+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private void injectExtraInComponent(Element element, HasExtras hasExtras, JField
105105
JExpression intent = invoke("getIntent");
106106
JBlock ifContainsKey = injectExtrasBlock._if(JExpr.invoke(extras, "containsKey").arg(extraKeyStaticField))._then();
107107

108-
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromIntentOrBundle(elementClass, intent, extras, extraKeyStaticField, injectExtrasMethod);
108+
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromIntentOrBundle(elementClass, intent, extras, extraKeyStaticField, injectExtrasMethod, hasExtras);
109109
ifContainsKey.assign(extraField, restoreMethodCall);
110110
}
111111

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public JExpression getExtraValue(VariableElement parameter, JVar intent, JVar ex
8080
}
8181

8282
BundleHelper bundleHelper = new BundleHelper(annotationHelper, parameter.asType());
83-
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromIntentOrBundle(parameterClass, intent, extras, getStaticExtraField(generatedClass, extraKey, holder), annotatedMethod);
83+
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromIntentOrBundle(parameterClass, intent, extras, getStaticExtraField(generatedClass, extraKey, holder), annotatedMethod, holder);
8484

8585
return block.decl(parameterClass, parameterName, restoreMethodCall);
8686
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ private void injectArgInComponent(Element element, EFragmentHolder holder, Bundl
9999
JFieldRef extraField = JExpr.ref(fieldName);
100100

101101
JBlock ifContainsKey = injectExtrasBlock._if(JExpr.invoke(bundle, "containsKey").arg(extraKeyStaticField))._then();
102-
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromBundle(elementClass, bundle, extraKeyStaticField, injectExtrasMethod);
102+
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromBundle(elementClass, bundle, extraKeyStaticField, injectExtrasMethod, holder);
103103
ifContainsKey.assign(extraField, restoreMethodCall);
104104
}
105105

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void process(Element element, HasInstanceState holder) {
7474
JFieldRef ref = ref(fieldName);
7575
saveStateBody.invoke(saveStateBundleParam, bundleHelper.getMethodNameToSave()).arg(fieldName).arg(ref);
7676

77-
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromBundle(elementClass, restoreStateBundleParam, JExpr.lit(fieldName), restoreStateMethod);
77+
JExpression restoreMethodCall = bundleHelper.getExpressionToRestoreFromBundle(elementClass, restoreStateBundleParam, JExpr.lit(fieldName), restoreStateMethod, holder);
7878
restoreStateBody.assign(ref, restoreMethodCall);
7979
}
8080
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private void addActionInOnHandleIntent(EIntentServiceHolder holder, ExecutableEl
114114
JClass extraParamClass = codeModelHelper.typeMirrorToJClass(param.asType(), holder);
115115

116116
BundleHelper bundleHelper = new BundleHelper(annotationHelper, param.asType());
117-
JExpression getExtraExpression = bundleHelper.getExpressionToRestoreFromIntentOrBundle(extraParamClass, intent, extras, paramVar, onHandleIntentMethod);
117+
JExpression getExtraExpression = bundleHelper.getExpressionToRestoreFromIntentOrBundle(extraParamClass, intent, extras, paramVar, onHandleIntentMethod, holder);
118118

119119
JVar extraField = callActionBlock.decl(extraParamClass, extraParamName, getExtraExpression);
120120
callActionInvocation.arg(extraField);

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import javax.lang.model.type.TypeKind;
3030
import javax.lang.model.type.TypeMirror;
3131

32+
import org.androidannotations.holder.GeneratedClassHolder;
33+
3234
import com.sun.codemodel.JClass;
3335
import com.sun.codemodel.JExpr;
3436
import com.sun.codemodel.JExpression;
@@ -114,7 +116,6 @@ public BundleHelper(AnnotationHelper helper, TypeMirror element) {
114116
if (isTypeParcelable(elementType)) {
115117
methodNameToSave = "put" + "ParcelableArray";
116118
methodNameToRestore = "get" + "ParcelableArray";
117-
restoreCallNeedCastStatement = true;
118119

119120
if (hasTypeArguments) {
120121
restoreCallNeedsSuppressWarning = true;
@@ -207,16 +208,23 @@ private boolean isTypeParcelable(TypeElement elementType) {
207208
return elementType != null && annotationHelper.isSubtype(elementType, parcelableType);
208209
}
209210

210-
public JExpression getExpressionToRestoreFromIntentOrBundle(JClass variableClass, JExpression intent, JExpression extras, JExpression extraKey, JMethod method) {
211+
public JExpression getExpressionToRestoreFromIntentOrBundle(JClass variableClass, JExpression intent, JExpression extras, JExpression extraKey, JMethod method, GeneratedClassHolder holder) {
211212
if ("byte[]".equals(element.toString())) {
212213
return intent.invoke("getByteArrayExtra").arg(extraKey);
213214
} else {
214-
return getExpressionToRestoreFromBundle(variableClass, extras, extraKey, method);
215+
return getExpressionToRestoreFromBundle(variableClass, extras, extraKey, method, holder);
215216
}
216217
}
217218

218-
public JExpression getExpressionToRestoreFromBundle(JClass variableClass, JExpression bundle, JExpression extraKey, JMethod method) {
219-
JExpression expressionToRestore = JExpr.invoke(bundle, methodNameToRestore).arg(extraKey);
219+
public JExpression getExpressionToRestoreFromBundle(JClass variableClass, JExpression bundle, JExpression extraKey, JMethod method, GeneratedClassHolder holder) {
220+
JExpression expressionToRestore;
221+
if (methodNameToRestore.equals("getParcelableArray")) {
222+
JClass erasure = variableClass.elementType().erasure().array();
223+
expressionToRestore = holder.refClass(org.androidannotations.api.bundle.BundleHelper.class).staticInvoke("getParcelableArray").arg(bundle).arg(extraKey).arg(erasure.dotclass());
224+
} else {
225+
expressionToRestore = JExpr.invoke(bundle, methodNameToRestore).arg(extraKey);
226+
}
227+
220228
if (restoreCallNeedCastStatement()) {
221229
expressionToRestore = JExpr.cast(variableClass, expressionToRestore);
222230

0 commit comments

Comments
 (0)