Reputation: 3713
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
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
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