google/gson · error · IllegalArgumentException

Type adapter ${className} must implement JsonSerializer or J

Error message

Type adapter ${className} must implement JsonSerializer or JsonDeserializer

What it means

TreeTypeAdapter.SingleTypeFactory wraps an object as a JsonSerializer and/or JsonDeserializer. If the object implements neither interface, the factory has no serialization or deserialization logic and rejects it with IllegalArgumentException. Through GsonBuilder.registerTypeAdapter a separate pre-check fires first, so this specific message surfaces when the factory is created directly.

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 310ac341f2)

Solutions

  1. If the object is a JsonSerializer or JsonDeserializer, ensure it correctly implements the interface generics
  2. If the object is a TypeAdapter, use TypeAdapters.newFactory instead of TreeTypeAdapter.newFactory
  3. Route adapter registration through GsonBuilder.registerTypeAdapter which validates and dispatches to the correct factory type

Example fix

// before — TypeAdapter passed to TreeTypeAdapter factory
TypeAdapter<MyType> adapter = ...;
factory = TreeTypeAdapter.newFactory(TypeToken.get(MyType.class), adapter); // throws

// after — use the correct factory for TypeAdapter
factory = TypeAdapters.newFactory(TypeToken.get(MyType.class), adapter);
Defensive patterns

Strategy: validation

Validate before calling

// Validate before creating a TreeTypeAdapter factory
public static void validateAdapter(Object adapter) {
    if (!(adapter instanceof JsonSerializer<?>) && !(adapter instanceof JsonDeserializer<?>)) {
        throw new IllegalArgumentException(
            adapter.getClass().getName() + " must implement JsonSerializer or JsonDeserializer");
    }
}

Prevention

When it happens

Trigger: Directly calling TreeTypeAdapter.newFactory, newFactoryWithMatchRawType, or newTypeHierarchyFactory with an object that does not implement JsonSerializer or JsonDeserializer; passing a TypeAdapter or plain object to a TreeTypeAdapter factory API instead of the TypeAdapter factory API.

Common situations: Library or framework code that programmatically constructs TreeTypeAdapter factories; misuse of the internal TreeTypeAdapter API instead of GsonBuilder.registerTypeAdapter.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/4c6406035df3d479. Report an issue: GitHub.