5

次のような単純な Json 構造があります。

{"MessageType":"TimeData","TimeData":{"hh":12,"mm":13,"ms":15,"ss":14}}

そして、それを逆シリアル化するために次のクラスを考案しました。

public class JsonMessage
{
    public enum MessageTypes{
        WhoAreYou,
        TimeData
    }
    JsonMessage(){
    }
    public MessageTypes MessageType;
}
class TimeData extends JsonMessage{
    int hh;
    int mm;
    int ss;
    int ms;

    TimeData() {
    }    
}

逆シリアル化を 2 つのフェーズに分割する必要があります。

1- を読み取るためにデシリアライズしますMessageType

2- に基づいて、残りの逆シリアル化を続行します。MessageType

コードは簡単です。

public void dispatch(Object message, IoSession session)
    {

            Gson gson = new Gson();
            JsonMessage result = gson.fromJson(message.toString(), JsonMessage.class);
            System.out.println(result.MessageType.toString());
            switch (result.MessageType)
                {
                    case WhoAreYou:{
                    //.....
                    break;
                    }
                    case TimeUpdate:
                        TimeData res = new Gson().fromJson(message.toString(), TimeData.class);
                        System.out.println(res.hh);
                        break;
                    default:break;
        }
    }

私のプログラムは正しいswitch-case(これは ですTimeUpdate) を入力できますが、正しく解析しません (println は 12 ではなく 0 を出力します)

私がどこで何か悪いことをしたと思いますか?ありがとうございました

4

2 に答える 2

7

問題は、JSON が関心のある別のオブジェクトを含むオブジェクトを表しているのに対し、Java は単一のオブジェクトであることです。

実際には、各タイプのデシリアライザーを作成し、次のことを決定したらそれらを使用できますMessageType

public static void main(String[] args)
{
    Gson gson = new GsonBuilder().registerTypeAdapter(TimeData.class, new TimeDataDeserializer()).create();
    String json = "{\"MessageType\":\"TimeData\",\"TimeData\":{\"hh\":12,\"mm\":13,\"ms\":15,\"ss\":14}}";
    JsonMessage message = gson.fromJson(json, JsonMessage.class);

    switch(message.MessageType)
    {
        case TimeData:
            TimeData td = new GsonBuilder()
                            .registerTypeAdapter(TimeData.class, new TimeDataDeserializer())
                            .create()
                            .fromJson(json, TimeData.class);
            td.MessageType = message.MessageType
            System.out.println(td.hh);
            break;
        default:
            break;
    }
}

class TimeDataDeserializer implements JsonDeserializer<TimeData>
{
    @Override
    public TimeData deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)  
        throws JsonParseException
    {
        JsonObject jo = je.getAsJsonObject().getAsJsonObject("TimeData");
        Gson g = new Gson();
        return g.fromJson(jo, TimeData.class);
    }
}
于 2013-04-26T04:16:45.007 に答える
1

次の方法でカスタムJsonDeserializerを実装することで、この同様の問題を解決することができました。

まず、型に基づいてサブクラスを列挙型にアタッチし、メソッドをClass<?>列挙型名に従って正しいものを取得します。

enum MessageType {
  WHO_ARE_YOU(WhoAreYou.class),
  TIME_UPDATE(TimeUpdate.class);

  public final Class<?> clazz;

  MessageType(Class<?> clazz) { this.clazz = clazz; }

  public static MessageType forName(String name) {
    for (MessageType t : values())
      if (name.equals(t.name()))
        return t;

    return NULL;
  }
}

次に、deserializeメソッドで次のことを行いました。

public JsonMessage deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
   JsonObject object = json.getAsJsonObject();
   String kind = object.get("messageType").getAsString();
   Class<?> clazz = MessageType.forName(kind).clazz;
   JsonMessage result = null;

   try {
     result = (JsonMessage)clazz.newInstance();
     Field[] fs = clazz.getFields();

     for (Field f : fs) {
       Object value = context.deserialize(object.get(f.getName()), f.getType());                 
       if (value != null)
         f.set(result, value);
     }
   } 
   catch (Exception e) {
     e.printStackTrace();
   }
}

すべてがリフレクションによって管理されるため、正しいオブジェクトが作成され、それに応じてすべてのフィールドが逆シリアル化されます。

私はオブジェクトの複雑な階層を持っていたので、gson デシリアライザーにすべてを管理させるためにこの方法を選びました。もちろん、シリアライザーを gson パーサー インスタンスに登録する必要があります。

A 注: Java 標準によると、名前付けはまったく正しくありません。enum 定数はALL_CAPITALIZED、enum クラス名は単数形にする必要があります (例: MessageType)。インスタンス変数はキャメルケースにする必要があります (例: messageTypenot MessageType)

于 2013-04-25T16:43:17.607 に答える