Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JsonSubTypes, list of polymorpic objects and Parcelable

My JSON structure:

{  
     ...
     "type":"post", // Type could vary
     "items":[]     // Array of items, each item is typeOf("type") 
     ...
}  

How can i deserialize and properly parcel items list inside my POJO:

public class ItemsEnvelope {
    private String type;

    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "type",
            visible = true)
    @JsonSubTypes({
            @JsonSubTypes.Type(value = A.class, name = "A"),
            @JsonSubTypes.Type(value = B.class, name = "B"),
            @JsonSubTypes.Type(value = C.class, name = "C")
    })
    private List<Item> items;

    interface Item extends Parcelable {}

    class A implements Item {
        // Bunch of getters/setters and Parcelable methods/constructor
    }

    class B implements Item {
        // Bunch of getters/setters and Parcelable methods/constructor
    }

    class C implements Item {
        // Bunch of getters/setters and Parcelable methods/constructor
    }

    // Bunch of getters/setters and Parcelable methods/constructor
}

To parcel typed list a CREATOR object should be provided, which an interface, obviously, can't have. Should i use an abstract class instead of interface?

like image 315
localhost Avatar asked Jul 26 '15 14:07

localhost


2 Answers

First things first: EXTERNAL_PROPERTY will only work when value is enclosed within another Object (POJO); and will not work for Lists, arrays or Maps.

If you were using one of other inclusion method, things should work in that you can serialize content as JSON, and read produced JSON back retaining types as expected. That is, round-trip serialization is supported when starting with Java objects. Beyond this, some JSON encoding structures can be supported; but it depends on exact kind of structure you are trying to support.

like image 108
StaxMan Avatar answered Oct 13 '22 13:10

StaxMan


Well, since Jackson expects type information on each list element and i didn't want to write a custom deserializer fot this POJO - i solved it another way.

First of all i did an interface which all my subtype items had to implement.

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
        property = "type",
        visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = PostFeedItem.class, name = BaseFeedItem.TYPE_POST),
        @JsonSubTypes.Type(value = PhotoFeedItem.class, name = BaseFeedItem.TYPE_PHOTO),
        @JsonSubTypes.Type(value = AudioFeedItem.class, name = BaseFeedItem.TYPE_AUDIO),
        @JsonSubTypes.Type(value = VideoFeedItem.class, name = BaseFeedItem.TYPE_VIDEO),
        @JsonSubTypes.Type(value = FriendFeedItem.class, name = BaseFeedItem.TYPE_FRIEND)
})
public interface FeedItem extends Parcelable {
    // ...
    @BaseFeedItem.Type
    String getType();
    // ...
}

Then i've made a base class, which all my subtype items had to extend.

public abstract class BaseFeedItem implements FeedItem {
    public static final String TYPE_POST = "post";
    public static final String TYPE_COMMUNITY_POST = "group_post";
    public static final String TYPE_PHOTO = "photo";
    public static final String TYPE_AUDIO = "audio";
    public static final String TYPE_VIDEO = "video";
    public static final String TYPE_FRIEND = "friend";

    @Retention(RetentionPolicy.SOURCE)
    @StringDef({TYPE_POST, TYPE_COMMUNITY_POST, TYPE_PHOTO, TYPE_AUDIO, TYPE_VIDEO, TYPE_FRIEND})
    public @interface Type {}
    private String type;

    @Type
    public String getType() {
        return type;
    }
    // ...
}

Finally, my POJO class:

public class NewsFeedEnvelope {
    // ...
    @JsonProperty("rows")
    private List<FeedItem> items;
    // ...
}

Now POJO is successfully automatically deserialized by Jackson without any custom deserializers.

like image 2
localhost Avatar answered Oct 13 '22 14:10

localhost