使用Moshi PolymorphicJsonAdapterFactory反序列化嵌套集合遇问题
复杂嵌套数据类型无法通过标准方法反序列化为目标类。现有一段可正常运行的代码,能将JSON反序列化为Map<String, ? extends T>结构:
private static <T> Map<String, ? extends T> deserializeTypeAdaptableJson(Class<T> baseType, List<Class<? extends T>> subclasses, String json) { PolymorphicJsonAdapterFactory<T> factory = PolymorphicJsonAdapterFactory.of(baseType, "type"); for (Class<? extends T> subclass : subclasses) { factory = factory.withSubtype(subclass, subclass.getSimpleName()); } Moshi moshi = new Moshi.Builder().add(factory).build(); ParameterizedType type = Types.newParameterizedType(Map.class, String.class, baseType); JsonAdapter<Map<String, ? extends T>> adapter = moshi.adapter(type); return adapter.fromJson(json); }
实际需要反序列化的是Map<String, List<? extends T>>,修改后的代码如下:
private static <T> Map<String, List<? extends T>> deserializeTypeAdaptableJson(Class<T> baseType, List<Class<? extends T>> subclasses, String json) { PolymorphicJsonAdapterFactory<T> factory = PolymorphicJsonAdapterFactory.of(baseType, "type"); for (Class<? extends T> subclass : subclasses) { factory = factory.withSubtype(subclass, subclass.getSimpleName()); } Moshi moshi = new Moshi.Builder().add(factory).build(); ParameterizedType type = Types.newParameterizedType(Map.class, String.class, List.class, baseType); JsonAdapter<Map<String, List<? extends T>>> adapter = moshi.adapter(type); return adapter.fromJson(json); }
虽然能得到正确的Map结构(键为String,值为List),但列表内的元素并非子类实例,而是带有"type"属性的Gson LinkedHashTreeMap。未找到嵌套集合反序列化的示例,请问需要添加什么配置?
问题出在Types.newParameterizedType的使用逻辑上,需要先创建嵌套的List参数化类型,再将其作为Map的值类型传入,而非直接把List.class和baseType并列传入。
修改后的完整代码
private static <T> Map<String, List<? extends T>> deserializeTypeAdaptableJson(Class<T> baseType, List<Class<? extends T>> subclasses, String json) { PolymorphicJsonAdapterFactory<T> factory = PolymorphicJsonAdapterFactory.of(baseType, "type"); for (Class<? extends T> subclass : subclasses) { factory = factory.withSubtype(subclass, subclass.getSimpleName()); } Moshi moshi = new Moshi.Builder().add(factory).build(); // 先构建List<? extends T>对应的参数化类型 ParameterizedType listType = Types.newParameterizedType(List.class, baseType); // 再构建Map<String, List<? extends T>>的参数化类型 ParameterizedType mapType = Types.newParameterizedType(Map.class, String.class, listType); JsonAdapter<Map<String, List<? extends T>>> adapter = moshi.adapter(mapType); return adapter.fromJson(json); }
原理说明
原代码中Types.newParameterizedType(Map.class, String.class, List.class, baseType)的写法不符合方法规则:该方法第一个参数是主类型,后续参数是主类型的泛型参数。Map的泛型参数仅为2个(Key和Value),传入3个参数会导致Moshi无法识别List内部的泛型类型,无法应用多态适配器,最终只能将列表元素反序列化为默认的LinkedHashTreeMap。
通过先构建List的参数化类型,再将其作为Map的Value类型传入,Moshi就能正确识别List内部需要反序列化的泛型类型,从而应用配置的PolymorphicJsonAdapterFactory,将列表元素正确反序列化为对应的子类实例。
内容的提问来源于stack exchange,提问作者wanderbild

