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
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.deser.std.StdDeserializer;
import tools.jackson.databind.exc.InvalidFormatException;
import tools.jackson.databind.type.LogicalType;

import jakarta.json.JsonPatch;
Expand All @@ -27,6 +29,13 @@ public LogicalType logicalType() {
public JsonPatch deserialize(JsonParser p, DeserializationContext ctxt)
throws JacksonException
{
// 09-Sep-2026, pjfanning: [datatypes-misc#92] Verify it IS an Array; otherwise
// `_deserializeArray()` reads past the end of the document and fails with
// a bare NPE on the resulting `null` token
if (p.currentToken() != JsonToken.START_ARRAY) {
throw InvalidFormatException.from(p, "JSON patch has to be an array of objects", p.getString(),
handledType());
}
return provider.createPatch(jsonValueDeser._deserializeArray(p, ctxt));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tools.jackson.datatype.jsonp;

import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.exc.InvalidFormatException;

import jakarta.json.*;

Expand All @@ -15,6 +16,8 @@ public class JsonPatchDeserializationTest extends TestBase {

private static final ObjectMapper MAPPER = newMapper();

private static final String EXPECTED_MESSAGE = "JSON patch has to be an array of objects";

@Test
public void testDeserializationAndPatching() throws Exception {
final String json = "[" +
Expand Down Expand Up @@ -51,6 +54,31 @@ public void testDeserializationAndPatching() throws Exception {
assertThat(patchedPerson).isEqualTo(new Person("Json", "Smith"));
}

@Test
public void testObjectDeserializationAndPatching() {
final String json = a2q("{'op':'replace','path':'/name','value':'Json'}");

final InvalidFormatException ex = assertThrows(InvalidFormatException.class,
() -> MAPPER.readValue(json, JsonPatch.class));
assertThat(ex.getMessage()).contains(EXPECTED_MESSAGE);
}

@Test
public void testScalarDeserializationAndPatching() {
final String json = a2q("'op'");

final InvalidFormatException ex = assertThrows(InvalidFormatException.class,
() -> MAPPER.readValue(json, JsonPatch.class));
assertThat(ex.getMessage()).contains(EXPECTED_MESSAGE);
}

@Test
public void testNumberDeserializationAndPatching() {
final InvalidFormatException ex = assertThrows(InvalidFormatException.class,
() -> MAPPER.readValue("42", JsonPatch.class));
assertThat(ex.getMessage()).contains(EXPECTED_MESSAGE);
}

static class Person {
private String name;
private String lastName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@ protected JsonArrayBuilder arrayBuilder() {
protected JsonObjectBuilder objectBuilder() {
return MODULE._builderFactory.createObjectBuilder();
}

protected static String a2q(String json) {
return json.replace("'", "\"");
}
}
3 changes: 2 additions & 1 deletion release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Modules:

3.3.0 (not yet released)

No changes since 3.2
#92: (jakarta-jsonp) `JsonPatch` deserialization throws `NullPointerException`
for non-Array input

3.2.2 (14-Aug-2026)

Expand Down
Loading