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

Java JsonSerializer不适用于使用GSON的嵌套对象,java,json,serialization,gson,android,Java,Json,Serialization,Gson,Android,我有一个json对象,如下所示: { "user": { "id": 1234 ... "photos": [ { "url": "http://....." ... }, { "url": "http://....." ...

我有一个json对象,如下所示:

{
    "user": {
        "id": 1234
        ... 
        "photos": [
            {
                "url": "http://....."
                ...
            },
            {
                "url": "http://....."
                ...
            }
        ]
    }
}
{
    "photos": [
         {
             "url": "http://....."
              ...
         },
         {
             "url": "http://....."
              ...
         },
         {
             "url": "http://....."
              ...
         }
]
我想为用户和照片编写一个自定义反序列化程序

因此,我:

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 
    }  
}
但是,当我反序列化用户类时,它会命中用户的反序列化器,但不会命中照片的反序列化器。但是如果我得到一个json,其中photo对象没有嵌套在用户json对象中,如下所示:

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

它将正确地命中照片的反序列化程序

我认为这些类与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://....." }
            ]
        }
    }
}
最后,jason回应:

public class User {
    private int id;
    ...
    private ArrayList<Photo> photos;
} 

public class Photo{
    private String url;
}

简言之,有一个非形式化规则:一旦您声明了一个类型适配器或反序列化器,该适配器或反序列化器原则上对某个类型共享相同的概念,那么您必须自己管理其实例化及其子字段。因此,当您反序列化排名靠前的用户时,其id和照片将自行反序列化。请注意,Photo.Deserializer会在您显式请求它(如gson.fromJson…、Photo.class)时调用,或者隐式应用它(对于后者),默认情况下,gson使用内置策略,请参阅ReflectTypeAdapterFactory,例如通过反序列化上下文。如果不绑定User.Deserializer,则相同的原则也适用于User,因此Gson使用ReflectTypeAdapterFactory.Adapter,它只使用反射遍历所有字段本身。更简短的是:至少在默认情况下,Gson不会合并多个策略,因此您可以将对象构造和设置委托给Gson,或者完全实例化它

知道了这一点,User.Deserializer可以按如下方式实现:

最终类用户{ 最终长id; 最后名单照片; 私人用户最终长id,最终列表照片{ this.id=id; this.photos=照片; } 静态最终类反序列化器 实现JsonDeserializer{ 私有静态最终类型photoListType=新类型令牌{ }.getType; @凌驾 公共用户反序列化最终JsonElement JsonElement、最终类型类型、最终JSONESerializationContext上下文{ //请注意,您必须首先选择属性 最终JsonObject JsonObject=jsonElement.getAsJsonObject; 返回新用户 //然后将它们委托给指定目标类型的反序列化上下文 context.deserializejsonObject.getid,long.class, //您可以递归地解构JsonElement,但反序列化上下文尊重使用GsonBuilder构建的Gson上下文 //这也会触发Photo.Deserializer context.deserializejsonObject.getphotos,photoListType ; } } } 我假设你代码中的照片是一个打字错误,应该是照片。如果不是,则可能会为照片实施类似的解决方案

期末照{ 最终字符串url; 私有最终字符串url{ this.url=url; } 静态最终类反序列化器 实现JsonDeserializer{ @凌驾 公共照片反序列化最终JsonElement JsonElement、最终类型类型、最终JSONESerializationContext上下文{ 最终JsonObject JsonObject=jsonElement.getAsJsonObject; 返回新照片 //jsonObject.geturl.getAsString可以更简单,但它不尊重Gson实例配置 context.deserializejsonObject.geturl,String.class ; } } } 如何使用它:

最终类包装器{ 最终用户; 私有包装器最终用户{ this.user=用户; } } 最终Gson Gson=新的GsonBuilder .registerTypeAdapterUser.class,新用户.Deserializer .registerTypeAdapterPhoto.class,新照片.反序列化器 创造 final Wrapper=gson.fromJsonJSON,Wrapper.class; System.out.printlnwrapper.user.id; wrapper.user.photos.forEachp->System.out.printlnp.url; 输出:

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


对不起,这是示例中的一个错误。我对其进行了更新,使其符合我的java类。否则它会影响反序列化程序,所以我认为代码可以正常工作。它只是从另一个反序列化程序调用它,这似乎是一个问题,它说照片,它真的是照片。这是一个打字错误。不是两个不同的类别。对吗?你能告诉我为什么这个案例需要自定义反序列化程序吗?我上面给出的例子非常简单。我在我的应用程序中使用的对象要复杂得多。嗨,我在GitHub上看到了你的问题:-你能关闭它吗,因为你知道Gson类型适配器现在是如何工作的?谢谢。啊,这就是我害怕的。而且你提到的多种策略没有合并的方法default@Sree是的,这是简单的代价。例c
ustom类型适配器工厂可用于将一些策略合并在一起:-先委托,然后以某种方式进行后期处理。换句话说,您只需要为父类型声明类型适配器-子类型适配器将是冗余的?