无法反序列化不同类型的子对象的列表

时间:2013-06-10 05:26:13

标签: java json gson

我有一个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; 

    }

你知道为什么我不能投入儿童班吗?我该如何解决呢。非常感谢。

1 个答案:

答案 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];
    }
}