Skip to content

AtomicIntegerArray deserializer crashes on JSON null (IllegalStateException) — symmetric fix to #3038 #3047

Description

@greymoth-jp

Bug

Deserializing a JSON array that contains a null element into an AtomicIntegerArray crashes with an uncaught IllegalStateException:

new Gson().fromJson("[1,null,3]", AtomicIntegerArray.class);
// throws IllegalStateException: Expected an int but was NULL at line 1 column 4 path $[1]

Root cause

In TypeAdapters.java, the ATOMIC_INTEGER_ARRAY adapter's read() method calls in.nextInt() inside a loop that only catches NumberFormatException:

public AtomicIntegerArray read(JsonReader in) throws IOException {
  List<Integer> list = new ArrayList<>();
  in.beginArray();
  while (in.hasNext()) {
    try {
      int integer = in.nextInt();
      list.add(integer);
    } catch (NumberFormatException e) {
      throw new JsonSyntaxException(e);
    }
  }
  in.endArray();
  ...
}

When the JsonReader is positioned at a NULL token, nextInt() throws IllegalStateException — which is not caught here, so it propagates raw instead of being converted to a JsonSyntaxException.

Relationship to #3038

PR #3038 (merged 2026-06-22) fixed the symmetric issue in AtomicLongArray. That adapter delegates to longAdapter.read(in), which returns null for a JSON null; the fix added an explicit null-check:

Number value = longAdapter.read(in);
if (value == null) {
  throw new JsonSyntaxException("null is not a valid AtomicLongArray element");
}
list.add(value.longValue());

AtomicIntegerArray was not updated with the same treatment.

Expected behaviour

A JSON null element inside an AtomicIntegerArray should throw a JsonSyntaxException (same as AtomicLongArray after #3038), not a raw IllegalStateException.

Suggested fix

Mirror the approach used in the AtomicLongArray adapter — either:

Option A — peek before reading:

while (in.hasNext()) {
  try {
    if (in.peek() == com.google.gson.stream.JsonToken.NULL) {
      throw new JsonSyntaxException("null is not a valid AtomicIntegerArray element");
    }
    int integer = in.nextInt();
    list.add(integer);
  } catch (NumberFormatException e) {
    throw new JsonSyntaxException(e);
  }
}

Option B — delegate to INTEGER type adapter (returns null for JSON null, already handles this safely) and add a null-check, consistent with the AtomicLongArray pattern.

A regression test analogous to the one added in #3038 for AtomicLongArray should also be added.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions