2

ダケット ヘッダー (PACKET_HEADER の下) + さまざまな種類のメッセージ (DATA の下) で構成される json パケットがあります。これらのメッセージは同じ親クラスを持っています:

//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; 

    }

なぜ私が子クラスにキャストできないのか分かりますか? どうすれば解決できますか。よろしくお願いします。

4

1 に答える 1

4

これは、Gson が少し手を加えないとポリモーフィズムを処理できないためです。

実際、JSON は型情報を保持しないため、Gson がドキュメントを逆シリアル化するときに、正しい型を推測する方法がないため、TimeMessageのようなサブクラスのインスタンスではなく、Message インスタンスのみを作成します。

追加のコンポーネントである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];
    }
}
于 2013-06-10T15:06:04.997 に答える