我用GSON库解析服务器JSON响应。后端人员有时会告诉我:“由于某些原因,我们无法在JSON中指定变量类型”(旧的PHP,他们不知道如何去做等等)。 GSON喜欢在其对象模型中进行强类型输入。所以我不能将Object解析为String。
GSON等待:
{
"service":{
"description":null,
"name":"Base",
"id":"4c7a90410529"
}
}
但它得到(空数据):
"service": ""
我得到了
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1396
解析此类响应的最佳做法是什么?
另一个问题: 我如何构建对象,它可以识别不时返回为Integer或String的Integer变量?相同的服务器端问题。
"data": "1"
或
"data": 1
我知道 - 我们应该在Java中使用特定类型。但有时候做出让步是值得的,
感谢
修改
我的解决方案基于Java Developer的答案。
ServiceDeserializer类根据其内部值反序列化每个对象。
public class ServiceDeserializer implements JsonDeserializer<ServiceState>{
@Override
public ServiceState deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String name = "";
String uuid = "";
String description = "";
if (json.isJsonObject()) {
JsonObject obj = json.getAsJsonObject();
if (!obj.get("name").isJsonNull()) {
name = obj.get("name").getAsString();
}
if (!obj.get("uuid").isJsonNull()) {
uuid = obj.get("uuid").getAsString();
}
if (!obj.get("description").isJsonNull()) {
description = obj.get("description").getAsString();
}
}
return new ServiceState(name, uuid, description);
}
}
我的GSON构造函数,带有ServiceState的类型适配器。
Gson gson = new GsonBuilder()
.registerTypeAdapter(ServiceState.class, new ServiceDeserializer())
.create();
答案 0 :(得分:1)
在尝试将其反序列化为Response
Java对象之前,需要抓取JSON响应。您可以使用Java org.json解析器来验证service
对象实际存在并以其他方式修复它。
String json = "{\"service\":{\r\n" +
" \"description\":null,\r\n" +
" \"name\":\"Base\",\r\n" +
" \"id\":\"4c7a90410529\"\r\n" +
"}}";
String json2 = "{\"service\":\"\"}";
JSONObject root = new JSONObject(json);
// JSONObject root = new JSONObject(json2);
if (root.optJSONObject("service") == null) {
root.put("service", new JSONObject());
}
Gson gson = new Gson();
Response response = gson.fromJson(root.toString(), Response.class);
System.out.println(response.getService());
输出:
// for JSONObject root = new JSONObject(json);
Service [id=4c7a90410529, name=Base, description=null]
// for JSONObject root = new JSONObject(json2);
Service [id=null, name=null, description=null]
其次,Gson
非常聪明,可以执行简单的转换,例如String
到Integer
等等。因此,反序列化此类JSON属性不会给您带来任何麻烦。
System.out.println(gson.fromJson("10", Integer.class)); // 10
System.out.println(gson.fromJson("\"20\"", Integer.class)); // 20
答案 1 :(得分:0)
你的json无效,任何Json解析器都无法解析语法不正确的json:
"service": {
"description": null,
"name": "Base",
"id": "4c7a90410529"
}
应该用大括号括起来,如下所述:
{
"service": {
"description": null,
"name": "Base",
"id": "4c7a90410529"
}
}
答案 2 :(得分:0)
json结构包含在{}
中。您的回答似乎缺失了。您可以在字符串的开头和结尾手动附加{
和}
,以使其成为有效的json结构。
完成此操作后,您可以使用Gson正常解析您的json响应。
解析此类响应的最佳做法是什么?
使用足够好的Json解析器。这绰绰有余。并尝试使用一个表示与响应完全相同的结构的类,以避免手动逐级解析json响应。
答案 3 :(得分:0)
如果您想严格遵守gson
,可以提供自定义deserializer。由于我们知道service
是基本json
字符串的属性或嵌入在其他property
中,我们可以使用反序列化器逐步解析有问题的组件并处理它们相应
public class MyJsonDeserializer implements JsonDeserializer<YourParsedData> {
@Override
public YourParsedData deserialize(final JsonElement je, final Type type, final JsonDeserialization Context jdc) throws JsonParseException
{
final JsonObject obj = je.getAsJsonObject(); //our original full json string
final JsonElement serviceElement = obj.get("service");
//here we provide the functionality to handle the naughty element. It seems emtpy string is returned as a JsonPrimitive... so one option
if(serviceElement instanceOf JsonPrimitive)
{
//it was empty do something
}
return YourParsedData.create(); //provide the functionality to take in the parsed data
}
}
自定义反序列化器的调用方式如下:
final Gson gson = new GsonBuilder().registerTypeAdapter(YourParsedData.class, new MyJsonDeserializer()).create();
gson.fromJson("{service: ''}", YourParsedData.class);
我输入了所有这些,如果我错过了一些语法,我道歉。