Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

ClassCastException when using @Extra with Parcelable[] objects #1208

Closed

Description

@ened

Given I have a model class RemoteMediaFile, which is roughly defined like this:

public class RemoteMediaFile implements Parcelable {
    private String mId;
    private String mParentId;
    public RemoteMediaFile() {
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.mId);
        dest.writeString(this.mParentId);
    }

    private RemoteMediaFile(Parcel in) {
        this.mId = in.readString();
        this.mParentId = in.readString();
    }

    public static final Creator<RemoteMediaFile> CREATOR = new Creator<RemoteMediaFile>() {
        public RemoteMediaFile createFromParcel(Parcel source) {
            return new RemoteMediaFile(source);
        }

        public RemoteMediaFile[] newArray(int size) {
            return new RemoteMediaFile[size];
        }
    };
}

Then I'd like to use @Extra in my Activity, which should read the array from an Intent:

@EActivity
public class RemotePhotoDetailActivity extends BaseActivity implements RemotePlayer{
    @Extra
    protected RemoteMediaFile[] remoteFiles;
}

However, this creates a ClassCastException:

Caused by: java.lang.ClassCastException: android.os.Parcelable[] cannot be cast to com.myapp.media.RemoteMediaFile[]
       at com.myapp.photos.RemotePhotoDetailActivity_.injectExtras_(RemotePhotoDetailActivity_.java:168)
       at com.myapp.photos.RemotePhotoDetailActivity_.init_(RemotePhotoDetailActivity_.java:109)
       at com.myapp.photos.RemotePhotoDetailActivity_.onCreate(RemotePhotoDetailActivity_.java:103)
       at android.app.Activity.performCreate(Activity.java:5231)
       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
       at android.app.ActivityThread.access$800(ActivityThread.java:135)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:5001)
       at java.lang.reflect.Method.invokeNative(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
       at dalvik.system.NativeStart.main(Native Method)

The generated code looks like this:

    private void injectExtras_() {
        Bundle extras_ = getIntent().getExtras();
        if (extras_!= null) {
            if (extras_.containsKey(REMOTE_FILES_EXTRA)) {
                remoteFiles = ((RemoteMediaFile[]) extras_.getParcelableArray(REMOTE_FILES_EXTRA));
            }
        }
    }

A fix would be to read the RemoteMediaFile[] object from the intent like this:

    private void injectExtras_() {
        Bundle extras_ = getIntent().getExtras();
        if (extras_!= null) {
            if (extras_.containsKey(REMOTE_FILES_EXTRA)) {
                Parcelable[] a = extras_.getParcelableArrayExtra(REMOTE_FILES_EXTRA);
                remoteFiles = Arrays.copyOf(a, a.length, RemoteMediaFile[].class);
            }
        }
    }

When I do this manually, it will work properly.

More details here: http://stackoverflow.com/a/10781119/375209

Activity

  1. changed the title [-]@Extra for Parcelable[] objects generates ClassCastException[/-] [+]ClassCastException when using @Extra with Parcelable[] objects[/+] on Nov 5, 2014
  2. WonderCsabo commented on Nov 5, 2014

    @WonderCsabo
    Member

    Can you post the code which adds the extra to the Intent?

  3. ened commented on Nov 5, 2014

    @ened
    ContributorAuthor
    final List<RemoteMediaFile> remoteMediaFiles = new ArrayList<>();
    
    // ...
    
    final RemoteMediaFile[] remoteFiles = new RemoteMediaFile[remoteMediaFiles.size()];
    remoteMediaFiles.toArray(remoteFiles);
    
    final Intent intent = new Intent();
    intent.setAction("com.myapp.photos.player.REMOTE_PLAY");
    intent.putExtra("remoteFiles", remoteFiles);
    mContext.startActivity(intent);
  4. WonderCsabo commented on Nov 5, 2014

    @WonderCsabo
    Member

    Thanks for the detailed report! You are right, this is indeed an issue. We have to add a special case for this in BundleHelper. Wanna contribute?

  5. WonderCsabo commented on Nov 5, 2014

    @WonderCsabo
    Member

    BTW we have a test for all types of extras. This defect was not discovered there because in the load test, we set the field directly with Reflection, so the type is still MyParcelableBean[] and the cast is successful. I wonder we should create another test, which uses the generated method to save the field, and the generated method to get to the field. But that would not be a unit test.

  6. ened commented on Nov 9, 2014

    @ened
    ContributorAuthor

    I think this will be a simple test extension of ExtraInjectedActivity and InjectExtraTest.

  7. WonderCsabo commented on Nov 9, 2014

    @WonderCsabo
    Member

    Yes indeed, that is the right place for this.

  8. ened commented on Nov 9, 2014

    @ened
    ContributorAuthor

    There's a class CustomData. I'm thinking to re-use that one (add a implements Parcelable). Guess that's what it was made for.

  9. WonderCsabo commented on Nov 9, 2014

    @WonderCsabo
    Member

    Please another class instead. If the class would implement both Serializable and Parcelable the Intent.putExtra method call would be ambiguous.

  10. ened commented on Nov 9, 2014

    @ened
    ContributorAuthor

    CustomParcelableData it is. :-)

  11. ened commented on Nov 14, 2014

    @ened
    ContributorAuthor

    @WonderCsabo I've started to add the tests, could you have a look at https://github.com/ened/androidannotations/compare/parcelable-array ? The weird thing is: the test passes. :-)

    I wonder if the please really is correct?

  12. WonderCsabo commented on Nov 14, 2014

    @WonderCsabo
    Member

    i just tried your test fixture. It seems Robolectric getParcelableArray returns the type you put it in the first place. But in real Android getParcelableArray return Parcelable[].

    Also please note we use Android 4.1 in Robolectric, but i tested with Android 4.4 on a real device. Maybe the behavior of getParcelableArray changed between the two versions?

  13. ened commented on Nov 14, 2014

    @ened
    ContributorAuthor

    Alright I'll test this out in the 4.1&4.4 emulator.

  14. WonderCsabo commented on Nov 14, 2014

    @WonderCsabo
    Member

    Thanks.

  15. WonderCsabo commented on Nov 21, 2014

    @WonderCsabo
    Member

    @ened did you have time for trying that out?

  16. ened commented on Nov 21, 2014

    @ened
    ContributorAuthor

    This weekend. :-)

    On Nov 21, 2014, at 22:04, Csaba Kozák notifications@github.com wrote:

    @ened did you have time for trying that out?

    —
    Reply to this email directly or view it on GitHub.

  17. ened commented on Dec 7, 2014

    @ened
    ContributorAuthor

    @WonderCsabo I've been trying to get my head around the code & think it will take a bit longer.

  18. WonderCsabo commented on Dec 22, 2014

    @WonderCsabo
    Member

    @ened any news on this?

  19. WonderCsabo commented on Dec 27, 2014

    @WonderCsabo
    Member

    I wrote this in November:

    This defect was not discovered there because in the load test, we set the field directly with Reflection

    I just reviewed the test and this is not true, i looked at it too quickly. We indeed save into a Bundle and load from that, so another test is not necessary. The test passed though, because the suspected bug in Robolectric you discovered. I opened robolectric/robolectric#1440 for that.

  20. ened commented on Dec 28, 2014

    @ened
    ContributorAuthor

    Thanks for taking the time to look into this.
    I've been trying to dig into this for quite a bit - anyone who is faster is welcome to help out.

  21. self-assigned this
    on Dec 28, 2014
  22. GaidamakUA commented on Jan 5, 2015

    @GaidamakUA

    I've faced this issue. I'm sorry for noobie question. Should I use some workaround, or I can get fix somehow?

  23. WonderCsabo commented on Jan 5, 2015

    @WonderCsabo
    Member

    @GaidamakUA i already proposed #1294 to fix this issue. You can build AA from that branch and use it. Or if you want to stick to the stable version, declare Parcelable[] as your @Extra object's type, then copy it to a specific array type manually, or just retrieve elements from it and cast them.

  24. GaidamakUA commented on Jan 5, 2015

    @GaidamakUA

    @WonderCsabo Thank you.

  25. nking commented on Feb 21, 2018

    @nking

    Note that Parcelable ClassCastException can occur as a mistyped exception when the
    member variables are null and are written to the out Parcel..

    One practice you could adopt in writeToParcel is to write an int flag of 0 or 1 before
    deciding to write a variable (e.g. 0 for null).
    Then in the read parcel method, you would read the flag to know whether there is a
    variable to read next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions