Gson:基于另一个字段的动态字段解析

帕特里克:

我有以下两种类型的JSON字符串,它们都有一个“类型”字段,但是“内容”字段具有不同的结构。

{"type": "Login", "content": {"username": "a", "password": "b"}}

{"type": "Forward", "content": {"deviceId": "a", "password": "b"}}

我想将它们解析为Java对象。现在我有两节课:

class Login {
    String username;
    String password;
}

class Forward {
    String deviceId;
}

现在的问题是,我必须先解析json消息的“一部分”(即“类型”部分),然后才能决定使用哪个类来继续解析“内容”。

有没有办法执行此“两步”解析?

我尝试了以下方法:
首先将json消息解析为此类的实例:

class Request {
    RequesType type;
    String content;
}

然后,基于该类的解析“类型”字段,我可以决定使用哪个类,即使用res = gson.fromJson(request.content, Forward.class);or res = gson.fromJson(content, Login.class)

但是我收到的json是

{"type": "Forward", "content":{"deviceId":"1"}}

而且我得到了预期的错误,它是字符串,但是是对象,所以我不知道如何继续。任何建议将不胜感激!

皮尔霍:

也许您想使用GSON的RuntimeTypeAdapterFactory它允许您从类型字段中确定要反序列化的类的类型:默认方便地命名为type

为了拥有GSON反序列化的继承权,我建议对POJO进行一些小的更改。创建类的目的Request是:

@Getter @Setter
public class Request {
    private String type;
    @Getter @Setter
    public static class Content {
        String password;
    }
}

根据请求类型覆盖它和内容,例如:

@Getter @Setter
public class ForwardRequest extends Request {
    @Getter @Setter
    public static class ForwardContent extends Content {
        private String deviceId;
    }
    private ForwardContent content;
}

@Getter @Setter
public class LoginRequest extends Request  {
    @Getter @Setter
    public static class LoginContent extends Content {
        private String username;
    }
    private LoginContent content;
}

对于上面的类,它只是:

@Test
public void test() {
    // Tell the top class
    RuntimeTypeAdapterFactory<Request> rttaf = RuntimeTypeAdapterFactory.of(Request.class)
        // Register inheriting types and the values per type field
        .registerSubtype(ForwardRequest.class, "Forward")
        .registerSubtype(LoginRequest.class, "Login");
    Gson gson = new GsonBuilder().setPrettyPrinting()
        .registerTypeAdapterFactory(rttaf)
        .create();
    // Constructed an array of your two types to be deserialized at the same time  
    String jsonArr = "["
          + "{\"type\": \"Login\", \"content\": {\"username\": \"a\", \"password\": \"b\"}}"
          + ","
          + "{\"type\": \"Forward\", \"content\": {\"deviceId\": \"a\", \"password\": \"b\"}}"
          + "]";
    // Deserialize the array as Request[]
    Request[] requests = gson.fromJson(jsonArr, Request[].class);
    log.info("{}", requests[0].getClass());
    log.info("{}", requests[1].getClass());   
}

上述的Outpur类似于:

类org.example.gson.LoginRequest
类org.example.gson.ForwardRequest

您只需要复制答案顶部链接中提供的文件,即可将其包含RuntimeTypeAdapterFactory在您的项目中。

更新:关于反序列化type或任何其他包含有关类型的信息的字段:GSON故意将其遗漏。它是一种瞬态场吗?您需要先知道的值,type然后才能进行反序列化,因此GSON不再需要对其进行反序列化。

再举一个例子-为了澄清这一点-如果您更改测试字符串,例如:

String jsonArr = "["
      + "{\"type\": \"LoginRequest\", \"content\": {\"username\": \"a\", \"password\": \"b\"}}"
      + ","
      + "{\"type\": \"ForwardRequest\", \"content\": {\"deviceId\": \"a\", \"password\": \"b\"}}"
      + "]";

因此,该类型可以保存类的简单名称(通常是这种情况),您可以像下面这样注册子类型:

.registerSubtype(ForwardRequest.class)
.registerSubtype(LoginRequest.class);

并且GSON希望将类的简单名称作为JSON的type属性的值。为什么要将类名保存在单独的字段中,因为它是可获取的Class.getSimpleName()

但是,您当然有时可能需要将其序列化到其他客户端。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

一个字段基于另一个字段的求和

React:以动态生成的形式基于另一个字段更新字段值

试图基于一个字段获取DateDiff并更新另一个字段

在Redux表单中基于另一个字段验证一个字段

将setFieldValue用于一个字段,基于另一个字段的值

SQL:基于另一个字段的值的条件字段输出

基于Jackson中另一个字段值的条件字段要求?

基于另一个字段值的猫鼬隐藏/显示字段

Django模型字段默认基于相同模型中的另一个字段

Spring Boot - Mongodb - 基于另一个字段的自动递增字段

基于另一个字段的Jackson字段序列化

如何在查询中添加基于另一个字段的字段

访问-自动更新是/否字段基于另一个字段

SQL更新字段基于另一个字段的条件

如何验证基于另一个字段的字段?

awk - 从基于另一个字段的字段添加值

动态字段数取决于另一个字段的值

将动态字段值复制到另一个字段

根据另一个字段更新一个字段

需要一个字段或另一个字段

使用 Azure DevOps API 获取具有基于另一个字段值的动态数据的字段的工作项类型字段值

尝试基于另一个字段的约束求和一个公式字段

MongoDB - 基于另一个字段值的 $match

创建基于另一个字段的计数器

mongodb基于另一个字段的计数值

在基于MySQL中另一个字段的子查询中使用LIMIT

基于另一个字段值的条件渲染标签颜色

组基于另一个字段中的2个相同数据组成一个字段

猫鼬需要基于另一个字段的一些枚举值的字段