[英]GSON : custom object deserialization
好的,所以我编辑了这个问题因为它不够清楚。
编辑2 :更新了JSON文件。
我在Android应用程序中使用GSON,我需要解析来自服务器的JSON文件,并且有点过于复杂。 我不希望我的对象结构太重,所以我想简化内容: 所以我的对象的结构将不是JSON文件的结构。
例如,如果在JSON中我有这个:
{
"object1":{
"attribute1" : "test1",
"attribute40" : "test40",
"user":{
"id":1,
"name":"foo"
}
,"example":{
"total":10,
"list":[
{
"tag":"tag1",
"name":"object name 1",
"pos":1
},
{
"tag":"tag10",
"name":"object name 10",
"pos":10
}
]
}
}
"object2":{
"attribute1":"test..."
}
}
我不想保留我当前的对象结构,一个对象Example
,它包含一个ArrayList
和一个int
“total”。 但我想只保留一个简单的String,其值为"object name 1;object name 2;..."
。
此外,我想只存储用户ID,而不是完整的用户,因为我已经将完整的用户存储在其他地方,并且还有其他服务器API调用。
所以我的班级类似于:
class Foo{
int userId;
String example; //"object name 1;object name 2;..."
...
}
所以我想我们可以使用自定义反序列化器实现这一点,但我找不到如何。 我想尽可能减少内存,所以我不认为有一个完整的对象示例,然后使用它来构建我的String example
是一种正确的方法。
在最坏的情况下,如果它太复杂,我希望能够在解析示例对象时至少只存储Tag项列表:所以我需要一个自定义反序列化器来摆脱int total
。
所以我会:
class Foo{
int userId;
ArrayList<Tag> example;
...
}
我采用了答案来呈现聊天中设计的完整解决方案,以适应更改的JSON字符串。 该代码假定字符串json完全包含问题中的(更新的)JSON。 要求是填写以下类(setter和toString ommitted):
class Object1
{
private String attribute1;
private String attribute40;
private int userId;
private String nameList;
}
GSON支持(作为大多数其他REST-libs)三种模式:
JsonParser.parse()
读取整个JSON,并在内存中构建DOM树(对象模型访问)。 因此,此解决方案适用于小型JSON文件。 JsonReader
只读取JSON的块。 代码更复杂,但它适用于大型JSON文件。 从Android 3.0 Honeycomb开始,GSON的流解析器包含在android.util.JsonReader
。 要通过GSON_DOM和GSON_BIND填充Object1类,实现如下:
private static void deserializeViaObjectAccess(final String json)
{
Gson gson = new Gson();
// Read the whole JSON into meomory via GSON_DOM
JsonParser parser = new JsonParser();
JsonObject object1 = parser.parse(json).getAsJsonObject().getAsJsonObject("object1");
// map the Object1 class via GSON_BIND
// (bind common attributes which exist in JSON and as properties in the class)
// mapper acts as factory
Object1 result = gson.fromJson(object1, Object1.class);
// manually read the attribute from the user object
int userId = object1.getAsJsonObject("user").getAsJsonPrimitive("id").getAsInt();
result.setUserId(userId);
// manually read the attributes from the example object
String names = "";
JsonArray list = object1.getAsJsonObject("example").getAsJsonArray("list");
for (int i = 0; i < list.size(); ++i)
{
JsonObject entry = list.get(i).getAsJsonObject();
String name = entry.getAsJsonPrimitive("name").getAsString();
names = i == 0 ? name : names + "; " + name;
}
result.setNameList(names);
// Output the result
log.debug(result.toString());
}
要通过GSON_STREAM和GSON_BIND填充Object1类,实现如下:
目前,这只有在通过GSON_BIND或GSON_STREAM完全加载节点时才有可能。 此示例需要分割节点本身。 这仅适用于即将推出的2.2版本。 稍后我会在GSON 2.2可用时提交代码。*
其中一个选项是解析使用内部GSON内置详见解析器JSON字符串这里 。 你会做这样的事情:
com.google.gson.JsonParser parser = new JsonParser();
JsonObject object = parser.parse(data).getAsJsonObject();
JsonObject example = object.getAsJsonObject("example");
JsonArray list = example.getAsJsonArray("list");
JsonObject和JsonArray是Gson本身的一部分。
使用这些之后,您可以使用getAsInt等函数来解析单个字段,并构建并返回您想要的任何对象。
编辑1
看起来你也可以在自定义类上使用gson.fromJson而不仅仅是本例中给出的通用Java类型。 因此,您必须使用parse解析JSON字符串,并在其中一个内部对象或数组上调用fromJson。
将示例JSON序列化为完整的Example对象,使用Example对象的name属性构建所需事物的String,忘记Example对象。
我并不完全理解第二个问题,但如果你有一个完整的Test1对象将所有的字段/属性,那么你可以创建一个Test2对象,它从Test1获取它想要的字段。 例如,您的Test2对象可以在其构造函数中接受Test1作为参数,并仅采用它忽略其余部分所需的属性。
当您通过http在Jsons中进行流式传输时,您可以简单地丢弃文本并仅存储自定义对象。 在这种情况下,您将不断丢弃不需要的信息。
While stream not empty
Read the next block into a new string
Deserialize the string to the your object
Store the object in a myArrayList
注意:如果您希望应用程序具有可靠性,则读取整个JSON并将其作为一个整体使用是非常必要的。 除非您想将JSON读作原始字符流(我怀疑,除非您的JSON真的非常大,否则这个快捷方式是必要的)。
Neverthelss,读取输入流而不强加和JSON良好构造要求,可以在不必编写和不必要的数据结构到内存的情况下完成。 如果您只想要一小部分数据,这可能会有效 - 即您只需要人们的名字或JSON中的网址。 但如果您想要更复杂的数据结构,它就会崩溃。 不过:
//示例解析来自JSON行的URL而不存储整个数据结构
While input stream is not empty
String x = nextLine
If x contains "http"
myArrayList.add(parseUrl(x)
最后的想法 :
Bur最终,Jsons REST请求不像SQL那样 - 你不能在通用和任意地忽略某些领域。也许,如果你真的想要更轻量级的Jsons,更自然的方法是告诉或检查你的RESt服务提供商是否可以简单地扩大类型RESt请求参数以适应您的用例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.