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
- 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).
- 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.
- Cast/adjust code that assumed read(path) returns Map<String,Object> for object nodes; with this provider objects must be databound explicitly.
- 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
- Never call bare read(path) on paths that resolve to JSON objects with this provider; always pass a target class or TypeRef.
- Remember JakartaMappingProvider only auto-unwraps scalars and arrays; objects go through map().
- Add a unit test asserting the shape returned by each read call after switching MappingProvider.
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
- an array or object instance is expected
- JSON-P adapter does not support getLocation()
- Put can not be performed to multiple properties
- Rename can not be performed to multiple properties
- setProperty operation cannot be used with
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/3fd88ddd1daed5ec.
Report an issue: GitHub.