{"id":"378090e77fd03ae5","repo":"google/gson","slug":"type-adapter-typeadapter-getclass-getname","errorCode":null,"errorMessage":"Type adapter \" + typeAdapter.getClass().getName() + \" must implement JsonSerializer or JsonDeserializer","messagePattern":"Type adapter \" \\+ typeAdapter\\.getClass\\(\\)\\.getName\\(\\) \\+ \" must implement JsonSerializer or JsonDeserializer","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/TreeTypeAdapter.java","lineNumber":167,"sourceCode":"      Class<?> hierarchyType, Object typeAdapter) {\n    return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);\n  }\n\n  private static final class SingleTypeFactory implements TypeAdapterFactory {\n    private final TypeToken<?> exactType;\n    private final boolean matchRawType;\n    private final Class<?> hierarchyType;\n    private final JsonSerializer<?> serializer;\n    private final JsonDeserializer<?> deserializer;\n\n    SingleTypeFactory(\n        Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, Class<?> hierarchyType) {\n      serializer = typeAdapter instanceof JsonSerializer ? (JsonSerializer<?>) typeAdapter : null;\n      deserializer =\n          typeAdapter instanceof JsonDeserializer ? (JsonDeserializer<?>) typeAdapter : null;\n      if (serializer == null && deserializer == null) {\n        Objects.requireNonNull(typeAdapter);\n        throw new IllegalArgumentException(\n            \"Type adapter \"\n                + typeAdapter.getClass().getName()\n                + \" must implement JsonSerializer or JsonDeserializer\");\n      }\n      this.exactType = exactType;\n      this.matchRawType = matchRawType;\n      this.hierarchyType = hierarchyType;\n    }\n\n    @SuppressWarnings(\"unchecked\") // guarded by typeToken.equals() call\n    @Override\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {\n      boolean matches =\n          exactType != null\n              ? exactType.equals(type) || (matchRawType && exactType.getType() == type.getRawType())\n              : hierarchyType.isAssignableFrom(type.getRawType());\n      return matches\n          ? new TreeTypeAdapter<>(","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/TreeTypeAdapter.java#L149-L185","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the registered object implement JsonSerializer<T> and/or JsonDeserializer<T>.","If it is a modern TypeAdapter, use GsonBuilder.registerTypeAdapter (or a TypeAdapterFactory) instead of TreeTypeAdapter.newFactory.","Double-check the generic type parameter matches the TypeToken passed to newFactory."],"exampleFix":"// before\nTreeTypeAdapter.newFactory(TypeToken.get(Foo.class), new FooTypeAdapter());\n// FooTypeAdapter extends TypeAdapter<Foo> only -> throws\n\n// after: implement the legacy interfaces, or register as TypeAdapter\nclass FooSerializer implements JsonSerializer<Foo> {\n  public JsonElement serialize(Foo src, Type t, JsonSerializationContext c) {\n    return c.serialize(src.name);\n  }\n}\n// or simpler: gsonBuilder.registerTypeAdapter(Foo.class, new FooTypeAdapter());","handlingStrategy":"validation","validationCode":"// Verify the adapter object implements a supported interface at registration time\nObject adapter = new FooTypeAdapter();\nif (!(adapter instanceof JsonSerializer) && !(adapter instanceof JsonDeserializer)) {\n  throw new IllegalArgumentException(adapter.getClass().getName()\n    + \" must implement JsonSerializer or JsonDeserializer for TreeTypeAdapter.newFactory\");\n}\nTreeTypeAdapter.newFactory(TypeToken.get(Foo.class), adapter);","typeGuard":"// Guard: prefer the modern TypeAdapter registration path when applicable\nstatic boolean isTreeAdapterCompatible(Object o) {\n  return o instanceof JsonSerializer || o instanceof JsonDeserializer;\n}","tryCatchPattern":"null","preventionTips":["Use GsonBuilder.registerTypeAdapter for modern TypeAdapter instances; reserve TreeTypeAdapter factories for JsonSerializer/JsonDeserializer.","Add a startup check that all custom factories build successfully.","Document the interface requirement on adapter helpers."],"tags":["gson","typeadapter","jsonserializer","jsondeserializer","factory"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}