google/gson · error · UnsupportedOperationException

Attempted to serialize java.lang.Class: ${className}. Forgot

Error message

Attempted to serialize java.lang.Class: ${className}. Forgot to register a type adapter?
See ${url}

What it means

Gson registers a built-in CLASS adapter that throws UnsupportedOperationException on write because serializing a java.lang.Class object is not meaningful. The adapter fires whenever Gson encounters a Class field during serialization and no custom adapter was registered.

Source

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

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

Solutions

  1. Mark the Class field with transient or @Expose(serialize = false) to exclude it from serialization
  2. Register a custom JsonSerializer<Class<?>> that serializes the class name as a string
  3. Remove the Class field from the model if it should not appear in JSON

Example fix

// before
class Entity {
    String name;
    Class<?> type; // causes UnsupportedOperationException on serialize
}

// after
class Entity {
    String name;
    @Expose(serialize = false)
    transient Class<?> type;
}
Defensive patterns

Strategy: validation

Validate before calling

// Check model classes for Class fields before serializing
public static boolean hasClassField(Class<?> type) {
    for (Field f : type.getDeclaredFields()) {
        if (f.getType() == Class.class && !Modifier.isTransient(f.getModifiers())) {
            return true; // will trigger UnsupportedOperationException on serialize
        }
    }
    return false;
}

Try / catch

try {
    String json = gson.toJson(obj);
} catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("Attempted to serialize java.lang.Class")) {
        // register a TypeAdapter<Class<?>> or mark the field transient
    }
}

Prevention

When it happens

Trigger: Serializing an object that has a field of type Class<?> (e.g. Class<?> type) via gson.toJson() without registering a custom TypeAdapter for Class.

Common situations: Domain models that store a Class reference for runtime type checks; ORM entities with a discriminator class field; accidentally including a Class field in a serializable DTO.

Related errors


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