Supported Types

Supported Types

A @JSON type’s members can be scalars, collections, enums, java.time types, or other @JSON types. This page is the authoritative list of what’s supported.

Scalars

Java typeJSON wire form
boolean / Booleantrue / false
byte, short, int, long (and boxed)integer
float, double (and boxed)number
BigIntegerinteger (unbounded)
BigDecimalnumber (precision preserved)
Stringstring
UUIDstring — canonical 8-4-4-4-12 form
any enumstring — the constant’s name()
Instant, LocalDate, LocalDateTime, OffsetDateTime, ZonedDateTime, Duration, Periodstring — ISO-8601 (see Dates & Times)
@JSON
public record Bag(BigInteger big, BigDecimal money) {}

@JSON
public record Ids(UUID id, Color color) {}   // Color is an enum

Boxed numeric types and reference types accept null; whether a null is written depends on @JSON(omitNulls).

Enums

An enum member is written as its constant name and parsed back with Enum.valueOf. An unknown constant name on input throws JSONProcessingException.

public enum Color { RED, GREEN, BLUE }

Color.GREEN ⇄ "GREEN".

Collections

Three container types are supported. Each element or value type must itself be supported — a scalar, enum, java.time type, @JSON type, or another collection. A Map<String, Object> is a special case that holds arbitrary JSON values.

Java typeJSONDeserialized intoNotes
List<E>arrayArrayList<E>
Set<E>arrayLinkedHashSet<E>insertion order preserved; dedups
Map<K, V>objectLinkedHashMap<K, V>insertion order preserved
@JSON
public record Lists(List<String> tags, List<Integer> nums, List<UUID> ids) {}

@JSON
public record Maps(Map<String, Integer> counts, Map<UUID, String> labels) {}
{
  "tags": ["a", "b"],
  "nums": [1, 2, 3],
  "ids": ["00000000-0000-0000-0000-000000000001"]
}

Map keys

Because JSON object keys are always strings, a Map key must be a type with a canonical string form: String, UUID, any enum, or a java.time type. Enum keys use name(); java.time keys use their ISO string.

@JSON
public record KeyedMaps(Map<Color, Integer> byColor, Map<Instant, String> byTime) {}

Nested collections

Collections nest to any depth — a list of lists, a map of lists, a map of maps, and so on. Each level follows the same rules (map keys must still be string-form; leaves must be supported types), and the whole structure round-trips.

@JSON
public record Catalog(Map<String, List<Product>> byCategory, List<List<String>> grid) {}

@JSON
public record Warehouse(
    Map<Region, Set<Product>> stock,                       // enum-keyed map of sets
    Map<String, Map<String, Product>> index,               // map of maps
    Map<String, List<Map<Instant, Integer>>> series) {}    // arbitrarily deep
{
  "byCategory": {
    "tools": [
      {"sku": "a"},
      {"sku": "b"}
    ],
    "toys": []
  },
  "grid": [
    ["x"],
    ["y", "z"]
  ]
}

Nested @JSON types

A member may be another @JSON type — directly, as a collection element, or as a map value. Each nested type just needs its own @JSON annotation (and must live in the same module). Nesting composes to any depth, including recursively.

@JSON
public record Address(String city, String zip) {}

@JSON
public record User(String name, Address address, List<Address> previous) {}
{
  "name": "alice",
  "address": {
    "city": "Denver",
    "zip": "80202"
  },
  "previous": []
}

Dynamic objects

A member typed Map<String, Object> (without @JSONCatchAll) holds an arbitrary JSON object under its own key — useful for free-form or schema-less data you don’t want to model field-by-field.

@JSON
public record Settings(String id, Map<String, Object> prefs) {}
{
  "id": "1",
  "prefs": {
    "theme": "dark",
    "retries": 3,
    "nested": {
      "on": true
    },
    "tags": [1, "x"]
  }
}

The nested object is captured into a LinkedHashMap of natural Java shapes, preserving insertion order:

JSON valueJava value
stringString
integer (≤ 18 digits)Long
integer (> 18 digits)BigInteger
number with . / exponentBigDecimal
true / falseBoolean
nullnull
objectLinkedHashMap<String, Object>
arrayArrayList<Object>

On serialize, the member is written as a nested object under its own (naming-strategy-applied) wire key — not spread at the top level like a catch-all. Null entries follow the type’s omitNulls setting, and the value round-trips byte-for-byte.

A type may declare any number of dynamic-object members and may also combine them with a catch-all. The values are always the natural shapes above — they’re never reconstructed into nested @JSON types. If you want typed values, use Map<String, SomeType> where SomeType is itself @JSON.

Not supported in this release

These are rejected at compile time with a clear error, rather than failing at runtime:

  • Non-string-form map keys — Map<Integer, V>, Map<SomeClass, V>, etc. (at any nesting level).
  • Raw or wildcard type arguments — List (no type argument), List<?>, Map<String, ? extends Number>.