google/gson · error · UnsupportedOperationException

Attempted to serialize java.lang.Class: " + value.getName()

Error message

Attempted to serialize java.lang.Class: " + value.getName() + ". Forgot to register a type adapter?\nSee " + TroubleshootingGuide.createUrl("java-lang-class-unsupported")

What it means

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.

Source

Thrown at gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java:71

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.regex.Pattern;

/**
 * Type adapters for basic types. More complex adapters exist as separate classes in the enclosing
 * package.
 */
public final class TypeAdapters {
  private TypeAdapters() {
    throw new UnsupportedOperationException();
  }

  @SuppressWarnings("rawtypes")
  public static final TypeAdapter<Class> CLASS =
      new TypeAdapter<Class>() {
        @Override
        public void write(JsonWriter out, Class value) throws IOException {
          throw new UnsupportedOperationException(
              "Attempted to serialize java.lang.Class: "
                  + value.getName()
                  + ". Forgot to register a type adapter?"
                  + "\nSee "
                  + TroubleshootingGuide.createUrl("java-lang-class-unsupported"));
        }

        @Override
        public Class read(JsonReader in) throws IOException {
          throw new UnsupportedOperationException(
              "Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?"
                  + "\nSee "
                  + TroubleshootingGuide.createUrl("java-lang-class-unsupported"));
        }
      }.nullSafe();

  public static final TypeAdapterFactory CLASS_FACTORY = newFactory(Class.class, CLASS);

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Register a custom TypeAdapter<Class<?>> that serializes the class name (or omits it).
  2. Remove the Class<?> field from the serialized type, or mark it transient.
  3. Exclude it with @Expose(serialize=false) under excludeFieldsWithoutExposeAnnotation.
  4. Replace the Class<?> field with a String holding the fully-qualified name.

Example fix

// before
class ErrorReport { Class<? extends Throwable> type; String msg; }
gson.toJson(report); // UnsupportedOperationException

// after
class ErrorReport { String typeName; String msg; }
// or register adapter
registerTypeAdapter(Class.class, new TypeAdapter<Class<?>>() {
  public void write(JsonWriter w, Class<?> c) throws IOException { w.value(c.getName()); }
  public Class<?> read(JsonReader r) throws IOException {
    try { return Class.forName(r.nextString()); }
    catch (ClassNotFoundException e) { throw new JsonIOException(e); }
  }
}.nullSafe());
Defensive patterns

Strategy: validation

Validate before calling

// Detect Class-typed fields before serializing
for (Field f : obj.getClass().getDeclaredFields()) {
  if (f.getType() == Class.class && !Modifier.isTransient(f.getModifiers())) {
    throw new IllegalStateException("Will fail: Class field " + f + " not transient and no adapter");
  }
}

Type guard

// Avoid carrying Class in serializable types
static boolean hasClassField(Class<?> c) {
  for (Field f : c.getDeclaredFields()) if (f.getType()==Class.class) return true;
  return false;
}

Try / catch

try {
  gson.toJson(obj);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Attempted to serialize java.lang.Class")) {
    // register a Class adapter and retry, or drop the field
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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