我有一个json对象,如下所示:
{
"user": {
"id": 1234
...
"photos": [
{
"url": "http://....."
...
},
{
"url": "http://....."
...
}
]
}
}
我想为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
}
}
并在初始化时执行此操作:
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
的反序列化程序
答案 0 :(得分:1)
我认为这些类与json文件不匹配。在这个json文件中:
{
"user": {
"id": 1234
...
"photos": {
"abc": {
"url": "http://....."
...
}
}
}
}
你有
public class User {
private int id;
private Photos photos;
}
public class Photos {
private MyUrl abc;
private MyUrl bcd;
private MyUrl cde;
...
}
public class MyUrl {
private String url;
}
要获取照片的ArrayList,json应如下所示(注意方括号及其内容):
{
"user": {
"id": 1234
...
"photos": [
{ "url": "http://....." },
{ "url": "http://....." },
...
{ "url": "http://....." }
]
}
}
}
这最后一个杰森回应:
public class User {
private int id;
...
private ArrayList<Photo> photos;
}
public class Photo{
private String url;
}
答案 1 :(得分:1)
简而言之,有一个非正式的规则:一旦你声明一个某种类型的类型适配器(或原则上共享相同概念的(反)序列化器),那么你有自己管理其实例化及其子字段。因此,当您反序列化最顶层的User
时,其id
和photos
会自行反序列化。请注意,Photo.Deserializer
在您明确请求gson.fromJson(..., Photo.class)
之后会被调用或隐式应用它(对于后者Gson默认使用内置策略,请参见ReflectiveTypeAdapterFactory
)反序列化语境。如果你不绑定User
,同样的原则会转到User.Deserializer
,因此Gson使用ReflectiveTypeAdapterFactory.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)
);
}
}
}
我假设代码中的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:// .....