我有以下两种类型的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);
或res = gson.fromJson(content, Login.class)
;
但是我收到的json是
{"type": "Forward", "content":{"deviceId":"1"}}
然后我得到了预期为String但却是Object的错误,所以我不知道如何继续。任何建议将不胜感激!
答案 0 :(得分:1)
在此处检查代码
Tooltip(
message: userAction.route.name,
child: Text(
userAction.route.name.length < 10
? userAction.route.name
: userAction.route.name.substring(0, 10) + '...',
style: TextStyle(fontWeight: FontWeight.bold),
),
)
答案 1 :(得分:0)
也许您想使用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()
?
但是,您当然有时可能需要将其序列化到其他客户端。