{"record":{"id":"4c6406035df3d479","repo":"google/gson","slug":"type-adapter-classname-must-implement-jsonseria","errorCode":null,"errorMessage":"Type adapter ${className} must implement JsonSerializer or JsonDeserializer","messagePattern":"Type adapter (.+?) 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/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/TreeTypeAdapter.java#L149-L185","documentation":"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.","triggerScenarios":"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.","commonSituations":"Library or framework code that programmatically constructs TreeTypeAdapter factories; misuse of the internal TreeTypeAdapter API instead of GsonBuilder.registerTypeAdapter.","solutions":["If the object is a JsonSerializer or JsonDeserializer, ensure it correctly implements the interface generics","If the object is a TypeAdapter, use TypeAdapters.newFactory instead of TreeTypeAdapter.newFactory","Route adapter registration through GsonBuilder.registerTypeAdapter which validates and dispatches to the correct factory type"],"exampleFix":"// before — TypeAdapter passed to TreeTypeAdapter factory\nTypeAdapter<MyType> adapter = ...;\nfactory = TreeTypeAdapter.newFactory(TypeToken.get(MyType.class), adapter); // throws\n\n// after — use the correct factory for TypeAdapter\nfactory = TypeAdapters.newFactory(TypeToken.get(MyType.class), adapter);","handlingStrategy":"validation","validationCode":"// Validate before creating a TreeTypeAdapter factory\npublic static void validateAdapter(Object adapter) {\n    if (!(adapter instanceof JsonSerializer<?>) && !(adapter instanceof JsonDeserializer<?>)) {\n        throw new IllegalArgumentException(\n            adapter.getClass().getName() + \" must implement JsonSerializer or JsonDeserializer\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Route all adapter registration through GsonBuilder.registerTypeAdapter which validates the interface","For TypeAdapter objects, use TypeAdapters.newFactory, not TreeTypeAdapter.newFactory","Verify adapter classes implement the correct Gson interface before passing to any factory API"],"tags":["type-adapter","registration","configuration"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}