From 9f09361c59e40e9a5f53b025cd3a78145ae4de92 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 16 Mar 2025 14:09:22 +0100 Subject: [PATCH 01/13] Create PolymorphicIdClassDeserTest.java --- .../deser/PolymorphicIdClassDeserTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java new file mode 100644 index 0000000000..5bfb65eda7 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java @@ -0,0 +1,39 @@ +package com.fasterxml.jackson.databind.deser; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializeUsingJDKTest; +import org.junit.jupiter.api.Test; + +import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.newJsonMapper; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class PolymorphicIdClassDeserTest { + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) + @JsonSubTypes({@JsonSubTypes.Type(value = FooClassImpl.class)}) + static abstract class FooClass { } + static class FooClassImpl extends FooClass { } + static class FooClassImpl2 extends FooClass { } + + /* + /************************************************************ + /* Unit tests, valid + /************************************************************ + */ + + private final ObjectMapper MAPPER = newJsonMapper(); + + @Test + public void testDeserialization() throws Exception + { + //trying to test if JsonSubTypes enforced + final String foo1 = MAPPER.writeValueAsString(new FooClassImpl()); + final String foo2 = MAPPER.writeValueAsString(new FooClassImpl2()); + FooClass res1 = MAPPER.readValue(foo1, FooClass.class); + assertTrue(res1 instanceof FooClassImpl); + // next bit should in theory fail because FooClassImpl2 is not listed as a subtype + FooClass res2 = MAPPER.readValue(foo2, FooClass.class); + assertTrue(res2 instanceof FooClassImpl2); + } +} From 17edca8d05648c38c3337572b4326bf6df5e45c4 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Thu, 27 Mar 2025 23:39:14 +0100 Subject: [PATCH 02/13] pass subtypes --- .../jsontype/impl/ClassNameIdResolver.java | 25 +++++++++++++++++-- .../impl/MinimalClassNameIdResolver.java | 25 ++++++++++++++++++- .../jsontype/impl/StdTypeResolverBuilder.java | 4 +-- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index 9952a00640..0dffa5ed13 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.cfg.MapperConfig; +import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.util.ClassUtil; @@ -36,6 +37,7 @@ protected ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory) { /** * @since 2.10 + * @deprecated Since 2.19 use variant that takes {@link Collection} */ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, PolymorphicTypeValidator ptv) { @@ -43,11 +45,30 @@ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, _subTypeValidator = ptv; } - public static ClassNameIdResolver construct(JavaType baseType, MapperConfig config, - PolymorphicTypeValidator ptv) { + /** + * @since 2.19 + */ + public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, + Collection subtypes, PolymorphicTypeValidator ptv) { + super(baseType, typeFactory); + _subTypeValidator = ptv; + } + + @Deprecated(since = "2.19") + public static ClassNameIdResolver construct(JavaType baseType, + MapperConfig config, PolymorphicTypeValidator ptv) { return new ClassNameIdResolver(baseType, config.getTypeFactory(), ptv); } + /** + * @since 2.19 + */ + public static ClassNameIdResolver construct(JavaType baseType, MapperConfig config, + Collection subtypes, + PolymorphicTypeValidator ptv) { + return new ClassNameIdResolver(baseType, config.getTypeFactory(), subtypes, ptv); + } + @Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.CLASS; } diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java index c4f08b07b0..668b2df194 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java @@ -1,12 +1,14 @@ package com.fasterxml.jackson.databind.jsontype.impl; import java.io.IOException; +import java.util.Collection; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.databind.DatabindContext; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.cfg.MapperConfig; +import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; import com.fasterxml.jackson.databind.type.TypeFactory; @@ -32,8 +34,19 @@ public class MinimalClassNameIdResolver */ protected final String _basePackagePrefix; + @Deprecated(since = "2.19") protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, PolymorphicTypeValidator ptv) + { + this(baseType, typeFactory, null, ptv); + } + + /** + * @since 2.19 + */ + protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, + Collection subtypes, + PolymorphicTypeValidator ptv) { super(baseType, typeFactory, ptv); String base = baseType.getRawClass().getName(); @@ -47,11 +60,21 @@ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, } } + @Deprecated(since = "2.19") public static MinimalClassNameIdResolver construct(JavaType baseType, MapperConfig config, - PolymorphicTypeValidator ptv) { + PolymorphicTypeValidator ptv) { return new MinimalClassNameIdResolver(baseType, config.getTypeFactory(), ptv); } + /** + * @since 2.19 + */ + public static MinimalClassNameIdResolver construct(JavaType baseType, MapperConfig config, + Collection subtypes, + PolymorphicTypeValidator ptv) { + return new MinimalClassNameIdResolver(baseType, config.getTypeFactory(), subtypes, ptv); + } + @Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.MINIMAL_CLASS; } diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java index 988f39a165..a64f13da74 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java @@ -356,9 +356,9 @@ protected TypeIdResolver idResolver(MapperConfig config, switch (_idType) { case DEDUCTION: // Deduction produces class names to be resolved case CLASS: - return ClassNameIdResolver.construct(baseType, config, subtypeValidator); + return ClassNameIdResolver.construct(baseType, config, subtypes, subtypeValidator); case MINIMAL_CLASS: - return MinimalClassNameIdResolver.construct(baseType, config, subtypeValidator); + return MinimalClassNameIdResolver.construct(baseType, config, subtypes, subtypeValidator); case SIMPLE_NAME: return SimpleNameIdResolver.construct(config, baseType, subtypes, forSer, forDeser); case NAME: From 9fa9678d71f38c207fda646db1017e3426666c31 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 28 Mar 2025 00:14:50 +0100 Subject: [PATCH 03/13] Update ClassNameIdResolver.java --- .../jsontype/impl/ClassNameIdResolver.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index 0dffa5ed13..0de8cd211a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -27,6 +27,8 @@ public class ClassNameIdResolver protected final PolymorphicTypeValidator _subTypeValidator; + private Set _allowedSubtypes; + /** * @deprecated Since 2.10 use variant that takes {@link PolymorphicTypeValidator} */ @@ -41,8 +43,7 @@ protected ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory) { */ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, PolymorphicTypeValidator ptv) { - super(baseType, typeFactory); - _subTypeValidator = ptv; + this(baseType, typeFactory, null, ptv); } /** @@ -52,6 +53,15 @@ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, Collection subtypes, PolymorphicTypeValidator ptv) { super(baseType, typeFactory); _subTypeValidator = ptv; + if (subtypes != null) { + for (NamedType t : subtypes) { + final Class cls = t.getType(); + if (_allowedSubtypes == null) { + _allowedSubtypes = new HashSet<>(); + } + _allowedSubtypes.add(cls.getName()); + } + } } @Deprecated(since = "2.19") @@ -93,8 +103,13 @@ public JavaType typeFromId(DatabindContext context, String id) throws IOExceptio protected JavaType _typeFromId(String id, DatabindContext ctxt) throws IOException { - // 24-Apr-2019, tatu: [databind#2195] validate as well as resolve: - JavaType t = ctxt.resolveAndValidateSubType(_baseType, id, _subTypeValidator); + boolean allowed = true; + if (_allowedSubtypes != null) { + allowed = _allowedSubtypes.contains(id); + } + final JavaType t = allowed ? + ctxt.resolveAndValidateSubType(_baseType, id, _subTypeValidator) : + null; if (t == null) { if (ctxt instanceof DeserializationContext) { // First: we may have problem handlers that can deal with it? From 7c92fa8a0132dbe07dd0232a7b2feb6427ef92cc Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 28 Mar 2025 01:00:45 +0100 Subject: [PATCH 04/13] add feature --- .../databind/DeserializationFeature.java | 15 +++++++++++- .../jsontype/impl/ClassNameIdResolver.java | 24 ++++++++++--------- .../deser/PolymorphicIdClassDeserTest.java | 16 ++++++++----- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java index a1f2837fbc..dbcb40bafc 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java @@ -253,7 +253,7 @@ public enum DeserializationFeature implements ConfigFeature FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY(true), /** - * Feature that determines behaviour for data-binding after binding the root value. + * Feature that determines behavior for data-binding after binding the root value. * If feature is enabled, one more call to * {@link com.fasterxml.jackson.core.JsonParser#nextToken} is made to ensure that * no more tokens are found (and if any is found, @@ -272,6 +272,19 @@ public enum DeserializationFeature implements ConfigFeature */ FAIL_ON_TRAILING_TOKENS(false), + /** + * Feature that determines behavior when deserializing polymorphic types of + * Id.CLASS or Id.MINIMAL_CLASS type if the subtype is not explicitly registered. + * For types like Id.NAME, you already need to declare the subtypes but with + * Id.CLASS and Id.MINIMAL_CLASS you do not. If enabled, an exception will be + * thrown if a subtype is encountered that has not been explicitly registered. + *

+ * Feature is disabled by default. + * + * @since 2.19 + */ + FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED(false), + /** * Feature that determines whether Jackson code should catch * and wrap {@link Exception}s (but never {@link Error}s!) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index 0de8cd211a..e7c38e7f9f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -103,19 +103,21 @@ public JavaType typeFromId(DatabindContext context, String id) throws IOExceptio protected JavaType _typeFromId(String id, DatabindContext ctxt) throws IOException { - boolean allowed = true; - if (_allowedSubtypes != null) { - allowed = _allowedSubtypes.contains(id); + DeserializationContext deserializationContext = null; + if (ctxt instanceof DeserializationContext) { + deserializationContext = (DeserializationContext) ctxt; } - final JavaType t = allowed ? - ctxt.resolveAndValidateSubType(_baseType, id, _subTypeValidator) : - null; - if (t == null) { - if (ctxt instanceof DeserializationContext) { - // First: we may have problem handlers that can deal with it? - return ((DeserializationContext) ctxt).handleUnknownTypeId(_baseType, id, this, "no such class found"); + if (_allowedSubtypes != null && deserializationContext != null + && deserializationContext.isEnabled( + DeserializationFeature.FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED)) { + if (!_allowedSubtypes.contains(id)) { + throw deserializationContext.invalidTypeIdException(_baseType, id, + "DeserializationFeature.FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED is explicitly enabled and the input class is not registered using JsonSubTypes annotation."); } - // ... meaning that we really should never get here. + } + final JavaType t = ctxt.resolveAndValidateSubType(_baseType, id, _subTypeValidator); + if (t == null && deserializationContext != null) { + return deserializationContext.handleUnknownTypeId(_baseType, id, this, "no such class found"); } return t; } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java index 5bfb65eda7..fa56de32e4 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java @@ -2,14 +2,17 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializeUsingJDKTest; +import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; +import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; import org.junit.jupiter.api.Test; -import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.newJsonMapper; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -public class PolymorphicIdClassDeserTest { +public class PolymorphicIdClassDeserTest extends DatabindTestUtil { + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) @JsonSubTypes({@JsonSubTypes.Type(value = FooClassImpl.class)}) static abstract class FooClass { } @@ -22,7 +25,9 @@ static class FooClassImpl2 extends FooClass { } /************************************************************ */ - private final ObjectMapper MAPPER = newJsonMapper(); + private final ObjectMapper MAPPER = jsonMapperBuilder() + .enable(DeserializationFeature.FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED) + .build(); @Test public void testDeserialization() throws Exception @@ -33,7 +38,6 @@ public void testDeserialization() throws Exception FooClass res1 = MAPPER.readValue(foo1, FooClass.class); assertTrue(res1 instanceof FooClassImpl); // next bit should in theory fail because FooClassImpl2 is not listed as a subtype - FooClass res2 = MAPPER.readValue(foo2, FooClass.class); - assertTrue(res2 instanceof FooClassImpl2); + assertThrows(InvalidTypeIdException.class, () -> MAPPER.readValue(foo2, FooClass.class)); } } From a1d812a1111749dc52dba614150b13fb0610380b Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 28 Mar 2025 01:19:04 +0100 Subject: [PATCH 05/13] build issues --- .../databind/jsontype/impl/ClassNameIdResolver.java | 4 +++- .../jsontype/impl/MinimalClassNameIdResolver.java | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index e7c38e7f9f..c4e5ca719e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -64,7 +64,9 @@ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, } } - @Deprecated(since = "2.19") + /** + * @deprecated since 2.19 + */ public static ClassNameIdResolver construct(JavaType baseType, MapperConfig config, PolymorphicTypeValidator ptv) { return new ClassNameIdResolver(baseType, config.getTypeFactory(), ptv); diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java index 668b2df194..367aadfab0 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java @@ -34,7 +34,9 @@ public class MinimalClassNameIdResolver */ protected final String _basePackagePrefix; - @Deprecated(since = "2.19") + /** + * @deprecated since 2.19 + */ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, PolymorphicTypeValidator ptv) { @@ -60,7 +62,9 @@ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, } } - @Deprecated(since = "2.19") + /** + * @deprecated since 2.19 + */ public static MinimalClassNameIdResolver construct(JavaType baseType, MapperConfig config, PolymorphicTypeValidator ptv) { return new MinimalClassNameIdResolver(baseType, config.getTypeFactory(), ptv); From c81688fcdcd06382ef2b2341ee49302dd1c2f6c0 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 28 Mar 2025 20:43:12 +0100 Subject: [PATCH 06/13] change feature name --- .../fasterxml/jackson/databind/DeserializationFeature.java | 2 +- .../jackson/databind/jsontype/impl/ClassNameIdResolver.java | 4 ++-- .../jackson/databind/deser/PolymorphicIdClassDeserTest.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java index dbcb40bafc..bfe5202025 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java @@ -283,7 +283,7 @@ public enum DeserializationFeature implements ConfigFeature * * @since 2.19 */ - FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED(false), + FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED(false), /** * Feature that determines whether Jackson code should catch diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index c4e5ca719e..e71253b469 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -111,10 +111,10 @@ protected JavaType _typeFromId(String id, DatabindContext ctxt) throws IOExcepti } if (_allowedSubtypes != null && deserializationContext != null && deserializationContext.isEnabled( - DeserializationFeature.FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED)) { + DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED)) { if (!_allowedSubtypes.contains(id)) { throw deserializationContext.invalidTypeIdException(_baseType, id, - "DeserializationFeature.FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED is explicitly enabled and the input class is not registered using JsonSubTypes annotation."); + "DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED is explicitly enabled and the input class is not registered using JsonSubTypes annotation."); } } final JavaType t = ctxt.resolveAndValidateSubType(_baseType, id, _subTypeValidator); diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java index fa56de32e4..231e1e3918 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java @@ -26,7 +26,7 @@ static class FooClassImpl2 extends FooClass { } */ private final ObjectMapper MAPPER = jsonMapperBuilder() - .enable(DeserializationFeature.FAIL_ON_POLYMORPHIC_SUBTYPE_CLASS_NOT_EXPLICITLY_REGISTERED) + .enable(DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED) .build(); @Test From eb299c078c2de933666ce351956eb9e0d04300ba Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 28 Mar 2025 21:00:22 +0100 Subject: [PATCH 07/13] add test case --- .../impl/MinimalClassNameIdResolver.java | 2 +- .../deser/PolymorphicIdClassDeserTest.java | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java index 367aadfab0..0a0401f044 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java @@ -50,7 +50,7 @@ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, Collection subtypes, PolymorphicTypeValidator ptv) { - super(baseType, typeFactory, ptv); + super(baseType, typeFactory, subtypes, ptv); String base = baseType.getRawClass().getName(); int ix = base.lastIndexOf('.'); if (ix < 0) { // can this ever occur? diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java index 231e1e3918..4f2c1e5ee4 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java @@ -19,6 +19,12 @@ static abstract class FooClass { } static class FooClassImpl extends FooClass { } static class FooClassImpl2 extends FooClass { } + @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) + @JsonSubTypes({@JsonSubTypes.Type(value = FooMinClassImpl.class)}) + static abstract class FooMinClass { } + static class FooMinClassImpl extends FooMinClass { } + static class FooMinClassImpl2 extends FooMinClass { } + /* /************************************************************ /* Unit tests, valid @@ -30,7 +36,7 @@ static class FooClassImpl2 extends FooClass { } .build(); @Test - public void testDeserialization() throws Exception + public void testDeserializationIdClass() throws Exception { //trying to test if JsonSubTypes enforced final String foo1 = MAPPER.writeValueAsString(new FooClassImpl()); @@ -40,4 +46,16 @@ public void testDeserialization() throws Exception // next bit should in theory fail because FooClassImpl2 is not listed as a subtype assertThrows(InvalidTypeIdException.class, () -> MAPPER.readValue(foo2, FooClass.class)); } + + @Test + public void testDeserializationIdMinimalClass() throws Exception + { + //trying to test if JsonSubTypes enforced + final String foo1 = MAPPER.writeValueAsString(new FooMinClassImpl()); + final String foo2 = MAPPER.writeValueAsString(new FooMinClassImpl2()); + FooMinClass res1 = MAPPER.readValue(foo1, FooMinClass.class); + assertTrue(res1 instanceof FooMinClassImpl); + // next bit should in theory fail because FooMinClassImpl2 is not listed as a subtype + assertThrows(InvalidTypeIdException.class, () -> MAPPER.readValue(foo2, FooMinClass.class)); + } } From 03fc82a7bc4cf0c51b18c80f801ff8c3c2855241 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 28 Mar 2025 16:09:34 -0700 Subject: [PATCH 08/13] Minor tweaks --- .../jsontype/impl/ClassNameIdResolver.java | 20 +++++++++++-------- .../impl/MinimalClassNameIdResolver.java | 12 ++++++----- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index e71253b469..eb186023e6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -27,7 +27,7 @@ public class ClassNameIdResolver protected final PolymorphicTypeValidator _subTypeValidator; - private Set _allowedSubtypes; + protected final Set _allowedSubtypes; /** * @deprecated Since 2.10 use variant that takes {@link PolymorphicTypeValidator} @@ -39,8 +39,9 @@ protected ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory) { /** * @since 2.10 - * @deprecated Since 2.19 use variant that takes {@link Collection} + * @deprecated Since 2.19 use variant that takes {@code Collection} */ + @Deprecated public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, PolymorphicTypeValidator ptv) { this(baseType, typeFactory, null, ptv); @@ -50,23 +51,26 @@ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, * @since 2.19 */ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, - Collection subtypes, PolymorphicTypeValidator ptv) { + Collection subtypes, PolymorphicTypeValidator ptv) { super(baseType, typeFactory); _subTypeValidator = ptv; + Set allowedSubtypes = null; if (subtypes != null) { for (NamedType t : subtypes) { final Class cls = t.getType(); - if (_allowedSubtypes == null) { - _allowedSubtypes = new HashSet<>(); + if (allowedSubtypes == null) { + allowedSubtypes = new HashSet<>(); } - _allowedSubtypes.add(cls.getName()); + allowedSubtypes.add(cls.getName()); } } + _allowedSubtypes = allowedSubtypes; } /** * @deprecated since 2.19 */ + @Deprecated public static ClassNameIdResolver construct(JavaType baseType, MapperConfig config, PolymorphicTypeValidator ptv) { return new ClassNameIdResolver(baseType, config.getTypeFactory(), ptv); @@ -76,8 +80,8 @@ public static ClassNameIdResolver construct(JavaType baseType, * @since 2.19 */ public static ClassNameIdResolver construct(JavaType baseType, MapperConfig config, - Collection subtypes, - PolymorphicTypeValidator ptv) { + Collection subtypes, + PolymorphicTypeValidator ptv) { return new ClassNameIdResolver(baseType, config.getTypeFactory(), subtypes, ptv); } diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java index 0a0401f044..9db48c8894 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/MinimalClassNameIdResolver.java @@ -37,6 +37,7 @@ public class MinimalClassNameIdResolver /** * @deprecated since 2.19 */ + @Deprecated protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, PolymorphicTypeValidator ptv) { @@ -47,8 +48,8 @@ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, * @since 2.19 */ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, - Collection subtypes, - PolymorphicTypeValidator ptv) + Collection subtypes, + PolymorphicTypeValidator ptv) { super(baseType, typeFactory, subtypes, ptv); String base = baseType.getRawClass().getName(); @@ -65,8 +66,9 @@ protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, /** * @deprecated since 2.19 */ + @Deprecated public static MinimalClassNameIdResolver construct(JavaType baseType, MapperConfig config, - PolymorphicTypeValidator ptv) { + PolymorphicTypeValidator ptv) { return new MinimalClassNameIdResolver(baseType, config.getTypeFactory(), ptv); } @@ -74,8 +76,8 @@ public static MinimalClassNameIdResolver construct(JavaType baseType, MapperConf * @since 2.19 */ public static MinimalClassNameIdResolver construct(JavaType baseType, MapperConfig config, - Collection subtypes, - PolymorphicTypeValidator ptv) { + Collection subtypes, + PolymorphicTypeValidator ptv) { return new MinimalClassNameIdResolver(baseType, config.getTypeFactory(), subtypes, ptv); } From f422ff6fcf171c8f11e8b051e011536409d0a4d1 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 28 Mar 2025 16:21:27 -0700 Subject: [PATCH 09/13] Deprecate one method --- .../jackson/databind/jsontype/impl/ClassNameIdResolver.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index eb186023e6..1794e2d2a3 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -88,6 +88,8 @@ public static ClassNameIdResolver construct(JavaType baseType, MapperConfig c @Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.CLASS; } + // 28-Mar-2025, tatu: Why is this here; not overridden so... ? + @Deprecated // since 2.19 public void registerSubtype(Class type, String name) { // not used with class name - based resolvers } @@ -113,12 +115,12 @@ protected JavaType _typeFromId(String id, DatabindContext ctxt) throws IOExcepti if (ctxt instanceof DeserializationContext) { deserializationContext = (DeserializationContext) ctxt; } - if (_allowedSubtypes != null && deserializationContext != null + if ((_allowedSubtypes != null) && (deserializationContext != null) && deserializationContext.isEnabled( DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED)) { if (!_allowedSubtypes.contains(id)) { throw deserializationContext.invalidTypeIdException(_baseType, id, - "DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED is explicitly enabled and the input class is not registered using JsonSubTypes annotation."); +"`DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED` is enabled and the input class is not registered using `@JsonSubTypes` annotation"); } } final JavaType t = ctxt.resolveAndValidateSubType(_baseType, id, _subTypeValidator); From 46243d4af4bfe376b78cbb4ba3feba35630700bd Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 28 Mar 2025 18:14:14 -0700 Subject: [PATCH 10/13] Add "jackson-benchmarks" as downstream build dep --- .github/workflows/trigger_dep_builds_v2.yml | 1 + .github/workflows/trigger_dep_builds_v3.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/trigger_dep_builds_v2.yml b/.github/workflows/trigger_dep_builds_v2.yml index dbf63dd7c6..2c31657de3 100644 --- a/.github/workflows/trigger_dep_builds_v2.yml +++ b/.github/workflows/trigger_dep_builds_v2.yml @@ -29,6 +29,7 @@ jobs: - 'FasterXML/jackson-jaxrs-providers' - 'FasterXML/jackson-jakarta-rs-providers' - 'FasterXML/jackson-integration-tests' + - 'FasterXML/jackson-benchmarks' steps: - name: Repository dispatch diff --git a/.github/workflows/trigger_dep_builds_v3.yml b/.github/workflows/trigger_dep_builds_v3.yml index 46c45d554b..575bca646e 100644 --- a/.github/workflows/trigger_dep_builds_v3.yml +++ b/.github/workflows/trigger_dep_builds_v3.yml @@ -29,6 +29,7 @@ jobs: - 'FasterXML/jackson-jaxrs-providers' - 'FasterXML/jackson-jakarta-rs-providers' - 'FasterXML/jackson-integration-tests' + - 'FasterXML/jackson-benchmarks' steps: - name: Repository dispatch From ca3ddfd5fc5902d6ec4daeed6b81d3a4ecb3edcb Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sat, 29 Mar 2025 20:07:10 +0100 Subject: [PATCH 11/13] fail if no subtype registered --- .../jsontype/impl/ClassNameIdResolver.java | 8 ++------ .../deser/PolymorphicIdClassDeserTest.java | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index 1794e2d2a3..2b9c90f46f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -54,14 +54,10 @@ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, Collection subtypes, PolymorphicTypeValidator ptv) { super(baseType, typeFactory); _subTypeValidator = ptv; - Set allowedSubtypes = null; + Set allowedSubtypes = new HashSet<>(); if (subtypes != null) { for (NamedType t : subtypes) { - final Class cls = t.getType(); - if (allowedSubtypes == null) { - allowedSubtypes = new HashSet<>(); - } - allowedSubtypes.add(cls.getName()); + allowedSubtypes.add(t.getType().getName()); } } _allowedSubtypes = allowedSubtypes; diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java index 4f2c1e5ee4..f116d16d31 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java @@ -19,6 +19,10 @@ static abstract class FooClass { } static class FooClassImpl extends FooClass { } static class FooClassImpl2 extends FooClass { } + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) + static abstract class FooClassNoRegSubTypes { } + static class FooClassNoRegSubTypesImpl extends FooClassNoRegSubTypes { } + @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS) @JsonSubTypes({@JsonSubTypes.Type(value = FooMinClassImpl.class)}) static abstract class FooMinClass { } @@ -43,10 +47,19 @@ public void testDeserializationIdClass() throws Exception final String foo2 = MAPPER.writeValueAsString(new FooClassImpl2()); FooClass res1 = MAPPER.readValue(foo1, FooClass.class); assertTrue(res1 instanceof FooClassImpl); - // next bit should in theory fail because FooClassImpl2 is not listed as a subtype + // next bit should fail because FooClassImpl2 is not listed as a subtype (see mapper config) assertThrows(InvalidTypeIdException.class, () -> MAPPER.readValue(foo2, FooClass.class)); } + @Test + public void testDeserializationIdClassNoReg() throws Exception + { + //trying to test if JsonSubTypes enforced + final String foo1 = MAPPER.writeValueAsString(new FooClassNoRegSubTypesImpl()); + // next bit should fail because FooClassImpl2 is not listed as a subtype (see mapper config) + assertThrows(InvalidTypeIdException.class, () -> MAPPER.readValue(foo1, FooClassNoRegSubTypes.class)); + } + @Test public void testDeserializationIdMinimalClass() throws Exception { @@ -55,7 +68,7 @@ public void testDeserializationIdMinimalClass() throws Exception final String foo2 = MAPPER.writeValueAsString(new FooMinClassImpl2()); FooMinClass res1 = MAPPER.readValue(foo1, FooMinClass.class); assertTrue(res1 instanceof FooMinClassImpl); - // next bit should in theory fail because FooMinClassImpl2 is not listed as a subtype + // next bit should fail because FooMinClassImpl2 is not listed as a subtype (see mapper config) assertThrows(InvalidTypeIdException.class, () -> MAPPER.readValue(foo2, FooMinClass.class)); } } From 14135d8caa1b54c8c6790d137df31f1c253419b6 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sat, 29 Mar 2025 20:09:49 +0100 Subject: [PATCH 12/13] Update PolymorphicIdClassDeserTest.java --- .../databind/deser/PolymorphicIdClassDeserTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java index f116d16d31..818f7dc1ec 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java @@ -53,6 +53,16 @@ public void testDeserializationIdClass() throws Exception @Test public void testDeserializationIdClassNoReg() throws Exception + { + final ObjectMapper mapper = newJsonMapper(); + final String foo1 = mapper.writeValueAsString(new FooClassNoRegSubTypesImpl()); + // the default mapper should be able to deserialize the object (sub type check not enforced) + FooClassNoRegSubTypes res1 = mapper.readValue(foo1, FooClassNoRegSubTypes.class); + assertTrue(res1 instanceof FooClassNoRegSubTypesImpl); + } + + @Test + public void testDefaultDeserializationIdClassNoReg() throws Exception { //trying to test if JsonSubTypes enforced final String foo1 = MAPPER.writeValueAsString(new FooClassNoRegSubTypesImpl()); From a1a4054c95474e68a595d7caf22055efd30ec7c0 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 30 Mar 2025 18:38:12 -0700 Subject: [PATCH 13/13] Minor pre-merge tweaks --- release-notes/VERSION-2.x | 2 ++ .../jackson/databind/DeserializationFeature.java | 15 ++++++++++----- .../jsontype/impl/ClassNameIdResolver.java | 10 ++++++++-- .../RegisteredClassDeser5027Test.java} | 7 ++++--- 4 files changed, 24 insertions(+), 10 deletions(-) rename src/test/java/com/fasterxml/jackson/databind/{deser/PolymorphicIdClassDeserTest.java => jsontype/RegisteredClassDeser5027Test.java} (96%) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 079e2cd69d..013cd88b7d 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -76,6 +76,8 @@ Project: jackson-databind failure of `java.util.Optional` (de)serialization without Java 8 module #5014: Add `java.lang.Runnable` as unsafe base type in `DefaultBaseTypeLimitingValidator` #5020: Support new `@JsonProperty.isRequired` for overridable definition of "required-ness" +#5027: Add `DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED` + (contributed by @pjfanning) #5052: Minor bug in `FirstCharBasedValidator.forFirstNameRule()`: returns `null` in non-default case diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java index bfe5202025..4918e41173 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationFeature.java @@ -273,11 +273,16 @@ public enum DeserializationFeature implements ConfigFeature FAIL_ON_TRAILING_TOKENS(false), /** - * Feature that determines behavior when deserializing polymorphic types of - * Id.CLASS or Id.MINIMAL_CLASS type if the subtype is not explicitly registered. - * For types like Id.NAME, you already need to declare the subtypes but with - * Id.CLASS and Id.MINIMAL_CLASS you do not. If enabled, an exception will be - * thrown if a subtype is encountered that has not been explicitly registered. + * Feature that determines behavior when deserializing polymorphic types that use + * Class-based Type Id mechanism (either + * {@code JsonTypeInfo.Id.CLASS} or {@code JsonTypeInfo.Id.MINIMAL_CLASS}): + * If enabled, an exception will be + * thrown if a subtype (Class) is encountered that has not been explicitly registered (by + * calling {@link ObjectMapper#registerSubtypes} or + * {@link com.fasterxml.jackson.annotation.JsonSubTypes}). + *

+ * Note that for Type Name - based Type Id mechanism ({@code JsonTypeInfo.Id.NAME}) + * you already need to register the subtypes but with so this feature has no effect. *

* Feature is disabled by default. * diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index 2b9c90f46f..42cd3a32b7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -27,6 +27,9 @@ public class ClassNameIdResolver protected final PolymorphicTypeValidator _subTypeValidator; + /** + * @since 2.19 (to support {@code DeserializationFeature.FAIL_ON_SUBTYPE_CLASS_NOT_REGISTERED}) + */ protected final Set _allowedSubtypes; /** @@ -54,13 +57,16 @@ public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory, Collection subtypes, PolymorphicTypeValidator ptv) { super(baseType, typeFactory); _subTypeValidator = ptv; - Set allowedSubtypes = new HashSet<>(); + Set allowedSubtypes = null; if (subtypes != null) { for (NamedType t : subtypes) { + if (allowedSubtypes == null) { + allowedSubtypes = new HashSet<>(); + } allowedSubtypes.add(t.getType().getName()); } } - _allowedSubtypes = allowedSubtypes; + _allowedSubtypes = (allowedSubtypes == null) ? Collections.emptySet() : allowedSubtypes; } /** diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/RegisteredClassDeser5027Test.java similarity index 96% rename from src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java rename to src/test/java/com/fasterxml/jackson/databind/jsontype/RegisteredClassDeser5027Test.java index 818f7dc1ec..f98d331090 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PolymorphicIdClassDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/RegisteredClassDeser5027Test.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.databind.deser; +package com.fasterxml.jackson.databind.jsontype; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -11,8 +11,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -public class PolymorphicIdClassDeserTest extends DatabindTestUtil { - +// For [databind#5027] +public class RegisteredClassDeser5027Test extends DatabindTestUtil +{ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) @JsonSubTypes({@JsonSubTypes.Type(value = FooClassImpl.class)}) static abstract class FooClass { }