当前位置: 首页 > 知识库问答 >
问题:

Gson不能反序列化继承的类?

浦思源
2023-03-14

我有一个简单的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() {
    }    
}

我需要将反序列化分为两个阶段:

1-反序列化以读取消息类型

2.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打印0而不是12)

你觉得我哪里做错了?谢谢你们

共有2个答案

东门彬
2023-03-14

我通过以下方式实现了一个定制的JsonDeserializer,成功地解决了类似的问题。

首先,根据类型和检索正确类的方法将子类附加到枚举中

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

然后在反序列化方法中,我执行了以下操作:

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解析器实例注册序列化程序。

注意:根据Java标准,你对事物的命名是非常不正确的。枚举常量应该是ALL_CAPITALIZED,枚举类名应该是单数的(例如。MessageType)。实例变量应该被骆驼(例如。MessageType而不是MessageType

潘振国
2023-03-14

问题是,JSON表示的对象包含您感兴趣的另一个对象,而Java只是一个对象。

实际上,您可以为每种类型编写反序列化程序,并在确定消息类型后使用它们:

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);
    }
}

 类似资料:
  • 在Android应用程序中,我需要用一个抽象级别反序列化Kotlin数据类的Json数据。但我不知道如何在构造函数中放置正确的属性。 简单来说,假设我有一个形状: 有两个派生 和 所以我的目标是,不要实例化一个形状。所以,相反,总是反序列化它的派生。稍后,我需要处理其他类中的一些集合属性,如: 但我还必须知道每个元素的派生类型。 当我尝试用Gson反序列化给定的示例时 我总是有一个非法的辩论例外

  • 解决了。 我在另一个类中初始化我的产品列表: 我想做的是,在构造函数中初始化我的产品列表,如下所示: 这是我的方法,它将对象列表写入。json文件: 我在成员的帮助下找到的解决方案: 和构造函数:

  • 问题:类A实现可序列化类B扩展了类A实现可序列化 现在我只使用类B作为运行时类型进行序列化。所以我有一个列表: 如果我现在反序列化它,我就得到了java。伊奥。OptionalDataException错误。我想知道的是,我的对象如何成为正确的运行时类型。反序列化: 如果在序列化时是类B的运行时类型,这是否会导致类B的运行时类型,或者我必须覆盖A的earch子类的默认序列化? 希望我没有错过任何明

  • 问题内容: 我想通过Google Gson传输列表对象,但是我不知道如何反序列化泛型类型。 看了这个之后我尝试了什么(BalusC的答案): 但是后来我在日食中遇到了一个错误,说“新的List(){}类型必须实现继承的抽象方法…”,如果我使用快速修复方法,则会得到20个以上的方法存根的怪物。 我很确定有一个更简单的解决方案,但是我似乎找不到它! 编辑: 我现在有 但是,我确实在“ fromJson

  • 问题内容: 由于要执行处理的业务逻辑,因此我正在实现自定义。但是某些部分可以解析为标准方式。这是否可能- 我自己处理一些元素,并让一些嵌套元素自动处理? 这是JSON: 这是项的自定义反序列化器: 现在,我想让GSON解析枚举。我可以自己完成,这只是几行代码,但是我更愿意库做很多。 问题答案: …但是我希望图书馆尽其所能。 好吧,只需使用Gson。 有数据传输对象模式,尤其是Gson映射类,可以完

  • 假设我有一组a、B、C类: 公开A类:整数; 公共B类:整数;字符串地址; 公共类C:int orderNumber; 如何反序列化仅包含这些类但顺序未知的Json字符串(在Java中使用Gson)?例如: 非常感谢你!