{"id":"4f4340ed4f802fd7","repo":"google/gson","slug":"attempted-to-serialize-java-lang-class-value","errorCode":null,"errorMessage":"Attempted to serialize java.lang.Class: \" + value.getName() + \". Forgot to register a type adapter?\\nSee \" + TroubleshootingGuide.createUrl(\"java-lang-class-unsupported\")","messagePattern":"Attempted to serialize java\\.lang\\.Class: \" \\+ value\\.getName\\(\\) \\+ \"\\. Forgot to register a type adapter\\?\\\\nSee \" \\+ TroubleshootingGuide\\.createUrl\\(\"java-lang-class-unsupported\"\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java","lineNumber":71,"sourceCode":"import java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.atomic.AtomicLongArray;\nimport java.util.regex.Pattern;\n\n/**\n * Type adapters for basic types. More complex adapters exist as separate classes in the enclosing\n * package.\n */\npublic final class TypeAdapters {\n  private TypeAdapters() {\n    throw new UnsupportedOperationException();\n  }\n\n  @SuppressWarnings(\"rawtypes\")\n  public static final TypeAdapter<Class> CLASS =\n      new TypeAdapter<Class>() {\n        @Override\n        public void write(JsonWriter out, Class value) throws IOException {\n          throw new UnsupportedOperationException(\n              \"Attempted to serialize java.lang.Class: \"\n                  + value.getName()\n                  + \". Forgot to register a type adapter?\"\n                  + \"\\nSee \"\n                  + TroubleshootingGuide.createUrl(\"java-lang-class-unsupported\"));\n        }\n\n        @Override\n        public Class read(JsonReader in) throws IOException {\n          throw new UnsupportedOperationException(\n              \"Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?\"\n                  + \"\\nSee \"\n                  + TroubleshootingGuide.createUrl(\"java-lang-class-unsupported\"));\n        }\n      }.nullSafe();\n\n  public static final TypeAdapterFactory CLASS_FACTORY = newFactory(Class.class, CLASS);\n","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L53-L89","documentation":"The built-in CLASS TypeAdapter (registered for java.lang.Class) refuses to serialize a Class object by throwing UnsupportedOperationException. Gson has no canonical textual representation for a Class reference, so serialization is intentionally blocked unless the user supplies a custom adapter. Thrown on write at line 71.","triggerScenarios":"A serializable object graph contains a field of type Class<?> (or Class) whose value is set to some Class reference, and no custom TypeAdapter<Class> is registered. Calling gson.toJson on such an object triggers CLASS.write. Also happens when serializing exceptions, proxies, or framework objects that carry a Class field.","commonSituations":"Logging/error DTOs holding `Class<? extends Exception> type`; ORM entities referencing entity types; reflection-heavy utilities; serializing Spring/Hibernate proxies or Throwable subclasses; forgetting that `Class` is a real serializable field type.","solutions":["Register a custom TypeAdapter<Class<?>> that serializes the class name (or omits it).","Remove the Class<?> field from the serialized type, or mark it transient.","Exclude it with @Expose(serialize=false) under excludeFieldsWithoutExposeAnnotation.","Replace the Class<?> field with a String holding the fully-qualified name."],"exampleFix":"// before\nclass ErrorReport { Class<? extends Throwable> type; String msg; }\ngson.toJson(report); // UnsupportedOperationException\n\n// after\nclass ErrorReport { String typeName; String msg; }\n// or register adapter\nregisterTypeAdapter(Class.class, new TypeAdapter<Class<?>>() {\n  public void write(JsonWriter w, Class<?> c) throws IOException { w.value(c.getName()); }\n  public Class<?> read(JsonReader r) throws IOException {\n    try { return Class.forName(r.nextString()); }\n    catch (ClassNotFoundException e) { throw new JsonIOException(e); }\n  }\n}.nullSafe());","handlingStrategy":"validation","validationCode":"// Detect Class-typed fields before serializing\nfor (Field f : obj.getClass().getDeclaredFields()) {\n  if (f.getType() == Class.class && !Modifier.isTransient(f.getModifiers())) {\n    throw new IllegalStateException(\"Will fail: Class field \" + f + \" not transient and no adapter\");\n  }\n}","typeGuard":"// Avoid carrying Class in serializable types\nstatic boolean hasClassField(Class<?> c) {\n  for (Field f : c.getDeclaredFields()) if (f.getType()==Class.class) return true;\n  return false;\n}","tryCatchPattern":"try {\n  gson.toJson(obj);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().startsWith(\"Attempted to serialize java.lang.Class\")) {\n    // register a Class adapter and retry, or drop the field\n  } else throw e;\n}","preventionTips":["Do not declare Class<?> fields on serialized DTOs; use a String type name.","Mark unavoidable Class fields transient.","Register a global TypeAdapter<Class<?>> if Class round-tripping is required.","Audit Throwable/Exception subclasses before serializing them."],"tags":["gson","serialization","class","unsupported","typeadapter"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}