Handling Type Mismatches and Heterogeneous List Parsing with Retrofit and Gson in Android

This article explains why Retrofit + Gson parsing can fail when server‑sent fields differ from client definitions or when lists contain heterogeneous item types, and demonstrates how to customize TypeAdapters and use @JsonAdapter to gracefully handle these scenarios in Android applications.

Beike Product & Technology
Beike Product & Technology
Beike Product & Technology
Handling Type Mismatches and Heterogeneous List Parsing with Retrofit and Gson in Android

1 Background

Android clients typically use Retrofit together with Gson for network request parsing. The minimal configuration is:

new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())

While this works for most data, two problems often arise:

Server‑sent field names or types do not match the client model, causing the whole parsing to fail.

Parsing of heterogeneous list items where each element may map to a different Java class.

Heterogeneous list means that each element in the list can be represented by a different Java entity.

The article explores the causes of these issues and provides solutions.

2 Prerequisite Knowledge

Retrofit + Gson parses JSON by reading the stream with JsonReader and delegating to the appropriate TypeAdapter. The essential steps are:

// Step 1: Create a usable Retrofit instance
new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())

// Step 2: Add a list of TypeAdapters
public static GsonConverterFactory create() {
    return create(new Gson());
}
// Gson() constructor registers built‑in TypeAdapters
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
factories.add(TypeAdapters.STRING_FACTORY);
... // other factories

// Step 3: When a response arrives, GsonConverterFactory intercepts it
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
}

// Step 4: Use the corresponding TypeAdapter to complete parsing
public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
        return adapter.read(jsonReader);
    } finally {
        value.close();
    }
}

These four snippets show that Retrofit + Gson reads the JSON string with JsonReader and uses the matching TypeAdapter for conversion.

3 Handling Server‑Client Field Type Incompatibility

By default, a mismatched field throws an exception and aborts parsing. To tolerate such mismatches, the read method of ReflectiveTypeAdapterFactory can be modified to skip problematic fields:

public T read(JsonReader in) throws IOException {
    try {
        while (in.hasNext()) {
            String name = in.nextName();
            BoundField field = boundFields.get(name);
            if (field == null || !field.deserialized) {
                in.skipValue();
            } else {
                try {
                    field.read(in, instance);
                } catch (Exception e) {
                    in.skipValue(); // skip the offending field
                }
            }
        }
    } catch (Exception e) {
        // Optional: log the error
        in.skipValue();
    }
    in.endObject();
    return instance;
}

This change catches any exception during field.read, skips the offending value, and continues parsing, preventing a total failure.

4 Heterogeneous List Parsing

Consider a JSON array where each element contains a type field indicating its concrete class:

{
  "list": [
    {"type": "a", ...},
    {"type": "b", ...},
    {"type": "c", ...}
  ]
}

Define a base class BaseCard with a cardType field, and let ACard, BCard, CCard extend it:

public class BaseCard {
    @SerializedName("type")
    private String cardType;
}

public class ACard extends BaseCard { }
public class BCard extends BaseCard { }
public class CCard extends BaseCard { }

Create a custom TypeAdapterFactory that maps each type value to the corresponding TypeAdapter and registers it in a map:

protected <T extends BaseTypeT> void addSubTypeAdapter(TypeAdapterFactory factory, Gson gson,
        String typeName, Class<T> subTypeClass) {
    mMap.put(typeName, new SubTypeReadWriteAdapter<>(
        gson.getDelegateAdapter(factory, TypeToken.get(subTypeClass))));
}

public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    return (TypeAdapter<T>) createTypeAdapter(gson);
}

public TypeAdapter<Card> createTypeAdapter(final Gson gson) {
    final TypeAdapterFactory factory = this;
    return new BaseTypeAdapter<Card>(gson, "type") {
        {
            addSubTypeAdapter(factory, gson, "a", ACard.class);
            addSubTypeAdapter(factory, gson, "b", BCard.class);
            addSubTypeAdapter(factory, gson, "c", CCard.class);
        }
    };
}

Annotate the base class with @JsonAdapter(DemoTypeAdapterFactory.class) so that Gson uses the custom factory:

@JsonAdapter(DemoTypeAdapterFactory.class)
public class BaseCard { ... }

With this setup, Gson can correctly deserialize a heterogeneous list by selecting the appropriate subclass based on the type field.

Overall, the article demonstrates how to extend Retrofit + Gson parsing to handle field‑type mismatches gracefully and to parse lists containing multiple concrete types using custom TypeAdapter implementations.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidparsingJSONGsonRetrofitHeterogeneous ListTypeAdapter
Beike Product & Technology
Written by

Beike Product & Technology

As Beike's official product and technology account, we are committed to building a platform for sharing Beike's product and technology insights, targeting internet/O2O developers and product professionals. We share high-quality original articles, tech salon events, and recruitment information weekly. Welcome to follow us.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.