Sre*_*ree 3 java serialization android json gson
我有一个 json 对象,如下所示:
{
"user": {
"id": 1234
...
"photos": [
{
"url": "http://....."
...
},
{
"url": "http://....."
...
}
]
}
}
Run Code Online (Sandbox Code Playgroud)
user我想为和编写一个自定义解串器photos。
所以我有:
public class User {
private long id;
private ArrayList<Photo> photos;
...
public static class Deserializer implements JsonDeserializer<User> {
... // does the custom serialization of the User object
}
}
public class Photo {
private String url;
...
public static class Deserializer implements JsonDeserializer<Photos> {
... // does the custom serialization of the Photo object
}
}
Run Code Online (Sandbox Code Playgroud)
初始化时我这样做:
new GsonBuilder()
.registerTypeAdapter(User.class, new User.Deserializer());
.registerTypeAdapter(Photos.class, new Photos.Deserializer());
Run Code Online (Sandbox Code Playgroud)
但是,当我反序列化该类时User,它会命中 的User反序列化器,但永远不会命中 的Photo反序列化器。但是,如果我得到一个 json,其中照片对象未嵌套在用户 json 对象中,如下所示:
{
"photos": [
{
"url": "http://....."
...
},
{
"url": "http://....."
...
},
{
"url": "http://....."
...
}
]
Run Code Online (Sandbox Code Playgroud)
它将正确命中 的Photo解串器
简而言之,有一个非正式的规则:一旦您为某种类型声明了类型适配器(或原则上共享相同概念的(反)序列化器) ,那么您必须自己管理其实例化及其子字段。因此,当您反序列化最顶层的 时User,它的id和photos会自行反序列化。请注意,Photo.Deserializer一旦您通过反序列化上下文显式请求它gson.fromJson(..., Photo.class)或隐式应用它(对于后者 Gson 默认情况下使用内置策略,请参阅ReflectiveTypeAdapterFactory示例),就会调用它。User如果你不绑定,同样的原理也适用User.Deserializer,因此 GsonReflectiveTypeAdapterFactory.Adapter<T>使用反射来迭代所有字段本身。更短的是:Gson 不会合并多个策略(至少在默认情况下),因此您要么将对象构造和设置委托给 Gson,要么完全实例化它。
知道了,User.Deserializer可以按如下方式实现:
final class User {
final long id;
final List<Photo> photos;
private User(final long id, final List<Photo> photos) {
this.id = id;
this.photos = photos;
}
static final class Deserializer
implements JsonDeserializer<User> {
private static final Type photoListType = new TypeToken<List<Photo>>() {
}.getType();
@Override
public User deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) {
// Note that you must pick up properties first
final JsonObject jsonObject = jsonElement.getAsJsonObject();
return new User(
// And then delegate them to the deserialization context specifying the target type
context.deserialize(jsonObject.get("id"), long.class),
// You can deconstruct JsonElement recursively, but deserialization context respects Gson context built with GsonBuilder
// This also does trigger the Photo.Deserializer
context.deserialize(jsonObject.get("photos"), photoListType)
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我假设Photos你的代码中有一个拼写错误,它应该是Photo. 如果不是,则可以为 实施类似的解决方案Photos。
final class Photo {
final String url;
private Photo(final String url) {
this.url = url;
}
static final class Deserializer
implements JsonDeserializer<Photo> {
@Override
public Photo deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
return new Photo(
// jsonObject.get("url").getAsString() can be more simple, but it does not respect Gson instance configuration
context.deserialize(jsonObject.get("url"), String.class)
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如何使用:
final class Wrapper {
final User user;
private Wrapper(final User user) {
this.user = user;
}
}
Run Code Online (Sandbox Code Playgroud)
final Gson gson = new GsonBuilder()
.registerTypeAdapter(User.class, new User.Deserializer())
.registerTypeAdapter(Photo.class, new Photo.Deserializer())
.create();
final Wrapper wrapper = gson.fromJson(JSON, Wrapper.class);
System.out.println(wrapper.user.id);
wrapper.user.photos.forEach(p -> System.out.println(p.url));
Run Code Online (Sandbox Code Playgroud)
输出:
第 1234
章
| 归档时间: |
|
| 查看次数: |
3897 次 |
| 最近记录: |