我有一个json数据包,包含一个dacket头(在PACKET_HEADER下)+许多不同类型的消息(在DATA下)。这些消息具有相同的父类:
//my packet class
public class Packet {
public PacketHeader PACKET_HEADER;
public Message[] DATA;
}
//my parent message class:
public class Message {
public enum MessageType {
WHOAREYOU,
TimeData,
Ready,
LocationData
}
public MessageType getMessageType() {
return MESSAGE_TYPE;
}
public void setMessageType(MessageType MessageType) {
this.MESSAGE_TYPE = MessageType;
}
private MessageType MESSAGE_TYPE;
//declaring public for simplicity
public String SENDER;
public String SENDER_TYPE;
}
//sample child class:
public class TimeMessage extends Message {
private int tick;
public int getTick()
{
return tick;
}
我将这样的输入反序列化:
@Override
public Handler create(Connector connector, Object packet, int clientID) {
Gson gson = new Gson();
Packet pack = gson.fromJson(packet.toString(), Packet.class);
System.out.println("Number of messages : " + pack.PACKET_HEADER.NOF_MESSAGES );//ok
for(Message msg : pack.DATA)
{
switch (msg.getMessageType()) {
//enters the switch successfully
case TimeData: {
System.out.println("Sender: " + msg.SENDER + " Sender_type: " + msg.SENDER_TYPE);//ok
TimeMessage time_msg = (TimeMessage) msg;//NOT ok, generates exception!!!!
//...
return new TimeHandler(time_msg, connector, clientID);
}
default:
System.out.println("Switch " + msg.getMessageType() + " is invalid");
return null;
}
}
return null;
}
你知道为什么我不能投入儿童班吗?我该如何解决呢。非常感谢。
答案 0 :(得分:3)
这是因为Gson在没有一点帮助的情况下无法处理多态。
确实 JSON不保留类型信息所以当Gson反序列化文档时,它将创建仅消息实例,而不是像 TimeMessage 那样创建子类的实例,因为它无法猜测正确的类型。
您必须使用其他组件 RuntimeTypeAdapterFactory 。
我刚刚在我的博客上写了一篇关于它的文章:http://pragmateek.com/javajson-mapping-with-gson
以下是您感兴趣的部分:http://pragmateek.com/javajson-mapping-with-gson/#Preserving_type_information
请询问您是否仍有问题。
编辑:
以下是针对您的具体情况的完整示例:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
public class Program
{
public static class Packet
{
public Message[] DATA;
}
public static enum MessageType
{
WHOAREYOU,
TimeData,
Ready,
LocationData
}
//my parent message class:
public static class Message {
public MessageType getMessageType() {
return MESSAGE_TYPE;
}
public void setMessageType(MessageType MessageType) {
this.MESSAGE_TYPE = MessageType;
}
private MessageType MESSAGE_TYPE;
//declaring public for simplicity
public String SENDER;
public String SENDER_TYPE;
}
//sample child class:
public static class TimeMessage extends Message
{
private int tick;
public int getTick()
{
return tick;
}
public TimeMessage(int tick)
{
this.tick = tick;
}
}
public static void main(String[] args)
{
Message[] messages = { new TimeMessage(123) };
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(Message.class, "$type").registerSubtype(TimeMessage.class));
Gson gson = builder.create();
String json = gson.toJson(messages);
Message[] outMessages = gson.fromJson(json, Message[].class);
TimeMessage tm = (TimeMessage)outMessages[0];
}
}