Victor Oliveira
Victor Oliveira

Reputation: 3713

How to deserialize types that inherit common base class - with Gson?

I have the following hierarchy:

RESPONSE

public class Response implements Serializable {

    @SerializedName("message")
    @Expose
    private List<Message> messages;

    public List<Message> getMessages() {
        return messages;
    }

    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }

}

MESSAGE

public class Message implements Serializable {

        @SerializedName("type")
        @Expose
        @MessageType
        private int type;

        @SerializedName("position")
        @Expose
        @MessagePosition
        private String position;

        public int getType() {
            return type;
        }

        public String getPosition() {
            return position;
        }

        public void setType(@MessageType int type) {
            this.type = type;
        }

        public void setPosition(@MessagePosition String position) {
            this.position = position;
        }

}

TEXT -> MESSAGE

public class TextMessage extends Message {

@SerializedName("text")
@Expose
private String text;

public String getText() {
    return text;
}

public void setText(String text) {
    this.text = text;
}

}

IMAGE -> MESSAGE

public class ImageMessage extends Message {

    @SerializedName("attachment")
    @Expose
    private Attachment attachment;

    public Attachment getAttachment() {
        return attachment;
    }

    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }

}

Trying to deserialize Message this way with GSon leads (naturally) to empty fields at text or attachment fields. I would like to have a best fit deserialization, which based on response would choose at run time which Message type (i.e. Text or Image) matches most fields to be fulfilled.

So far the only thoughts I had were:

1 - Use @JsonAdapter -> Didn't work

2 - Create another hierarchy structure to point classes at compile time like:

---- Response
   |
    - TextResponse -> List<TextMessage>
   |
    - ImageResponse -> List<ImageMessage>

Second option is not really what I want and makes me multiply the number of classes in a way that might get too complicated to apply later maintenance.

Does anyone know a way to handle this problem? Any framework or concepts that could be applied?

Thanks in advance

Upvotes: 2

Views: 2013

Answers (2)

pirho
pirho

Reputation: 12285

Maybe you could use Gson extras RunTimeTypeAdapterFactory. Check this example:

RuntimeTypeAdapterFactory<Message> factory = RuntimeTypeAdapterFactory
    .of(Message.class, "type") // actually type is the default field to determine
                               // the sub class so not needed to set here
                               // but set just to point that it is used
    // assuming value 1 in field "int type" identifies TextMessage
    .registerSubtype(TextMessage.class, "1")
    // and assuming int 2 identifies ImageMessage
    .registerSubtype(ImageMessage.class, "2");

Then use GsonBuilder.registerTypeAdapterfactory(factory) to use this.

This just is not found from Gson core library. You need to fetch it here. You might also find some Maven/Gradle dep from global repo that someone has done but maybe easiest is just to copy this file.

It enables later hacks then if you need to modify its behavior.

Upvotes: 2

beigirad
beigirad

Reputation: 5744

I implemented this with GodClass that has all of message types fields.

but you don't use this POJO classes as DTO (Data Transfer Object) in your application.

Json is a protocol and not supported Inheritance and etc.

In same scenario I implemented this inheritance and hierarchy for DTOs.

PS: DTO in my answer is Models that we pass for example in Adapter or an Activity and so on.

Upvotes: 0

Related Questions