google/gson · error · UnsupportedOperationException

Attempted to deserialize a java.lang.Class. Forgot to regist

Error message

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

What it means

The built-in CLASS TypeAdapter refuses to deserialize a java.lang.Class. Reading a Class reference from arbitrary JSON is unsafe (effectively Class.forName on attacker-controlled input) so Gson blocks it with UnsupportedOperationException unless the user explicitly registers a TypeAdapter<Class>. Thrown on read at line 81.

Source

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

    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);

  public static final TypeAdapter<BitSet> BIT_SET =
      new TypeAdapter<BitSet>() {
        @Override
        public BitSet read(JsonReader in) throws IOException {
          BitSet bitset = new BitSet();
          in.beginArray();
          int i = 0;
          JsonToken tokenType = in.peek();
          while (tokenType != JsonToken.END_ARRAY) {
            boolean set;

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Register a custom, security-conscious TypeAdapter<Class<?>> that validates allowed class names before Class.forName.
  2. Replace the Class field with a String identifier and resolve the class through a controlled lookup.
  3. Exclude the Class field from deserialization (transient / @Expose(deserialize=false)).
  4. Use RuntimeTypeAdapterFactory for polymorphic typing instead of carrying Class in JSON.

Example fix

// before
class Job { Class<? extends Task> taskType; }
gson.fromJson(json, Job.class); // throws on read

// after
class Job { String taskTypeName; }
// resolve later via a whitelist
Class<? extends Task> resolve(Job j) {
  return ALLOWED.get(j.taskTypeName);
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject incoming JSON targeting a Class field before deserialization
if (targetTypeHasClassField(MyType.class) && jsonContainsValueAtClassField(json)) {
  throw new IllegalArgumentException("Refusing to deserialize Class from JSON");
}

Type guard

null

Try / catch

try {
  gson.fromJson(json, Job.class);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Attempted to deserialize a java.lang.Class")) {
    // register a whitelisting Class adapter if you truly need this
  } else throw e;
}

Prevention

When it happens

Trigger: Deserializing JSON into a type that has a Class<?> field when the JSON contains a value at that position, and no custom Class adapter is registered. Also triggered by fromJson targeting a Class directly (gson.fromJson(json, Class.class)).

Common situations: Round-tripping serialized DTOs that include a Class field; deserializing config that references handler classes by type; frameworks that embed type metadata; polymorphic dispatch attempted via a Class field instead of a RuntimeTypeAdapterFactory.

Related errors


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