Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ NOTE: Jackson 3.x components rely on 2.x annotations; there are no separate

#346: Add `@JsonWrapped` annotation
(contributed by @sri-adarsh-kumar)
#357: Add `@JsonPointer` annotation for binding a property from a nested
JSON value selected with JSON Pointer syntax

2.22 (31-May-2026)

Expand Down
56 changes: 56 additions & 0 deletions src/main/java/com/fasterxml/jackson/annotation/JsonPointer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.fasterxml.jackson.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation used to indicate that a property is to be deserialized from the
* value selected by a JSON Pointer expression, instead of from a direct child
* property of the containing JSON Object.
*<p>
* For example, given input such as:
*<pre>
* {
* "employee" : {
* "details" : {
* "departmentId" : 123
* }
* }
* }
*</pre>
* property can be bound directly with:
*<pre>
* public class Employee {
* &#64;JsonPointer("/employee/details/departmentId")
* public int departmentId;
* }
*</pre>
* Pointer syntax follows JSON Pointer (RFC 6901), including escaping of
* {@code '~'} and {@code '/'} characters as {@code "~0"} and {@code "~1"},
* respectively.
*<p>
* This annotation only defines logical property access during deserialization;
* it has no effect on serialization. If the pointer does not resolve to a value,
* the property is considered absent. An explicitly resolved JSON {@code null}
* is handled as a regular null property value.
*<p>
* Actual support for this annotation is provided by data-binding modules such
* as {@code jackson-databind}; annotation introspection by itself does not enable
* JSON Pointer traversal.
*
* @since 2.23
*/
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPointer
{
/**
* JSON Pointer expression used to locate the value in the input document.
*
* @return JSON Pointer expression for the annotated property
*/
String value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.fasterxml.jackson.annotation;

import java.lang.reflect.Constructor;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class JsonPointerTest
{
private static class BeanWithField {
@JsonPointer("/nested/field")
public String field;
}

private static class BeanWithMethod {
@JsonPointer("/nested/field")
public void setField(String field) { }
}

private static class BeanWithParameter {
public BeanWithParameter(@JsonPointer("/nested/field") String field) { }
}

@JsonPointer("/nested/field")
@JacksonAnnotationsInside
@interface BundleAnnotation { }

@Test
public void testRuntimeRetentionOnField() throws Exception {
JsonPointer ann = BeanWithField.class.getField("field").getAnnotation(JsonPointer.class);
assertNotNull(ann);
assertEquals("/nested/field", ann.value());
}

@Test
public void testRuntimeRetentionOnMethod() throws Exception {
JsonPointer ann = BeanWithMethod.class.getMethod("setField", String.class)
.getAnnotation(JsonPointer.class);
assertNotNull(ann);
}

@Test
public void testApplicableOnConstructorParameter() throws Exception {
Constructor<?> ctor = BeanWithParameter.class.getDeclaredConstructor(String.class);
JsonPointer ann = ctor.getParameters()[0].getAnnotation(JsonPointer.class);
assertNotNull(ann);
}

@Test
public void testApplicableOnAnnotationType() {
JsonPointer ann = BundleAnnotation.class.getAnnotation(JsonPointer.class);
assertNotNull(ann);
}
}