Follow up on Issue #4004 and PR #5595
Is your feature request related to a problem? Please describe.
Long story short, error types are confusing and sometimes misleading.
Jackson 3.1 introduced FunctionalScalarDeserializer that provides a rich and extensible deserialization model, but error handling in user-provided deserializers is currently too loose, leading to loss of semantic meaning
in exception types.
Problematic scenario
Consider the following test:
@Test
public void justThrowErrorEvenWithValidFormat() throws Exception
{
SimpleModule module = new SimpleModule("test");
module.addDeserializer(Bar.class,
new FunctionalScalarDeserializer<>(Bar.class, (p, ctx) -> {
// 1) Blindly throw user/business exception
throw new IllegalArgumentException(
"BiFunction error: " + p.getValueAsString());
}));
ObjectMapper mapper = jsonMapperBuilder()
.addModule(module)
.build();
try {
// 2) JSON input is fully valid
mapper.readValue("{\"bar\":\"fieldValue\"}", BarWrapper.class);
fail();
} catch (InvalidFormatException e) {
// 3) Jackson wraps the exception as InvalidFormatException
verifyException(e, "Cannot deserialize");
}
}
In this case:
- User code throws an arbitrary exception (
IllegalArgumentException)
- The JSON input is valid
- Jackson wraps the failure as
InvalidFormatException <--- why?
From a user perspective, encountering InvalidFormatException strongly suggests that the input value itself is invalid or malformed.
However, in this scenario the failure is entirely due to application/domain logic,
not input format.
This makes it difficult for users to correctly interpret and classify errors
(e.g. client error vs server error).
There could be more cases.
Describe the solution you'd like
Goal: Make exception wrapping from user-provided deserializers predictable
Jackson should apply deterministic wrapping rules when exceptions are thrown from user-provided deserialization callbacks (for example,
FunctionalScalarDeserializer), so that the resulting exception type reflects
the nature of the failure.
Proposed behavior
- Provide guidelines on HOW user should throw error (and which type)
- DO improve Exception handling logic within
FunctionalScalarDeserializer
Below is my rough idea of mentioned guideline.
/**
* A general-purpose deserializer that uses a {@link Function} or {@link BiFunction}
* to convert JSON scalar values (strings, numbers, booleans) into target type instances.
* <p>
* This deserializer is primarily designed for String-based conversions but also
* supports other JSON scalar types via {@code getValueAsString()} coercion.
* Non-scalar JSON values (arrays, objects, embedded objects) are rejected.
* <p>
* <b>Error handling guidelines:</b>
* <ul>
* <li>Exceptions of type {@link com.fasterxml.jackson.databind.exc.InvalidFormatException}
* thrown by user code are treated as explicit signals of invalid input values
* and are propagated as-is.</li>
* <li>{@link com.fasterxml.jackson.databind.JsonMappingException} may be thrown by
* user code to indicate a deliberate mapping failure and will be propagated.</li>
* <li>Other runtime exceptions thrown by user code are considered application or
* domain failures and may be wrapped as {@link com.fasterxml.jackson.databind.JsonMappingException}
* rather than being reported as input-format errors.</li>
* </ul>
* <p>
* Usage examples:
* ...... rest omitted.....
Exception handling rules
| Thrown by user code |
Jackson behavior |
| InvalidFormatException |
Propagate as-is |
| JsonMappingException |
Propagate as-is |
| Other Exceptions |
Wrap in JsonMappingException |
Resulting Benefit
- Valid JSON input is not reported as format error
- User intent is preserved when signaling mapping failures
- Custom deserializer error behavior becomes consistent and predictable
Follow up on Issue #4004 and PR #5595
Is your feature request related to a problem? Please describe.
Long story short, error types are confusing and sometimes misleading.
Jackson 3.1 introduced
FunctionalScalarDeserializerthat provides a rich and extensible deserialization model, but error handling in user-provided deserializers is currently too loose, leading to loss of semantic meaningin exception types.
Problematic scenario
Consider the following test:
In this case:
IllegalArgumentException)InvalidFormatException<--- why?From a user perspective, encountering
InvalidFormatExceptionstrongly suggests that the input value itself is invalid or malformed.However, in this scenario the failure is entirely due to application/domain logic,
not input format.
This makes it difficult for users to correctly interpret and classify errors
(e.g. client error vs server error).
There could be more cases.
Describe the solution you'd like
Goal: Make exception wrapping from user-provided deserializers predictable
Jackson should apply deterministic wrapping rules when exceptions are thrown from user-provided deserialization callbacks (for example,
FunctionalScalarDeserializer), so that the resulting exception type reflectsthe nature of the failure.
Proposed behavior
FunctionalScalarDeserializerBelow is my rough idea of mentioned guideline.
Exception handling rules
Resulting Benefit