From 3c4c0a2c75c65ad5f6b86c27165e4e1845f78ce4 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Wed, 3 Jul 2024 19:29:27 +0900 Subject: [PATCH 1/5] Add a fixer and test --- .../databind/deser/BeanDeserializer.java | 4 +- .../failing/ObjectIdSubTypes4607Test.java | 38 ------------------- 2 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 src/test/java/com/fasterxml/jackson/failing/ObjectIdSubTypes4607Test.java diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java index 25ae119c6c..0d23ada44b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java @@ -372,7 +372,9 @@ public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) t // [databind#3838]: since 2.16 Uniform handling of missing objectId // only for the specific "empty JSON Object" case if (_objectIdReader != null && p.hasTokenId(JsonTokenId.ID_END_OBJECT)) { - ctxt.reportUnresolvedObjectId(_objectIdReader, bean); + if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)) { + ctxt.reportUnresolvedObjectId(_objectIdReader, bean); + } } if (_injectables != null) { injectValues(ctxt, bean); diff --git a/src/test/java/com/fasterxml/jackson/failing/ObjectIdSubTypes4607Test.java b/src/test/java/com/fasterxml/jackson/failing/ObjectIdSubTypes4607Test.java deleted file mode 100644 index dd380e76cb..0000000000 --- a/src/test/java/com/fasterxml/jackson/failing/ObjectIdSubTypes4607Test.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.fasterxml.jackson.failing; - -import java.util.List; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import com.fasterxml.jackson.annotation.*; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; - -public class ObjectIdSubTypes4607Test extends DatabindTestUtil -{ - @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class) - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME) - @JsonSubTypes({ - @JsonSubTypes.Type(value = EnumTypeDefinition.class, name = "enum"), - @JsonSubTypes.Type(value = NumberTypeDefinition.class, name = "number") - }) - interface TypeDefinition { - } - - static class EnumTypeDefinition implements TypeDefinition { - public List values; - } - - static class NumberTypeDefinition implements TypeDefinition { - } - - @Test - public void shouldHandleTypeDefinitionJson() throws Exception { - final ObjectMapper mapper = newJsonMapper(); - TypeDefinition model = mapper.readValue("{ \"@type\": \"number\" }", TypeDefinition.class); - Assertions.assertInstanceOf(NumberTypeDefinition.class, model); - } -} - From 34fc6664b9ba25c09fe7e5927e42164931997e42 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Wed, 3 Jul 2024 19:29:48 +0900 Subject: [PATCH 2/5] Add test --- .../objectid/ObjectIdSubTypes4607Test.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java diff --git a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java new file mode 100644 index 0000000000..91aeef9b3c --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java @@ -0,0 +1,79 @@ +package com.fasterxml.jackson.databind.objectid; + +import java.util.List; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; + +import static com.fasterxml.jackson.databind.BaseMapTest.jsonMapperBuilder; +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ObjectIdSubTypes4607Test extends DatabindTestUtil +{ + @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class) + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME) + @JsonSubTypes({ + @JsonSubTypes.Type(value = EnumTypeDefinition.class, name = "enum"), + @JsonSubTypes.Type(value = NumberTypeDefinition.class, name = "number") + }) + interface TypeDefinition { + } + + static class EnumTypeDefinition implements TypeDefinition { + public List values; + } + + static class NumberTypeDefinition implements TypeDefinition { + } + + @Test + public void shouldHandleTypeDefinitionJson() throws Exception { + String input = "{\"@type\": \"number\"}"; + + TypeDefinition model = jsonMapperBuilder() + .disable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) + .build() + .readValue(input, TypeDefinition.class); + + Assertions.assertInstanceOf(NumberTypeDefinition.class, model); + } + + @Test + public void testRoundTrip() throws Exception { + ObjectMapper mapper = jsonMapperBuilder() + .enable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) + .build(); + + // Ser + String JSON = mapper.writeValueAsString(new NumberTypeDefinition()); + assertTrue(JSON.contains("@id")); + + // Deser + TypeDefinition model = mapper.readValue(JSON, TypeDefinition.class); + Assertions.assertInstanceOf(NumberTypeDefinition.class, model); + } + + @Test + public void shouldHandleTypeDefinitionJsonFail() throws Exception { + String input = "{\"@type\": \"number\"}"; + + try { + TypeDefinition model = jsonMapperBuilder() + .enable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) + .build() + .readValue(input, TypeDefinition.class); + fail("Should not pass"); + } catch (Exception e) { + assertTrue(e.getMessage().startsWith("No Object Id found for an instance of")); + } + } + +} + From d9a9d2d4eeb186c269b38aae577e691cca052de4 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Wed, 3 Jul 2024 19:30:30 +0900 Subject: [PATCH 3/5] Update ObjectIdSubTypes4607Test.java --- .../jackson/databind/objectid/ObjectIdSubTypes4607Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java index 91aeef9b3c..29698e2392 100644 --- a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java @@ -11,12 +11,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; -import static com.fasterxml.jackson.databind.BaseMapTest.jsonMapperBuilder; import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertTrue; public class ObjectIdSubTypes4607Test extends DatabindTestUtil { + // Unused @JsonIdentityInfo @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME) @JsonSubTypes({ From a4aeb5f9ce5e6cbfc4d3558dd82f9a71f15e8f26 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Wed, 3 Jul 2024 19:31:40 +0900 Subject: [PATCH 4/5] Update ObjectIdSubTypes4610Test.java --- ...ectIdSubTypes4607Test.java => ObjectIdSubTypes4610Test.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/com/fasterxml/jackson/databind/objectid/{ObjectIdSubTypes4607Test.java => ObjectIdSubTypes4610Test.java} (97%) diff --git a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java similarity index 97% rename from src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java rename to src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java index 29698e2392..878a051f62 100644 --- a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4607Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java @@ -14,7 +14,7 @@ import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertTrue; -public class ObjectIdSubTypes4607Test extends DatabindTestUtil +public class ObjectIdSubTypes4610Test extends DatabindTestUtil { // Unused @JsonIdentityInfo @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class) From 9d2a5964efe3ac3a790b7b3756ace9577eb6437f Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 3 Jul 2024 20:11:31 -0700 Subject: [PATCH 5/5] Add release notes, streamline code a bit --- release-notes/VERSION-2.x | 3 ++ .../databind/deser/BeanDeserializer.java | 1 + .../objectid/ObjectIdSubTypes4610Test.java | 31 +++++++++---------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 997a989c5f..86a5477772 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -18,6 +18,9 @@ Project: jackson-databind (reported by @dmelisso) #4595: No way to explicitly disable wrapping in custom annotation processor (reported by @SimonCockx) +#4610: `DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS` does not work when + used with Polymorphic type handling + (fix by Joo-Hyuk K) 2.17.1 (04-May-2024) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java index 0d23ada44b..010d6a98df 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java @@ -372,6 +372,7 @@ public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) t // [databind#3838]: since 2.16 Uniform handling of missing objectId // only for the specific "empty JSON Object" case if (_objectIdReader != null && p.hasTokenId(JsonTokenId.ID_END_OBJECT)) { + // [databind#4610]: check if we are to skip failure if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)) { ctxt.reportUnresolvedObjectId(_objectIdReader, bean); } diff --git a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java index 878a051f62..7fa3c87260 100644 --- a/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/objectid/ObjectIdSubTypes4610Test.java @@ -2,12 +2,12 @@ import java.util.List; -import com.fasterxml.jackson.databind.DeserializationFeature; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; @@ -33,47 +33,44 @@ static class EnumTypeDefinition implements TypeDefinition { static class NumberTypeDefinition implements TypeDefinition { } + private final ObjectMapper MAPPER = newJsonMapper(); + @Test public void shouldHandleTypeDefinitionJson() throws Exception { String input = "{\"@type\": \"number\"}"; - TypeDefinition model = jsonMapperBuilder() - .disable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) - .build() - .readValue(input, TypeDefinition.class); + TypeDefinition model = MAPPER.readerFor(TypeDefinition.class) + .without(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) + .readValue(input); Assertions.assertInstanceOf(NumberTypeDefinition.class, model); } @Test public void testRoundTrip() throws Exception { - ObjectMapper mapper = jsonMapperBuilder() - .enable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) - .build(); - // Ser - String JSON = mapper.writeValueAsString(new NumberTypeDefinition()); + String JSON = MAPPER.writeValueAsString(new NumberTypeDefinition()); assertTrue(JSON.contains("@id")); // Deser - TypeDefinition model = mapper.readValue(JSON, TypeDefinition.class); + TypeDefinition model = MAPPER.readerFor(TypeDefinition.class) + .with(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) + .readValue(JSON); Assertions.assertInstanceOf(NumberTypeDefinition.class, model); } @Test public void shouldHandleTypeDefinitionJsonFail() throws Exception { - String input = "{\"@type\": \"number\"}"; + String JSON = "{\"@type\": \"number\"}"; try { - TypeDefinition model = jsonMapperBuilder() - .enable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) - .build() - .readValue(input, TypeDefinition.class); + /*TypeDefinition model =*/ MAPPER.readerFor(TypeDefinition.class) + .with(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS) + .readValue(JSON); fail("Should not pass"); } catch (Exception e) { assertTrue(e.getMessage().startsWith("No Object Id found for an instance of")); } } - }