Class CollectingProblemHandler
DeserializationProblemHandler that collects recoverable
problems into a per-call bucket stored in DeserializationContext
attributes.
Design: This handler is completely stateless. The problem collection
bucket is allocated per-call by ObjectReader.readValueCollectingProblems(...)
and stored in per-call context attributes, ensuring thread-safety and call isolation.
Usage: This class is internal infrastructure, registered automatically by
ObjectReader.problemCollectingReader(). Users should not instantiate or
register this handler manually.
Design rationale - Context Attributes vs Handler State:
Problem collection state is stored in DeserializationContext attributes
rather than within this handler for several reasons:
- Thread-safety: The handler instance is shared across all calls to the same ObjectReader. Storing mutable state in the handler would require synchronization and complicate the implementation.
- Call isolation: Each call to
readValueCollectingProblems()needs its own problem bucket. Context attributes are perfect for this - they're created per-call and automatically cleaned up after deserialization. - Immutability: Jackson's config objects (including handlers) are designed to be immutable and reusable. Storing per-call state violates this principle.
- Configuration vs State: The handler stores configuration (max problems limit) while attributes store runtime state (the actual problem list). This separation follows Jackson's design patterns.
The handler itself is stateless - it's just a strategy for handling problems. The actual collection happens in a bucket passed through context attributes.
Recoverable errors handled:
- Unknown properties (
handleUnknownProperty) - skips children - Type coercion failures (
handleWeirdStringValue,handleWeirdNumberValue) - returns defaults - Map key coercion (
handleWeirdKey) - returnsNOT_HANDLED - Instantiation failures (
handleInstantiationProblem) - returns null when safe
Default values: Primitives receive zero/false defaults; reference types
(including boxed primitives) receive null to avoid masking nullability issues.
DoS protection: Collection stops when the configured limit (default 100) is reached, preventing memory/CPU exhaustion attacks.
JSON Pointer: Paths are built from parser context following RFC 6901,
with proper escaping of ~ and / characters via jackson-core's
JsonPointer class.
- Since:
- 3.1
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final intMaximum number of problems to collect before stopping.private static final ObjectAttribute key for the problem collection bucket.static final intDefault maximum number of problems to collect before stopping.Fields inherited from class DeserializationProblemHandler
NOT_HANDLED -
Constructor Summary
ConstructorsConstructorDescriptionConstructs a handler with the default maximum problem limit.CollectingProblemHandler(int maxProblems) Constructs a handler with a specific maximum problem limit. -
Method Summary
Modifier and TypeMethodDescriptionprivate tools.jackson.core.JsonPointerbuildJsonPointer(tools.jackson.core.JsonParser p) Builds a JsonPointer from the parser's current context.static List<CollectedProblem> Retrieves the problem collection bucket from context attributes.private ObjectgetDefaultValue(Class<?> type) Returns a sensible default value for the given type to allow deserialization to continue.intGets the maximum number of problems this handler will collect.handleInstantiationProblem(DeserializationContext ctxt, Class<?> instClass, Object argument, Throwable t) Method called when instance creation for a type fails due to an exception.booleanhandleUnknownProperty(DeserializationContext ctxt, tools.jackson.core.JsonParser p, ValueDeserializer<?> deserializer, Object beanOrClass, String propertyName) Method called when a JSON Object property with an unrecognized name is encountered.handleWeirdKey(DeserializationContext ctxt, Class<?> rawKeyType, String keyValue, String failureMsg) Method called when a property name from input cannot be converted to a non-Java-String key type (passed asrawKeyType) due to format problem.handleWeirdNumberValue(DeserializationContext ctxt, Class<?> targetType, Number valueToConvert, String failureMsg) Method called when a numeric value (integral or floating-point from input cannot be converted to a non-numeric value type due to specific problem (as opposed to numeric values never being usable).handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg) Method called when a String value cannot be converted to a non-String value type due to specific problem (as opposed to String values never being usable).private booleanrecordProblem(DeserializationContext ctxt, String message, JavaType targetType, Object rawValue) Records a problem in the collection bucket.private tools.jackson.core.TokenStreamLocationsafeGetLocation(tools.jackson.core.JsonParser p) Safely retrieves the current token location, handling null parser.private tools.jackson.core.JsonTokensafeGetToken(tools.jackson.core.JsonParser p) Safely retrieves the current token, handling null parser.Methods inherited from class DeserializationProblemHandler
handleMissingInstantiator, handleMissingTypeId, handleNullForPrimitives, handleUnexpectedToken, handleUnknownTypeId, handleWeirdNativeValue
-
Field Details
-
DEFAULT_MAX_PROBLEMS
public static final int DEFAULT_MAX_PROBLEMSDefault maximum number of problems to collect before stopping. Prevents memory exhaustion attacks.- See Also:
-
ATTR_KEY
Attribute key for the problem collection bucket. Using class object as key (not a string) for type safety. -
_maxProblems
private final int _maxProblemsMaximum number of problems to collect before stopping.
-
-
Constructor Details
-
CollectingProblemHandler
public CollectingProblemHandler()Constructs a handler with the default maximum problem limit. -
CollectingProblemHandler
public CollectingProblemHandler(int maxProblems) Constructs a handler with a specific maximum problem limit.- Parameters:
maxProblems- Maximum number of problems to collect (must be positive)
-
-
Method Details
-
getMaxProblems
public int getMaxProblems()Gets the maximum number of problems this handler will collect. -
getBucket
Retrieves the problem collection bucket from context attributes.- Returns:
- Problem bucket, or null if not in collecting mode
-
recordProblem
private boolean recordProblem(DeserializationContext ctxt, String message, JavaType targetType, Object rawValue) Records a problem in the collection bucket.- Returns:
- true if problem was recorded, false if limit reached
-
safeGetLocation
private tools.jackson.core.TokenStreamLocation safeGetLocation(tools.jackson.core.JsonParser p) Safely retrieves the current token location, handling null parser. -
safeGetToken
private tools.jackson.core.JsonToken safeGetToken(tools.jackson.core.JsonParser p) Safely retrieves the current token, handling null parser. -
buildJsonPointer
private tools.jackson.core.JsonPointer buildJsonPointer(tools.jackson.core.JsonParser p) Builds a JsonPointer from the parser's current context. Uses the built-inTokenStreamContext.pathAsPointer()method which handles RFC 6901 escaping ('~' becomes '~0', '/' becomes '~1'). -
handleUnknownProperty
public boolean handleUnknownProperty(DeserializationContext ctxt, tools.jackson.core.JsonParser p, ValueDeserializer<?> deserializer, Object beanOrClass, String propertyName) throws tools.jackson.core.JacksonException Description copied from class:DeserializationProblemHandlerMethod called when a JSON Object property with an unrecognized name is encountered. Content (supposedly) matching the property are accessible via parser that can be obtained from passed deserialization context. Handler can also choose to skip the content; if so, it MUST return true to indicate it did handle property successfully. Skipping is usually done like so:parser.skipChildren();
Note:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) takes effect only after handler is called, and only if handler did not handle the problem.- Overrides:
handleUnknownPropertyin classDeserializationProblemHandler- Parameters:
p- Parser to use for handling problematic contentbeanOrClass- Either bean instance being deserialized (if one has been instantiated so far); or Class that indicates type that will be instantiated (if no instantiation done yet: for example when bean uses non-default constructors)- Returns:
- True if the problem is resolved (and content available used or skipped); false if the handler did not anything and the problem is unresolved. Note that in latter case caller will either throw an exception or explicitly skip the content, depending on configuration.
- Throws:
tools.jackson.core.JacksonException
-
handleWeirdKey
public Object handleWeirdKey(DeserializationContext ctxt, Class<?> rawKeyType, String keyValue, String failureMsg) throws tools.jackson.core.JacksonException Description copied from class:DeserializationProblemHandlerMethod called when a property name from input cannot be converted to a non-Java-String key type (passed asrawKeyType) due to format problem. Handler may choose to do one of 3 things:- Indicate it does not know what to do by returning
DeserializationProblemHandler.NOT_HANDLED - Throw a
IOExceptionto indicate specific fail message (instead of standard exception caller would throw - Return actual key value to use as replacement, and continue processing.
- Overrides:
handleWeirdKeyin classDeserializationProblemHandler- Parameters:
failureMsg- Message that will be used by caller (by callingDeserializationContext.weirdKeyException(Class, String, String)) to indicate type of failure unless handler produces key to use- Returns:
- Either
DeserializationProblemHandler.NOT_HANDLEDto indicate that handler does not know what to do (and exception may be thrown), or value to use as key (possiblynull - Throws:
tools.jackson.core.JacksonException
- Indicate it does not know what to do by returning
-
handleWeirdStringValue
public Object handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg) throws tools.jackson.core.JacksonException Description copied from class:DeserializationProblemHandlerMethod called when a String value cannot be converted to a non-String value type due to specific problem (as opposed to String values never being usable). Handler may choose to do one of 3 things:- Indicate it does not know what to do by returning
DeserializationProblemHandler.NOT_HANDLED - Throw a
IOExceptionto indicate specific fail message (instead of standard exception caller would throw - Return actual converted value (of type
targetType) to use as replacement, and continue processing.
- Overrides:
handleWeirdStringValuein classDeserializationProblemHandler- Parameters:
failureMsg- Message that will be used by caller (by callingDeserializationContext.weirdNumberException(Number, Class, String)) to indicate type of failure unless handler produces key to use- Returns:
- Either
DeserializationProblemHandler.NOT_HANDLEDto indicate that handler does not know what to do (and exception may be thrown), or value to use as (possiblynull) - Throws:
tools.jackson.core.JacksonException
- Indicate it does not know what to do by returning
-
handleWeirdNumberValue
public Object handleWeirdNumberValue(DeserializationContext ctxt, Class<?> targetType, Number valueToConvert, String failureMsg) throws tools.jackson.core.JacksonException Description copied from class:DeserializationProblemHandlerMethod called when a numeric value (integral or floating-point from input cannot be converted to a non-numeric value type due to specific problem (as opposed to numeric values never being usable). Handler may choose to do one of 3 things:- Indicate it does not know what to do by returning
DeserializationProblemHandler.NOT_HANDLED - Throw a
IOExceptionto indicate specific fail message (instead of standard exception caller would throw - Return actual converted value (of type
targetType) to use as replacement, and continue processing.
- Overrides:
handleWeirdNumberValuein classDeserializationProblemHandler- Parameters:
failureMsg- Message that will be used by caller (by callingDeserializationContext.weirdNumberException(Number, Class, String)) to indicate type of failure unless handler produces key to use- Returns:
- Either
DeserializationProblemHandler.NOT_HANDLEDto indicate that handler does not know what to do (and exception may be thrown), or value to use as (possiblynull) - Throws:
tools.jackson.core.JacksonException
- Indicate it does not know what to do by returning
-
handleInstantiationProblem
public Object handleInstantiationProblem(DeserializationContext ctxt, Class<?> instClass, Object argument, Throwable t) throws tools.jackson.core.JacksonException Description copied from class:DeserializationProblemHandlerMethod called when instance creation for a type fails due to an exception. Handler may choose to do one of following things:- Indicate it does not know what to do by returning
DeserializationProblemHandler.NOT_HANDLED - Throw a
IOExceptionto indicate specific fail message (instead of standard exception caller would throw - Return actual instantiated value (of type
targetType) to use as replacement, and continue processing. - Return
nullto use null as value but not to try further processing (in cases where properties would otherwise be bound)
- Overrides:
handleInstantiationProblemin classDeserializationProblemHandler- Parameters:
instClass- Type that was to be instantiatedargument- (optional) Additional argument that was passed to creator, if anyt- Exception that caused instantiation failure- Returns:
- Either
DeserializationProblemHandler.NOT_HANDLEDto indicate that handler does not know what to do (and exception may be thrown), or value to use (possiblynull - Throws:
tools.jackson.core.JacksonException
- Indicate it does not know what to do by returning
-
getDefaultValue
-