google/gson · error · IllegalArgumentException

Type adapter " + typeAdapter.getClass().getName() + " must i

Error message

Type adapter " + typeAdapter.getClass().getName() + " must implement JsonSerializer or JsonDeserializer

What it means

Thrown by TreeTypeAdapter.SingleTypeFactory when an object registered as a type adapter (via TreeTypeAdapter.newFactory / newTypeHierarchyFactory) implements neither JsonSerializer nor JsonDeserializer. Gson requires the legacy 'tree adapter' object to implement at least one of these interfaces; an IllegalArgumentException is raised at factory construction time (often when Gson is built).

Source

Thrown at gson/src/main/java/com/google/gson/internal/bind/TreeTypeAdapter.java:167

      Class<?> hierarchyType, Object typeAdapter) {
    return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);
  }

  private static final class SingleTypeFactory implements TypeAdapterFactory {
    private final TypeToken<?> exactType;
    private final boolean matchRawType;
    private final Class<?> hierarchyType;
    private final JsonSerializer<?> serializer;
    private final JsonDeserializer<?> deserializer;

    SingleTypeFactory(
        Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, Class<?> hierarchyType) {
      serializer = typeAdapter instanceof JsonSerializer ? (JsonSerializer<?>) typeAdapter : null;
      deserializer =
          typeAdapter instanceof JsonDeserializer ? (JsonDeserializer<?>) typeAdapter : null;
      if (serializer == null && deserializer == null) {
        Objects.requireNonNull(typeAdapter);
        throw new IllegalArgumentException(
            "Type adapter "
                + typeAdapter.getClass().getName()
                + " must implement JsonSerializer or JsonDeserializer");
      }
      this.exactType = exactType;
      this.matchRawType = matchRawType;
      this.hierarchyType = hierarchyType;
    }

    @SuppressWarnings("unchecked") // guarded by typeToken.equals() call
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      boolean matches =
          exactType != null
              ? exactType.equals(type) || (matchRawType && exactType.getType() == type.getRawType())
              : hierarchyType.isAssignableFrom(type.getRawType());
      return matches
          ? new TreeTypeAdapter<>(

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Make the registered object implement JsonSerializer<T> and/or JsonDeserializer<T>.
  2. If it is a modern TypeAdapter, use GsonBuilder.registerTypeAdapter (or a TypeAdapterFactory) instead of TreeTypeAdapter.newFactory.
  3. Double-check the generic type parameter matches the TypeToken passed to newFactory.

Example fix

// before
TreeTypeAdapter.newFactory(TypeToken.get(Foo.class), new FooTypeAdapter());
// FooTypeAdapter extends TypeAdapter<Foo> only -> throws

// after: implement the legacy interfaces, or register as TypeAdapter
class FooSerializer implements JsonSerializer<Foo> {
  public JsonElement serialize(Foo src, Type t, JsonSerializationContext c) {
    return c.serialize(src.name);
  }
}
// or simpler: gsonBuilder.registerTypeAdapter(Foo.class, new FooTypeAdapter());
Defensive patterns

Strategy: validation

Validate before calling

// Verify the adapter object implements a supported interface at registration time
Object adapter = new FooTypeAdapter();
if (!(adapter instanceof JsonSerializer) && !(adapter instanceof JsonDeserializer)) {
  throw new IllegalArgumentException(adapter.getClass().getName()
    + " must implement JsonSerializer or JsonDeserializer for TreeTypeAdapter.newFactory");
}
TreeTypeAdapter.newFactory(TypeToken.get(Foo.class), adapter);

Type guard

// Guard: prefer the modern TypeAdapter registration path when applicable
static boolean isTreeAdapterCompatible(Object o) {
  return o instanceof JsonSerializer || o instanceof JsonDeserializer;
}

Try / catch

null

Prevention

When it happens

Trigger: Calling TreeTypeAdapter.newFactory(TypeToken, Object), newFactoryWithMatchRawType, or newTypeHierarchyFactory with an object that is a plain TypeAdapter (new style) or arbitrary class. The factory at line 165 detects serializer==null && deserializer==null and throws.

Common situations: Migrating from old Gson where adapters were JsonSerializer/JsonDeserializer to the modern TypeAdapter API and passing the wrong kind of object into a tree factory; copy-paste errors; passing a lambda that does not implement the right interface; accidental null-like adapter wrappers.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/378090e77fd03ae5.json. Report an issue: GitHub.