也许您想使用 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());
}
上面的输出类似于:
类 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\"}}"
+ "]";
因此该类型包含简单的类名称(通常是
case) 你可以像这样注册子类型:
.registerSubtype(ForwardRequest.class)
.registerSubtype(LoginRequest.class);
并且 GSON 期望类简单名称作为 JSON 类型属性的值。为什么要将类名放在单独的字段中,因为它是可获取的Class.getSimpleName()?
当然,您有时可能需要将其序列化给其他客户端。