gpt4 book ai didi

java - JsonSerializer 不适用于使用 GSON 的嵌套对象

转载 作者:搜寻专家 更新时间:2023-11-01 08:28:15 25 4
gpt4 key购买 nike

我有一个看起来像这样的 json 对象:

{
"user": {
"id": 1234
...
"photos": [
{
"url": "http://....."
...
},
{
"url": "http://....."
...
}
]
}
}

我想为 userphotos 编写自定义反序列化器。

所以我有:

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
}
}

初始化时我这样做:

new GsonBuilder()
.registerTypeAdapter(User.class, new User.Deserializer());
.registerTypeAdapter(Photos.class, new Photos.Deserializer());

但是,当我反序列化 User 类时,它命中了 User 的反序列化器,但从未命中 Photo 的反序列化器。但是如果我得到一个 json,其中的照片对象没有像这样嵌套在用户 json 对象中:

{
"photos": [
{
"url": "http://....."
...
},
{
"url": "http://....."
...
},
{
"url": "http://....."
...
}
]

它将正确命中Photo的反序列化器

最佳答案

简而言之,有一个非正式的规则:一旦你为一个特定类型声明了一个类型适配器(或原则上共享相同概念的(反)序列化器),那么你就有了自己管理它的实例化和它的子字段。因此,当您反序列化最顶层的 User 时, 它的 idphotos是你自己反序列化的。请注意 Photo.Deserializer一旦你像gson.fromJson(..., Photo.class)这样明确地请求它就会被调用或者通过反序列化上下文隐式应用它(对于后者 Gson 默认使用内置策略,请参见 ReflectiveTypeAdapterFactory 例如)。同样的原则适用于 User如果你不绑定(bind) User.Deserializer , 因此 Gson 使用 ReflectiveTypeAdapterFactory.Adapter<T>它只是使用反射遍历所有字段本身。甚至更短:Gson 不会合并多个策略(至少在默认情况下),因此您要么将对象构造和设置委托(delegate)给 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)
);
}

}

}

我假设 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)
);
}

}

}

如何使用:

final class Wrapper {

final User user;

private Wrapper(final User user) {
this.user = user;
}

}
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));

输出:

1234
http://.....
http://.....

关于java - JsonSerializer 不适用于使用 GSON 的嵌套对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42772466/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com