json-path/JsonPath · error · MappingException

JSON decimal number cannot be mapped to " + className

Error message

JSON decimal number cannot be mapped to " + className

What it means

mapDecimalJsonNumber converts a JSON decimal (non-integral) number to Float/Double/BigDecimal (and primitive variants). Any other target type throws MappingException with the target's simple name — e.g. requesting Integer or String for a value like 3.14.

Solutions

  1. Request Double.class, Float.class or BigDecimal.class instead of the unsupported type
  2. Read as BigDecimal and convert explicitly (intValue(), longValue(), toPlainString())
  3. Use .map(...) with a custom conversion function
  4. Adjust the path or document so the value's numeric shape matches the target

Example fix

// before
int n = ctx.read("$.ratio", int.class); // 1.5 -> MappingException
// after
int n = ctx.read("$.ratio", BigDecimal.class).intValue();
Defensive patterns

Strategy: type-guard

Validate before calling

Object raw = ctx.read(path);
if (!(raw instanceof Number)) throw new IllegalStateException(path + " is not numeric");
Double d = ctx.read(path, Double.class);

Type guard

boolean isDecimalNumber(Object v) { return v instanceof Double || v instanceof Float || v instanceof BigDecimal; }

Try / catch

try {
    Double d = ctx.read(path, Double.class);
} catch (MappingException e) {
    BigDecimal bd = ctx.read(path, BigDecimal.class);
    double d2 = bd.doubleValue();
}

Prevention

When it happens

Trigger: read(path, Integer.class) or read(path, String.class) where the JSON value is a decimal number; read(path, MyClass.class) on a JSON fractional number.

Common situations: Documents where a value that is usually integral occasionally arrives as 1.0/1.5, so the Integer-typed read fails; expecting strings or custom types from JSON decimals; provider switch removing implicit narrowing/coercion.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

    @SuppressWarnings("unchecked")
    private <T> T mapDecimalJsonNumber(JsonNumber jsonNumber, Class<?> targetType) {
        if (targetType.isPrimitive()) {
            if (float.class.equals(targetType)) {
                return (T) new Float(jsonNumber.doubleValue());
            } else if (double.class.equals(targetType)) {
                return (T) Double.valueOf(jsonNumber.doubleValue());
            }
        } else if (Float.class.equals(targetType)) {
            return (T) new Float(jsonNumber.doubleValue());
        } else if (Double.class.equals(targetType)) {
            return (T) Double.valueOf(jsonNumber.doubleValue());
        } else if (BigDecimal.class.equals(targetType)) {
            return (T) jsonNumber.bigDecimalValue();
        }

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

View on GitHub (pinned to 62a4c9f0f6)