From 0cc75734666cffe3dd206e4d02218cd337d99518 Mon Sep 17 00:00:00 2001 From: Jackson Date: Thu, 4 Dec 2025 20:44:30 +0900 Subject: [PATCH 1/2] Fix #1654: strictTypeIdHandling for properties annotated with @JsonTypeInfo(use = NONE) --- .../impl/AsPropertyTypeDeserializer.java | 18 ++++++++++++++++-- .../jsontype/impl/TypeSerializerBase.java | 10 ++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java b/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java index 91226c6814..162d215a2f 100644 --- a/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java +++ b/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java @@ -1,5 +1,6 @@ package tools.jackson.databind.jsontype.impl; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import tools.jackson.core.JacksonException; @@ -169,8 +170,10 @@ protected Object _deserializeTypedUsingDefaultImpl(JsonParser p, // genuine, or faked for "dont fail on bad type id") ValueDeserializer deser = _findDefaultImplDeserializer(ctxt); if (deser == null) { - JavaType t = _strictTypeIdHandling - ? _handleMissingTypeId(ctxt, priorFailureMsg) : _baseType; + JavaType t = isStrictTypeIdHandlingForProperty() + ? _handleMissingTypeId(ctxt, priorFailureMsg) + : _baseType; + if (t == null) { // 09-Mar-2017, tatu: Is this the right thing to do? return null; @@ -203,6 +206,17 @@ public Object deserializeTypedFromAny(JsonParser p, DeserializationContext ctxt) return deserializeTypedFromObject(p, ctxt); } + // [databind#1654]: Determine whether strict type-id handling should apply for this property. + private boolean isStrictTypeIdHandlingForProperty() { + if (!_strictTypeIdHandling) { + return false; + } + if (_property == null) { + return true; + } + JsonTypeInfo typeInfo = _property.getAnnotation(JsonTypeInfo.class); + return typeInfo == null || typeInfo.use() != JsonTypeInfo.Id.NONE; + } // These are fine from base class: //public Object deserializeTypedFromArray(JsonParser p, DeserializationContext ctxt) //public Object deserializeTypedFromScalar(JsonParser p, DeserializationContext ctxt) diff --git a/src/main/java/tools/jackson/databind/jsontype/impl/TypeSerializerBase.java b/src/main/java/tools/jackson/databind/jsontype/impl/TypeSerializerBase.java index a6ce5cb80e..788669667d 100644 --- a/src/main/java/tools/jackson/databind/jsontype/impl/TypeSerializerBase.java +++ b/src/main/java/tools/jackson/databind/jsontype/impl/TypeSerializerBase.java @@ -44,6 +44,16 @@ public WritableTypeId writeTypePrefix(JsonGenerator g, SerializationContext ctxt WritableTypeId idMetadata) throws JacksonException { _generateTypeId(ctxt, idMetadata); + + // [databind#1654]: If the property overrides type info with @JsonTypeInfo(use = NONE), + // skip writing a type id for this property. + if (_property != null) { + JsonTypeInfo typeInfo = _property.getAnnotation(JsonTypeInfo.class); + if (typeInfo != null && typeInfo.use() == JsonTypeInfo.Id.NONE) { + idMetadata.id = null; + } + } + // 16-Jan-2022, tatu: As per [databind#3373], skip for null typeId. // And return "null" to avoid matching "writeTypeSuffix" as well. // 15-Jun-2024, tatu: [databind#4407] Not so fast! Output wrappers From 3804a6a0aa2fd36fc24c3d64d94189aac241c3d8 Mon Sep 17 00:00:00 2001 From: Jackson Date: Thu, 4 Dec 2025 20:48:58 +0900 Subject: [PATCH 2/2] Update test file for #1654 (#5467) --- .../databind/{tofix => }/NoTypeInfo1654Test.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) rename src/test/java/tools/jackson/databind/{tofix => }/NoTypeInfo1654Test.java (89%) diff --git a/src/test/java/tools/jackson/databind/tofix/NoTypeInfo1654Test.java b/src/test/java/tools/jackson/databind/NoTypeInfo1654Test.java similarity index 89% rename from src/test/java/tools/jackson/databind/tofix/NoTypeInfo1654Test.java rename to src/test/java/tools/jackson/databind/NoTypeInfo1654Test.java index 5f64f9c1c8..4e2c5d798c 100644 --- a/src/test/java/tools/jackson/databind/tofix/NoTypeInfo1654Test.java +++ b/src/test/java/tools/jackson/databind/NoTypeInfo1654Test.java @@ -1,4 +1,4 @@ -package tools.jackson.databind.tofix; +package tools.jackson.databind; import java.util.*; @@ -7,10 +7,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import tools.jackson.core.JsonParser; -import tools.jackson.databind.*; import tools.jackson.databind.annotation.JsonDeserialize; import tools.jackson.databind.testutil.DatabindTestUtil; -import tools.jackson.databind.testutil.failure.JacksonTestFailureExpected; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -77,24 +75,22 @@ void noTypeElementOverride() throws Exception { } // [databind#1654] - @JacksonTestFailureExpected @Test void noTypeInfoOverrideSer() throws Exception { Value1654UntypedContainer cont = new Value1654UntypedContainer( new Value1654(3), new Value1654(7) ); - assertEquals(a2q("{'values':[{'x':3},{'x': 7}] }"), + assertEquals(a2q("{'values':[{'x':3},{'x':7}]}"), MAPPER.writeValueAsString(cont)); } // [databind#1654] - @JacksonTestFailureExpected @Test void noTypeInfoOverrideDeser() throws Exception { // and then actual failing case final String noTypeJson = a2q( - "{'values':[{'x':3},{'x': 7}] }" + "{'values':[{'x':3},{'x':7}]}" ); Value1654UntypedContainer unResult = MAPPER.readValue(noTypeJson, Value1654UntypedContainer.class); assertEquals(2, unResult.values.size());