Home > Back-end >  Can't perform polymorphic deserialization of nested collections using Moshi PolymorphicJsonAdap
Can't perform polymorphic deserialization of nested collections using Moshi PolymorphicJsonAdap

Time:02-05

Complex nested Data types won't deserialize to intended classes using a standard approach.

As of now, I have this working code, which deserializes json to Map<String, ? extends T> structure:

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

What I actually need to deserialize is Map<String, List<? extends T>>, but this code

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

however gives me the correct structure - Map with String keys and List values, but inside of those lists instead of subclasses' instances, I receive Gson's LinkedHashTreeMap with "type" property storing the actual class. I couldn't find an example for deserializing nested collections. What do I need to add?

CodePudding user response:

It seems that to deserialize nested collections we have to pass nested parametrized types to the adapter. After changing this

ParameterizedType type = Types.newParameterizedType(Map.class, String.class, List.class, baseType);
ParameterizedType type = Types.newParameterizedType(Map.class, String.class, Types.newParameterizedType(List.class, baseType));

I now have a working solution - I get a Map with List<? extends T> values, where values are actual descendants of a common ancestor and not LinkedHashTreeMaps.

  • Related