Skip to content

Add JsonPointer property deserialization support - #6161

Draft
arnabnandy7 wants to merge 1 commit into
FasterXML:3.xfrom
arnabnandy7:feature/json-pointer-binding
Draft

Add JsonPointer property deserialization support#6161
arnabnandy7 wants to merge 1 commit into
FasterXML:3.xfrom
arnabnandy7:feature/json-pointer-binding

Conversation

@arnabnandy7

Copy link
Copy Markdown

Summary

Adds databind support for deserializing POJO properties from nested JSON values selected with @JsonPointer.

References:

Example

Given:

{
  "name": "Bob",
  "employee": {
    "details": {
      "departmentId": 123
    }
  }
}

A property can be bound directly using:

public class Employee {
    public String name;

    @JsonPointer("/employee/details/departmentId")
    public Integer departmentId;
}

Implementation

  • Adds @JsonPointer support to AnnotationIntrospector.
  • Supports annotation-introspector pairs and JacksonAnnotationIntrospector.
  • Detects and contextualizes pointer-bound properties during bean deserializer resolution.
  • Buffers input only for POJOs containing pointer-bound properties.
  • Uses the existing property deserializer when binding the selected value, preserving standard type coercion, custom deserializers, null handling, and assignment behavior.
  • Removes pointer-only top-level source properties from regular bean binding so they are not treated as unknown.
  • Continues to report unrelated unknown properties when FAIL_ON_UNKNOWN_PROPERTIES is enabled.

Initial scope

  • Deserialization only.
  • Supports fields and setter methods.
  • Creator properties are explicitly rejected.
  • A missing pointer target leaves the property unchanged.
  • An explicit JSON null uses normal property null handling.
  • Pointer syntax and escaping follow RFC 6901.

Testing

Focused coverage includes:

  • Nested field binding
  • Setter binding
  • RFC 6901 escaping
  • Missing pointer targets
  • Explicit JSON null
  • Unrelated unknown-property handling
./mvnw -Dtest=JsonPointerDeserializationTest test

Result:

Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

Comment thread src/main/java/tools/jackson/databind/deser/impl/JsonPointerPropertyHandler.java Outdated
Comment thread src/main/java/tools/jackson/databind/deser/impl/JsonPointerPropertyHandler.java Outdated
Signed-off-by: Arnab Nandy <arnab_nandy7@yahoo.com>
@arnabnandy7
arnabnandy7 force-pushed the feature/json-pointer-binding branch from 63392ea to f86391a Compare August 12, 2026 15:15
@gitar-bot

gitar-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown
CI failed: Build failure across all jobs caused by a missing import for `JsonPointer` in `JacksonAnnotationIntrospector.java`.

Overview

A consistent build failure occurred across all 4 analyzed CI jobs due to a missing symbol JsonPointer in JacksonAnnotationIntrospector.java during compilation.

Failures

Missing symbol JsonPointer in JacksonAnnotationIntrospector (confidence: high)

  • Type: build
  • Affected jobs: 94200817166, 94200817006, 94200817022, 94200816984
  • Related to change: yes
  • Root cause: JacksonAnnotationIntrospector.java references JsonPointer at line 523, but the required import statement is missing from the file.
  • Suggested fix: Add the appropriate import statement for JsonPointer (e.g., import tools.jackson.core.JsonPointer; or equivalent) in src/main/java/tools/jackson/databind/introspect/JacksonAnnotationIntrospector.java.

Summary

  • Change-related failures: 4 build failures caused by a missing import/class reference in JacksonAnnotationIntrospector.java.
  • Infrastructure/flaky failures: 0
  • Recommended action: Add the missing JsonPointer import in JacksonAnnotationIntrospector.java and re-run the build.
Code Review ✅ Approved 4 resolved / 4 findings

Adds @JsonPointer property deserialization support using buffered input and RFC 6901 compliant parsing, addressing findings related to update paths, deep copy overhead, invalid pointer expressions, and error wrapping.

✅ 4 resolved
Edge Case: JsonPointer ignored on update/merge deserialization path

📄 src/main/java/tools/jackson/databind/deser/bean/BeanDeserializer.java:187-201 📄 src/main/java/tools/jackson/databind/deser/bean/BeanDeserializer.java:266-280 📄 src/main/java/tools/jackson/databind/deser/bean/BeanDeserializerBase.java:607-620
Pointer handling is only wired into deserialize(JsonParser, DeserializationContext). The update path deserialize(p, ctxt, bean) (used by readerForUpdating(...) and property @JsonMerge/POJO-into-existing binding) never invokes _jsonPointerPropertyHandler, and because the property was removed from _beanProperties in resolve(), it is also not bound there. Result: pointer-bound properties are silently skipped when updating an existing instance. Either route the update path through the pointer handler as well, or document/reject the update case explicitly so the omission is not silent.

Performance: Full deepCopy of source tree on every pointer-bean deserialization

📄 src/main/java/tools/jackson/databind/deser/impl/JsonPointerPropertyHandler.java:50-52 📄 src/main/java/tools/jackson/databind/deser/bean/BeanDeserializer.java:190-201
For any POJO containing a pointer property, each deserialization now reads the entire input into a tree (readTree), performs a full deepCopy() of the root ObjectNode, then re-parses via TreeTraversingParser — roughly tripling work and doubling peak memory. The deepCopy() clones all nested subtrees only to drop a few top-level keys. Since nodes are effectively immutable during read, a shallow copy (new ObjectNode sharing existing child references, minus the pointer roots) is sufficient and much cheaper.

Quality: Invalid @JsonPointer expression throws raw IllegalArgumentException

📄 src/main/java/tools/jackson/databind/deser/impl/JsonPointerPropertyHandler.java:28-30 📄 src/main/java/tools/jackson/databind/deser/bean/BeanDeserializerBase.java:607-618
addProperty calls JsonPointer.compile(expression) during resolve(), which throws IllegalArgumentException for malformed input (e.g. a value not starting with '/'). This surfaces as a raw, low-context exception during deserializer construction instead of a proper InvalidDefinitionException. Validate/compile the expression where DeserializationContext is available and route failures through ctxt.reportBadDefinition(...) for a clear, bean-scoped error message.

Quality: process() does not wrap property errors with wrapAndThrow

📄 src/main/java/tools/jackson/databind/deser/impl/JsonPointerPropertyHandler.java:55-67
In JsonPointerPropertyHandler.process, deserializeAndSet is invoked directly, so any failure propagates without the bean/property context that BeanDeserializer normally adds via wrapAndThrow. Errors on pointer-bound properties will therefore have less actionable diagnostics (no property path / bean reference) than errors on normal properties. Consider wrapping the call in a try/catch that produces an equivalent contextualized exception.

Tip

Comment Gitar fix CI or enable auto-apply: gitar auto-apply:on

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@arnabnandy7
arnabnandy7 marked this pull request as draft August 12, 2026 17:42
@arnabnandy7

arnabnandy7 commented Aug 12, 2026

Copy link
Copy Markdown
Author

It depends on FasterXML/jackson-annotations#358 until that's merged and the updated 2.23-SNAPSHOT becomes available to CI it'll keep on failing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant