json-path/JsonPath · error · MappingException

JSON boolean (false) cannot be mapped to " + className

Error message

JSON boolean (false) cannot be mapped to " + className

What it means

JakartaMappingProvider.mapImpl converts a JSON-P JsonValue into a Java type. When the source is JsonValue.FALSE and the requested targetType is anything other than Boolean (or boolean via earlier checks), it cannot convert and throws MappingException. This is a deliberate strictness: the provider does not coerce booleans to strings, numbers, or objects.

Solutions

  1. Change the requested target type to Boolean.class (or boolean) so the false value maps directly
  2. Fix the JSON path to select a value of the expected type, or verify the document shape at the path
  3. Use .map(...) with a custom conversion lambda instead of direct type mapping
  4. Configure a different MappingProvider (e.g. JsonSmartMappingProvider) if lenient coercion is desired

Example fix

// before
String enabled = context.read("$.enabled", String.class); // MappingException
// after
Boolean enabled = context.read("$.enabled", Boolean.class);
Defensive patterns

Strategy: type-guard

Validate before calling

Object raw = ctx.read(path);
if (!(raw instanceof Boolean)) throw new IllegalStateException(path + " is not a JSON boolean: " + raw);
Boolean b = ctx.read(path, Boolean.class);

Type guard

boolean isBoolean(Object v) { return v instanceof Boolean || v == Boolean.FALSE || v == Boolean.TRUE; }

Try / catch

try {
    Boolean b = ctx.read(path, Boolean.class);
} catch (MappingException e) {
    // fall back to raw read and convert
    Object raw = ctx.read(path);
}

Prevention

When it happens

Trigger: Calling JsonPath.parse(json).read(path, Class) (or .map(...) / mapping via the provider) where the JSON value at the path is literally false and the requested target type is not Boolean.class/boolean — e.g. read("$.enabled", String.class) or read("$.flag", Integer.class).

Common situations: Path points at a boolean field while a String/numeric type was assumed (API schema changed true/false into an enum-like field); config where a flag is expected to be a string "false" but the document contains real JSON false; switching from the default JsonSmartMappingProvider (looser coercions) to JakartaMappingProvider and old coercions now fail.

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/0be1fcba7499b424. Report an issue: GitHub.

Appendix: source

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

    private Object mapImpl(Object source, final Type targetType) {
        if (source == null || source == JsonValue.NULL) {
            return null;
        }
        if (source == JsonValue.TRUE) {
            if (Boolean.class.equals(targetType)) {
                return Boolean.TRUE;
            } else {
                String className = targetType.toString();
                throw new MappingException("JSON boolean (true) cannot be mapped to " + className);
            }
        }
        if (source == JsonValue.FALSE) {
            if (Boolean.class.equals(targetType)) {
                return Boolean.FALSE;
            } else {
                String className = targetType.toString();
                throw new MappingException("JSON boolean (false) cannot be mapped to " + className);
            }
        } else if (source instanceof JsonString) {
            if (String.class.equals(targetType)) {
                return ((JsonString) source).getChars();
            } else {
                String className = targetType.toString();
                throw new MappingException("JSON string cannot be mapped to " + className);
            }
        } else if (source instanceof JsonNumber) {
            JsonNumber jsonNumber = (JsonNumber) source;
            if (jsonNumber.isIntegral()) {
                return mapIntegralJsonNumber(jsonNumber, getRawClass(targetType));
            } else {
                return mapDecimalJsonNumber(jsonNumber, getRawClass(targetType));
            }
        }
        if (source instanceof JsonArrayBuilder) {
            source = ((JsonArrayBuilder) source).build();

View on GitHub (pinned to 62a4c9f0f6)