1

I have a Java Bean class, annotated with @Parcel(Parcel.Serialization.BEAN) and Gson's @SerializedName on some fields:

Question.java:

@Parcel(Parcel.Serialization.BEAN)
public class Question {

    private Integer id;
    private String title;
    private String description;
    private User user;

    @SerializedName("other_model_id")
    private Integer otherModelId,

    @SerializedName("created_at")
    private Date createdAt;

    // ----- Getters and setters -----
}

When I'm starting ShowQuestionActivity, I pass my Parceled question object to it (where question has all fields set):

Intent intent = new Intent(context, ShowQuestionActivity.class);
intent.putExtra("extra_question", Parcels.wrap(question));
startActivity(intent);

On ShowQuestionActivity, I get "extra_question" from my intent object:

Question question = Parcels.unwrap(intent.getParcelableExtra(Constants.EXTRA_QUESTION));

But Parceler returns me only title and description (Strings)... All other fields are null.

Wrapping the object with Parcels.wrap(question) and unwrapping it with Parcels.unwrap(question) on debugger works perfectly, but after passing it through intent, it seems to "lose" its values, but I can't find the problem...


My Parceler setup is the following:

Module build.gradle:

dependencies {
    compile 'org.parceler:parceler-api:1.1.4'
    apt 'org.parceler:parceler:1.1.4'
}

And in my project's build.gradle:

dependencies {
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
  • Your setup looks correct. Are all your getters/setters properly declared? Is User annotated with `@Parcel`, and did you add a `@ParcelPropertyConverter` for Date? – John Ericksen May 24 '16 at 04:36
  • @JohnEricksen, my getters and setters are properly declared. User is annotated with `@Parcel(Parcel.Serialization.BEAN)` with getters and setters and I haven't added `@ParcelPropertyConverter` for Date yet, as I'm not going to use this field for now. Does it stop Parceler from generating Parcel classes? – Jonathan Nobrega May 24 '16 at 23:25
  • I was trying to figure out what was going on, and when I've added`@ParcelProperty("Gson @SerializedName field")`it worked as expected, but it warned me about reflection. Do I really need to write a @ParcelProperty for every field? And what about reflection? – Jonathan Nobrega May 24 '16 at 23:25
  • You shouldn't have to.... would you mind sharing more of your Question class, perhaps over a gist? – John Ericksen May 25 '16 at 02:49
  • @JohnEricksen Well... I didn't write setters for id, otherModelId and createdAt because they came from JSON and GSON did the job (using reflection). Writing them for all fields solved the problem, as I didn't realize Parceler needed them. Sorry if I made you waste your time with such a simple problem... Should I answer my own question or you do it? – Jonathan Nobrega May 25 '16 at 13:58
  • certainly not a waste of time, and this highlights a gap in the documentation which I'll need to fill. I went ahead and answered the question. Thanks! – John Ericksen May 25 '16 at 22:21
  • 1
    Thanks for the feedback and for sharing your awesome library with developers @JohnEricksen! – Jonathan Nobrega May 27 '16 at 12:31

1 Answers1

2

With the BEAN serialization strategy, Parceler requires matching getter and setters for each property in the class that you want to be wrapped and unwrapped.

In addition properties that aren't mapped by default, like Date, require you to write a converter or map these types in with @ParcelClass. See http://parceler.org/#custom_serialization

Here's a code example:

@Parcel(Parcel.Serialization.BEAN)
public class Question {

    private Integer id;
    private String title;
    private Date createdAt;

    // id is included in the Parcelable because it has matching getter and setters
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }

    // title is not included as the setter is missing (it's not a true bean property)
    public String getTitle() { return title; }

    // createdAt will issue an error as it is not a defined type, and no converter is defined.
    public Date getCreatedAt() { return createdAt; }
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }   
}

Worth noting, if you're happy with Gson marshalling your internal class state, you may want to consider using the default FIELD serialization strategy instead of BEAN paired with non-private fields. This technique will not require any specific getter and setters combination.

John Ericksen
  • 10,995
  • 4
  • 45
  • 75
  • Wow! Thank you for noting this. I didn't know that I needed to implement the getters and setters manually. Seems like a hindsight on the library. Why couldn't the generated class handle this? – w3bshark Dec 15 '16 at 16:00
  • This is only with the BEAN sealization type. With the default FIELD type, the fields will be used directly and avoid the need for getters/setters. – John Ericksen Dec 15 '16 at 16:24
  • Yep, got that. I'm using Realm with Parceler for some of my objects and only those objects require BEAN serialization, so I only updated those. Thanks for the help. Much appreciated! – w3bshark Dec 15 '16 at 16:31