json-path/JsonPath · error · IllegalArgumentException

Use map() method to databind a JsonObject

Error message

Use map() method to databind a JsonObject

What it means

JakartaMappingProvider.unwrapJsonValue() converts JSON-P JsonValue leaves (strings, numbers, booleans, arrays) into plain Java objects. When it encounters a JsonObject (a nested JSON object), it deliberately refuses and throws IllegalArgumentException, because objects cannot be safely auto-flattened and must instead be databound to a target class via the provider's map() method. This is an intentional design boundary, not a data corruption bug.

Source

Thrown at json-path/src/main/java/com/jayway/jsonpath/spi/mapper/JakartaMappingProvider.java:258

        String className = targetType.getSimpleName();
        throw new MappingException("JSON decimal number cannot be mapped to " + className);
    }

    private Object unwrapJsonValue(Object jsonValue) {
        if (jsonValue == null) {
            return null;
        }
        if (!(jsonValue instanceof JsonValue)) {
            return jsonValue;
        }
        switch (((JsonValue) jsonValue).getValueType()) {
        case ARRAY:
        	// TODO do we unwrap JsonObjectArray proxies?
            //return ((JsonArray) jsonValue).getValuesAs(JsonValue.class);
            return ((JsonArray) jsonValue).getValuesAs((JsonValue v) -> unwrapJsonValue(v));
        case OBJECT:
            throw new IllegalArgumentException("Use map() method to databind a JsonObject");
        case STRING:
            return ((JsonString) jsonValue).getString();
        case NUMBER:
            if (((JsonNumber) jsonValue).isIntegral()) {
                //return ((JsonNumber) jsonValue).bigIntegerValueExact();
                try {
                    return ((JsonNumber) jsonValue).intValueExact();
                } catch (ArithmeticException e) {
                    return ((JsonNumber) jsonValue).longValueExact();
                }
            } else {
                //return ((JsonNumber) jsonValue).bigDecimalValue();
                return ((JsonNumber) jsonValue).doubleValue();
            }
        case TRUE:
            return Boolean.TRUE;
        case FALSE:
            return Boolean.FALSE;

View on GitHub (pinned to 62a4c9f0f6)

Solutions

  1. Request a concrete target type so the map() databinding path is used: read("$.store.book[0]", Book.class) or read(path, new TypeRef<Map<String,Object>>(){}) instead of a bare read(path).
  2. If you want raw structure back, wrap the read in map(..., JsonValue.class) or obtain the underlying JsonObject directly from the JsonStructure document and navigate it with the JSON-P API.
  3. Cast/adjust code that assumed read(path) returns Map<String,Object> for object nodes; with this provider objects must be databound explicitly.
  4. As a last resort catch IllegalArgumentException and fall back to the databind path, but prefer fixing the read call.

Example fix

// before
Object book = jsonPath.read("$.store.book[0]"); // IllegalArgumentException: Use map() method to databind a JsonObject
// after
Map<String, Object> book = jsonPath.read("$.store.book[0]", new TypeRef<Map<String, Object>>() {});
Defensive patterns

Strategy: type-guard

Validate before calling

JsonValue v = (JsonValue) jsonPath.json();
if (((JsonObject) ((JsonArray) v).getValue(0)).getValueType() == JsonValue.ValueType.OBJECT) {
    // must use databind: read(path, Target.class)
}

Type guard

boolean needsDatabind(Object v) {
    return v instanceof JsonValue && ((JsonValue) v).getValueType() == JsonValue.ValueType.OBJECT;
}

Try / catch

try {
    Object o = jsonPath.read(path);
} catch (IllegalArgumentException e) {
    Object o = jsonPath.read(path, Map.class);
}

Prevention

When it happens

Trigger: Calling JsonPath.parse(...).read("$.path") (i.e. map()/unwrap path) on a JSON-P document where the addressed value is a JsonObject, or reading a JSON array whose elements are objects via a path that causes unwrapJsonValue to be applied to an object element (see JsonArray.getValuesAs(unwrapJsonValue) at line 256).

Common situations: Reading $.store.book[0] or any object-valued path without a target class; iterating an array of objects while expecting unwrapped Maps; switching MappingProvider from the default (which returns Maps) to the Jakarta JSON-P provider, where object nodes are no longer represented as java.util.Map; forgetting that this provider only unwraps scalar leaves and arrays.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11). Data as JSON: /api/errors/3fd88ddd1daed5ec. Report an issue: GitHub.