From 228bc0ef4a59dd47422603a59812768153ddd1c8 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Mon, 22 May 2023 09:59:02 +0900 Subject: [PATCH 01/34] Add tests for `Record` deserialization regression and related (#3921) --- .../RecordDeserialization3906Test.java | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 src/test-jdk14/java/com/fasterxml/jackson/databind/failing/RecordDeserialization3906Test.java diff --git a/src/test-jdk14/java/com/fasterxml/jackson/databind/failing/RecordDeserialization3906Test.java b/src/test-jdk14/java/com/fasterxml/jackson/databind/failing/RecordDeserialization3906Test.java new file mode 100644 index 0000000000..dcc9a00029 --- /dev/null +++ b/src/test-jdk14/java/com/fasterxml/jackson/databind/failing/RecordDeserialization3906Test.java @@ -0,0 +1,161 @@ +package com.fasterxml.jackson.databind.failing; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.AnnotatedClass; +import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; +import com.fasterxml.jackson.databind.introspect.VisibilityChecker; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Test case that covers both failing-by-regression tests and passing tests. + *

For more details, refer to + * + * [databind#3906]: Regression: 2.15.0 breaks deserialization for records when mapper.setVisibility(ALL, NONE); + */ +public class RecordDeserialization3906Test extends BaseMapTest { + + /* + /********************************************************** + /* Set up + /********************************************************** + */ + + record Record3906(String string, int integer) { + } + + @JsonAutoDetect(creatorVisibility = Visibility.NON_PRIVATE) + record Record3906Annotated(String string, int integer) { + } + + record Record3906Creator(String string, int integer) { + @JsonCreator + Record3906Creator { + } + } + + private record PrivateRecord3906(String string, int integer) { + } + + /* + /********************************************************** + /* Failing tests that pass in 2.14 (regression) + /********************************************************** + */ + + // minimal config for reproduction + public void testEmptyJsonToRecordMiminal() throws JsonProcessingException { + ObjectMapper mapper = newJsonMapper(); + mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); + + Record3906 recordDeser = mapper.readValue("{}", Record3906.class); + + assertEquals(new Record3906(null, 0), recordDeser); + } + + // actual config used reproduction + public void testEmptyJsonToRecordActualImpl() throws JsonProcessingException { + ObjectMapper mapper = newJsonMapper(); + mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); + mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); + + Record3906 recordDeser = mapper.readValue("{}", Record3906.class); + + assertEquals(new Record3906(null, 0), recordDeser); + } + + /* + /********************************************************** + /* Passing Tests : Suggested work-arounds + /* for future modifications + /********************************************************** + */ + + public void testEmptyJsonToRecordWorkAround() throws JsonProcessingException { + ObjectMapper mapper = newJsonMapper(); + mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); + mapper.setVisibility(PropertyAccessor.CREATOR, Visibility.ANY); + + Record3906 recordDeser = mapper.readValue("{}", Record3906.class); + + assertEquals(new Record3906(null, 0), recordDeser); + } + + public void testEmptyJsonToRecordCreatorsVisibile() throws JsonProcessingException { + ObjectMapper mapper = newJsonMapper(); + mapper.setVisibility(PropertyAccessor.CREATOR, Visibility.NON_PRIVATE); + + Record3906 recordDeser = mapper.readValue("{}", Record3906.class); + assertEquals(new Record3906(null, 0), recordDeser); + } + + public void testEmptyJsonToRecordUsingModule() throws JsonProcessingException { + ObjectMapper mapper = jsonMapperBuilder().addModule(new SimpleModule() { + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + context.insertAnnotationIntrospector(new NopAnnotationIntrospector() { + @Override + public VisibilityChecker findAutoDetectVisibility(AnnotatedClass ac, + VisibilityChecker checker) { + return ac.getType().isRecordType() + ? checker.withCreatorVisibility(JsonAutoDetect.Visibility.NON_PRIVATE) + : checker; + } + }); + } + }).build(); + + Record3906 recordDeser = mapper.readValue("{}", Record3906.class); + assertEquals(new Record3906(null, 0), recordDeser); + } + + public void testEmptyJsonToRecordDirectAutoDetectConfig() throws JsonProcessingException { + ObjectMapper mapper = newJsonMapper(); + + Record3906Annotated recordDeser = mapper.readValue("{}", Record3906Annotated.class); + assertEquals(new Record3906Annotated(null, 0), recordDeser); + } + + public void testEmptyJsonToRecordJsonCreator() throws JsonProcessingException { + ObjectMapper mapper = newJsonMapper(); + + Record3906Creator recordDeser = mapper.readValue("{}", Record3906Creator.class); + assertEquals(new Record3906Creator(null, 0), recordDeser); + } + + public void testEmptyJsonToRecordUsingModuleOther() throws JsonProcessingException { + ObjectMapper mapper = jsonMapperBuilder().addModule( + new SimpleModule() { + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + context.insertAnnotationIntrospector(new NopAnnotationIntrospector() { + @Override + public VisibilityChecker findAutoDetectVisibility(AnnotatedClass ac, + VisibilityChecker checker) { + if (ac.getType() == null) { + return checker; + } + if (!ac.getType().isRecordType()) { + return checker; + } + // If this is a Record, then increase the "creator" visibility again + return checker.withCreatorVisibility(Visibility.ANY); + } + }); + } + }) + .build(); + + assertEquals(new Record3906(null, 0), + mapper.readValue("{}", Record3906.class)); + assertEquals(new PrivateRecord3906(null, 0), + mapper.readValue("{}", PrivateRecord3906.class)); + } +} From 79c232fa8442f8ef490f0bb6cdf04d9a30095d2a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Fri, 19 May 2023 23:52:20 +0900 Subject: [PATCH 02/34] Backport findPolymorphicTypeInfo --- .../JacksonAnnotationIntrospector.java | 25 +++++++++++-------- .../jsontype/impl/StdTypeResolverBuilder.java | 5 ++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index dfeaee6888..134443ba2d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1508,24 +1508,29 @@ protected PropertyName _findConstructorName(Annotated a) protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { + // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 + final AnnotationIntrospector ai = config.getAnnotationIntrospector(); + JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); + + JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); + // First: maybe we have explicit type resolver? TypeResolverBuilder b; - JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class); if (resAnn != null) { - if (info == null) { + if (typeInfo == null) { return null; } // let's not try to force access override (would need to pass // settings through if we did, since that's not doable on some platforms) b = config.typeResolverBuilderInstance(ann, resAnn.value()); } else { // if not, use standard one, if indicated by annotations - if (info == null) { + if (typeInfo == null) { return null; } // bit special; must return 'marker' to block use of default typing: - if (info.use() == JsonTypeInfo.Id.NONE) { + if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } b = _constructStdTypeResolverBuilder(); @@ -1537,26 +1542,26 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } - b = b.init(info.use(), idRes); + b = b.init(typeInfo.getIdType(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = info.include(); + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { inclusion = JsonTypeInfo.As.PROPERTY; } b = b.inclusion(inclusion); - b = b.typeProperty(info.property()); - Class defaultImpl = info.defaultImpl(); + b = b.typeProperty(typeInfo.getPropertyName()); + Class defaultImpl = typeInfo.getDefaultImpl(); // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - if (defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { + if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { b = b.defaultImpl(defaultImpl); } - b = b.typeIdVisibility(info.visible()); + b = b.typeIdVisibility(typeInfo.getIdVisible()); return b; } 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 a98b92c0ed..a08026a613 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 @@ -1,5 +1,6 @@ package com.fasterxml.jackson.databind.jsontype.impl; +import com.fasterxml.jackson.databind.introspect.Annotated; import java.util.Collection; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -436,11 +437,11 @@ protected boolean _strictTypeIdHandling(DeserializationConfig config, JavaType b * * @return true if the class has type resolver annotations, false otherwise * - * @since 2.15 + * @since 2.15, using {@code ai.findPolymorphicTypeInfo(config, ac)} since 2.16. */ protected boolean _hasTypeResolver(DeserializationConfig config, JavaType baseType) { AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config, baseType.getRawClass()); AnnotationIntrospector ai = config.getAnnotationIntrospector(); - return ai.findTypeResolver(config, ac, baseType) != null; + return ai.findPolymorphicTypeInfo(config, ac) != null; } } From 8cabbd96c340df518ceb2da54a309ae30ce58c57 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 00:01:19 +0900 Subject: [PATCH 03/34] Clean up unnccessary change. --- .../databind/introspect/JacksonAnnotationIntrospector.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 134443ba2d..2072eb537f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1512,8 +1512,6 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, final AnnotationIntrospector ai = config.getAnnotationIntrospector(); JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); - JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); - // First: maybe we have explicit type resolver? TypeResolverBuilder b; JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class); From 0b30af1ac6a38f077017a9cea2989b8ded50bec4 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:23:27 +0900 Subject: [PATCH 04/34] Use Value class around TypeResolverBuilder --- .../JacksonAnnotationIntrospector.java | 29 ++++++----- .../jsontype/TypeResolverBuilder.java | 15 ++++++ .../jsontype/impl/StdTypeResolverBuilder.java | 49 +++++++++++++++++++ .../ser/jdk/MapKeySerializationTest.java | 22 +++++++++ 4 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 2072eb537f..521872d468 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1531,7 +1531,7 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } - b = _constructStdTypeResolverBuilder(); + b = _constructStdTypeResolverBuilder(config, typeInfo, baseType); } // Does it define a custom type id resolver? JsonTypeIdResolver idResInfo = _findAnnotation(ann, JsonTypeIdResolver.class); @@ -1540,35 +1540,38 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } - b = b.init(typeInfo.getIdType(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); - if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - inclusion = JsonTypeInfo.As.PROPERTY; + if (ann instanceof AnnotatedClass) { + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { + typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); + } } - b = b.inclusion(inclusion); - b = b.typeProperty(typeInfo.getPropertyName()); - Class defaultImpl = typeInfo.getDefaultImpl(); - + // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) + Class defaultImpl = typeInfo.getDefaultImpl(); if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { - b = b.defaultImpl(defaultImpl); + typeInfo = typeInfo.withDefaultImpl(defaultImpl); } - b = b.typeIdVisibility(typeInfo.getIdVisible()); + + b = b.init(typeInfo, idRes); return b; } /** * Helper method for constructing standard {@link TypeResolverBuilder} * implementation. + * + * @since 2.16, backported from 3.0 */ - protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() { - return new StdTypeResolverBuilder(); + protected TypeResolverBuilder _constructStdTypeResolverBuilder(MapperConfig config, + JsonTypeInfo.Value typeInfo, JavaType baseType) { + return new StdTypeResolverBuilder(typeInfo); } /** diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index d1d592866b..a72bdade03 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -97,6 +97,21 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); + + /** + * Initialization method that is called right after constructing + * the builder instance, in cases where information could not be + * passed directly (for example when instantiated for an annotation) + * + * @param settings Configuration settings to apply. + * + * @return Resulting builder instance (usually this builder, + * but not necessarily) + * + * @since 2.16 + */ + public T init(JsonTypeInfo.Value settings, TypeIdResolver res); + /* /********************************************************** 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 a08026a613..ffc1714aa6 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 @@ -35,6 +35,8 @@ public class StdTypeResolverBuilder * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; + + protected Boolean _requireTypeIdForSubtypes; /** * Default class to use in case type information is not available @@ -54,6 +56,27 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } + public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + _typeProperty = _propName(settings.getPropertyName(), _idType); + _typeIdVisible = settings.getIdVisible(); + _defaultImpl = settings.getDefaultImpl(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + } + + protected static String _propName(String propName, JsonTypeInfo.Id idType) { + if (propName == null) { + propName = idType.getDefaultPropertyName(); + } + return propName; + } + /** * @since 2.9 */ @@ -79,6 +102,7 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, _customIdResolver = base._customIdResolver; _defaultImpl = defaultImpl; + _requireTypeIdForSubtypes = base._requireTypeIdForSubtypes; } public static StdTypeResolverBuilder noTypeInfoBuilder() { @@ -99,6 +123,31 @@ public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes) return this; } + @Override + public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, + TypeIdResolver idRes) + { + _customIdResolver = idRes; + + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + + // Let's also initialize property name as per idType default + _typeProperty = settings.getPropertyName(); + if (_typeProperty == null) { + _typeProperty = _idType.getDefaultPropertyName(); + } + _typeIdVisible = settings.getIdVisible(); + _defaultImpl = settings.getDefaultImpl(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + return this; + } + @Override public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java index 2765ddb9d3..c9a77a84fa 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java @@ -256,6 +256,28 @@ public void testUnWrappedMapWithDefaultType() throws Exception{ assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); } + // [databind#838] + public void testUnWrappedMapWithDefaultTypeWithValue() throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + SimpleModule mod = new SimpleModule("test"); + mod.addKeySerializer(ABC.class, new ABCKeySerializer()); + mapper.registerModule(mod); + + TypeResolverBuilder typer = ObjectMapper.DefaultTypeResolverBuilder.construct( + ObjectMapper.DefaultTyping.NON_FINAL, mapper.getPolymorphicTypeValidator()); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NAME, JsonTypeInfo.As.PROPERTY, + null, null, true, null); + typer.init(typeInfo, null); + mapper.setDefaultTyping(typer); + + Map stuff = new HashMap(); + stuff.put(ABC.B, "bar"); + String json = mapper.writerFor(new TypeReference>() { + }) + .writeValueAsString(stuff); + assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); + } + // [databind#1552] public void testMapsWithBinaryKeys() throws Exception { From a509ac284eac32158326b725f4199a522305cc99 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:30:46 +0900 Subject: [PATCH 05/34] Clean up changes --- .../introspect/JacksonAnnotationIntrospector.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 521872d468..57245a4289 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1543,18 +1543,16 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - if (ann instanceof AnnotatedClass) { - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); - if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); - } + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { + typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); } - + Class defaultImpl = typeInfo.getDefaultImpl(); + // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - Class defaultImpl = typeInfo.getDefaultImpl(); if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { typeInfo = typeInfo.withDefaultImpl(defaultImpl); } From 97c14f1bee9ff0831cad6fadbf100813d9b01faa Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:58:43 +0900 Subject: [PATCH 06/34] Add version changes in StdTypeResolverBuilder --- .../jsontype/impl/StdTypeResolverBuilder.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 ffc1714aa6..bfe90a1710 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 @@ -35,7 +35,10 @@ public class StdTypeResolverBuilder * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; - + + /** + * @since 2.16 (backported from Jackson 3.0) + */ protected Boolean _requireTypeIdForSubtypes; /** @@ -56,6 +59,9 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } + /** + * @since 2.16 (backported from Jackson 3.0) + */ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { if (settings != null) { _idType = settings.getIdType(); @@ -70,6 +76,9 @@ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { } } + /** + * @since 2.16 (backported from Jackson 3.0) + */ protected static String _propName(String propName, JsonTypeInfo.Id idType) { if (propName == null) { propName = idType.getDefaultPropertyName(); From 3b7733971d8096ae817c0a44b141a5cd674a9f95 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 21 May 2023 00:32:07 +0900 Subject: [PATCH 07/34] Replace usage of TypeResolverBuilder.init --- .../com/fasterxml/jackson/databind/ObjectMapper.java | 11 ++++++----- .../databind/jsontype/TypeResolverBuilder.java | 5 +++-- .../jsontype/impl/StdTypeResolverBuilder.java | 4 +++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 0ce19c8689..b263403d64 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -1993,8 +1993,9 @@ public ObjectMapper activateDefaultTyping(PolymorphicTypeValidator ptv, TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, ptv); // we'll always use full class name, when using defaulting - typer = typer.init(JsonTypeInfo.Id.CLASS, null); - typer = typer.inclusion(includeAs); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.CLASS, includeAs, + null, null, false, null); + typer = typer.init(typeInfo, null); return setDefaultTyping(typer); } @@ -2023,9 +2024,9 @@ public ObjectMapper activateDefaultTypingAsProperty(PolymorphicTypeValidator ptv TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, ptv); // we'll always use full class name, when using defaulting - typer = typer.init(JsonTypeInfo.Id.CLASS, null); - typer = typer.inclusion(JsonTypeInfo.As.PROPERTY); - typer = typer.typeProperty(propertyName); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.CLASS, JsonTypeInfo.As.PROPERTY, + propertyName, null, false, null); + typer = typer.init(typeInfo, null); return setDefaultTyping(typer); } diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index a72bdade03..d43a5930f5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -15,8 +15,9 @@ * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

- * Builder is first initialized by calling {@link #init} method, and then - * configured using 'set' methods like {@link #inclusion}. + * Builder is first initialized by calling {@link #init(JsonTypeInfo.Value, TypeIdResolver)} method, with + * configurations passed in through {@link JsonTypeInfo.Value} that is constructed by + * {@link JsonTypeInfo.Value#construct(JsonTypeInfo.Id, As, String, Class, boolean, Boolean)}. * Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed 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 bfe90a1710..b3432755ca 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 @@ -115,7 +115,9 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, } public static StdTypeResolverBuilder noTypeInfoBuilder() { - return new StdTypeResolverBuilder().init(JsonTypeInfo.Id.NONE, null); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, + null, null, false, null); + return new StdTypeResolverBuilder().init(typeInfo, null); } @Override From 57b740e675a5907704b64db26fa38f579f0da590 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Mon, 22 May 2023 12:54:41 +0900 Subject: [PATCH 08/34] Apply review --- .../introspect/JacksonAnnotationIntrospector.java | 3 +-- .../databind/jsontype/TypeResolverBuilder.java | 11 +++++++---- .../databind/ser/jdk/MapKeySerializationTest.java | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 57245a4289..2b94b737d9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1509,8 +1509,7 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 - final AnnotationIntrospector ai = config.getAnnotationIntrospector(); - JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); + JsonTypeInfo.Value typeInfo = findPolymorphicTypeInfo(config, ann); // First: maybe we have explicit type resolver? TypeResolverBuilder b; diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index d43a5930f5..eb5c1dbbd6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -103,16 +103,19 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * Initialization method that is called right after constructing * the builder instance, in cases where information could not be * passed directly (for example when instantiated for an annotation) + *

+ * NOTE: This method will be abstract in Jackson 3.0. * * @param settings Configuration settings to apply. * * @return Resulting builder instance (usually this builder, * but not necessarily) - * - * @since 2.16 + * + * @since 2.16 (backported from Jackson 3.0) */ - public T init(JsonTypeInfo.Value settings, TypeIdResolver res); - + default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { + return init(settings.getIdType(), res); + } /* /********************************************************** diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java index c9a77a84fa..a34d787b4f 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java @@ -256,7 +256,6 @@ public void testUnWrappedMapWithDefaultType() throws Exception{ assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); } - // [databind#838] public void testUnWrappedMapWithDefaultTypeWithValue() throws Exception { final ObjectMapper mapper = new ObjectMapper(); SimpleModule mod = new SimpleModule("test"); From 04b8ed2aed7995d7c3d38f2c77829b9c08b751c8 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 23 May 2023 10:14:25 +0900 Subject: [PATCH 09/34] Add behavioral test regarding `transient` field with annotation (#3951) --- .../introspect/Transient3948Test.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/introspect/Transient3948Test.java diff --git a/src/test/java/com/fasterxml/jackson/databind/introspect/Transient3948Test.java b/src/test/java/com/fasterxml/jackson/databind/introspect/Transient3948Test.java new file mode 100644 index 0000000000..7f7859be87 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/introspect/Transient3948Test.java @@ -0,0 +1,67 @@ +package com.fasterxml.jackson.databind.introspect; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.Serializable; + +public class Transient3948Test extends BaseMapTest { + + @JsonPropertyOrder(alphabetic = true) + static class Obj implements Serializable { + + private static final long serialVersionUID = -1L; + + private String a = "hello"; + + @JsonIgnore + private transient String b = "world"; + + @JsonProperty("cat") + private String c = "jackson"; + + @JsonProperty("dog") + private transient String d = "databind"; + + public String getA() { + return a; + } + + public String getB() { + return b; + } + + public String getC() { + return c; + } + + public String getD() { + return d; + } + } + + final ObjectMapper DEFAULT_MAPPER = newJsonMapper(); + + final ObjectMapper MAPPER_TRANSIENT = jsonMapperBuilder() + .configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true) + .build(); + + public void testJsonIgnoreSerialization() throws Exception { + Obj obj1 = new Obj(); + + String json = DEFAULT_MAPPER.writeValueAsString(obj1); + + assertEquals(a2q("{'a':'hello','b':'world','cat':'jackson','dog':'databind'}"), json); + } + + public void testJsonIgnoreSerializationTransient() throws Exception { + Obj obj1 = new Obj(); + + String json = MAPPER_TRANSIENT.writeValueAsString(obj1); + + assertEquals(a2q("{'a':'hello','cat':'jackson','dog':'databind'}"), json); + } +} From 35059904aeadcace2083044722deb67615dd4bf5 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 22 May 2023 18:21:54 -0700 Subject: [PATCH 10/34] Update Maven wrapper version --- .mvn/wrapper/maven-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 305f3b65c2..a36fc474ef 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar From 58b9fc9e2f4132d7d245c6faddec18656300eef1 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 23 May 2023 11:24:44 +0900 Subject: [PATCH 11/34] Backport `TypeResolverBuilder` initialization mechanisms from Jackson 3.0 (#3949) --- .../jsontype/TypeResolverBuilder.java | 18 +++++++ .../jsontype/impl/StdTypeResolverBuilder.java | 52 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index d1d592866b..10dfd83f12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -98,6 +98,24 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); + /** + * Initialization method that is called right after constructing + * the builder instance, in cases where information could not be + * passed directly (for example when instantiated for an annotation) + *

+ * NOTE: This method is abstract in Jackson 3.0, at the moment of writing. + * + * @param settings Configuration settings to apply. + * + * @return Resulting builder instance (usually this builder, + * but not necessarily) + * + * @since 2.16 (backported from Jackson 3.0) + */ + default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { + return init(settings.getIdType(), res); + } + /* /********************************************************** /* Methods for configuring resolver to build 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 a98b92c0ed..df9c66ed21 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 @@ -80,6 +80,31 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, _defaultImpl = defaultImpl; } + /** + * @since 2.16 (backported from Jackson 3.0) + */ + public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + _typeProperty = _propName(settings.getPropertyName(), _idType); + _defaultImpl = settings.getDefaultImpl(); + } + } + + /** + * @since 2.16 (backported from Jackson 3.0) + */ + protected static String _propName(String propName, JsonTypeInfo.Id idType) { + if (propName == null) { + propName = idType.getDefaultPropertyName(); + } + return propName; + } + public static StdTypeResolverBuilder noTypeInfoBuilder() { return new StdTypeResolverBuilder().init(JsonTypeInfo.Id.NONE, null); } @@ -98,6 +123,33 @@ public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes) return this; } + /** + * @since 2.16 (backported from Jackson 3.0) + */ + @Override + public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, + TypeIdResolver idRes) + { + _customIdResolver = idRes; + + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + + // Let's also initialize property name as per idType default + _typeProperty = settings.getPropertyName(); + if (_typeProperty == null) { + _typeProperty = _idType.getDefaultPropertyName(); + } + _typeIdVisible = settings.getIdVisible(); + _defaultImpl = settings.getDefaultImpl(); + } + return this; + } + @Override public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes) From cc02b19bce73f69a62317edabcf1ee76b65411c3 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 22 May 2023 20:02:36 -0700 Subject: [PATCH 12/34] remove obsolete "optimize" property --- pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3728c5cd96..e43b8115a1 100644 --- a/pom.xml +++ b/pom.xml @@ -321,7 +321,6 @@ maven-compiler-plugin true - true 14 14 @@ -375,7 +374,6 @@ maven-compiler-plugin true - true 17 17 From a42a015767cae9c1616580b42aada64e4e90292a Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 22 May 2023 20:11:49 -0700 Subject: [PATCH 13/34] Start work on #3950: add skeletal IterationType (to merge to 3.0) --- .../jackson/databind/type/IterationType.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/java/com/fasterxml/jackson/databind/type/IterationType.java diff --git a/src/main/java/com/fasterxml/jackson/databind/type/IterationType.java b/src/main/java/com/fasterxml/jackson/databind/type/IterationType.java new file mode 100644 index 0000000000..1892a39533 --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/type/IterationType.java @@ -0,0 +1,29 @@ +package com.fasterxml.jackson.databind.type; + +import com.fasterxml.jackson.databind.JavaType; + +/** + * Specialized {@link SimpleType} for types that are allow iteration + * over Collection(-like) types: this includes types like + * {@link java.util.Iterator}. + * Referenced type is accessible using {@link #getContentType()}. + * + * @since 2.16 + */ +public abstract class IterationType extends SimpleType +{ + private static final long serialVersionUID = 1L; + + protected final JavaType _iteratedType; + + /** + * Constructor used when upgrading into this type (via {@link #upgradeFrom}, + * the usual way for {@link IterationType}s to come into existence. + * Sets up what is considered the "base" reference type + */ + protected IterationType(TypeBase base, JavaType iteratedType) + { + super(base); + _iteratedType = iteratedType; + } +} From dcffc4167cf57cd85206d0a5f737b921c351010a Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 22 May 2023 20:23:49 -0700 Subject: [PATCH 14/34] Minor removal of deprecated "narrow" method implementation from JavaType (deprecated in 2.7) --- .../fasterxml/jackson/databind/JavaType.java | 4 +- .../jackson/databind/type/ArrayType.java | 14 ------ .../databind/type/CollectionLikeType.java | 8 ---- .../jackson/databind/type/CollectionType.java | 7 --- .../jackson/databind/type/MapLikeType.java | 9 ---- .../jackson/databind/type/MapType.java | 8 ---- .../databind/type/PlaceholderForType.java | 6 --- .../jackson/databind/type/ReferenceType.java | 26 ++++------ .../databind/type/ResolvedRecursiveType.java | 6 --- .../jackson/databind/type/SimpleType.java | 48 ------------------- .../jackson/databind/type/TestJavaType.java | 4 -- 11 files changed, 13 insertions(+), 127 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/JavaType.java b/src/main/java/com/fasterxml/jackson/databind/JavaType.java index aae3285a3d..1323b52ac5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JavaType.java +++ b/src/main/java/com/fasterxml/jackson/databind/JavaType.java @@ -254,7 +254,9 @@ public JavaType forcedNarrowBy(Class subclass) } @Deprecated // since 2.7 - protected abstract JavaType _narrow(Class subclass); + protected JavaType _narrow(Class subclass) { + return this; + } /* /********************************************************************** diff --git a/src/main/java/com/fasterxml/jackson/databind/type/ArrayType.java b/src/main/java/com/fasterxml/jackson/databind/type/ArrayType.java index 877ebe4436..5b6d655667 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/ArrayType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/ArrayType.java @@ -106,16 +106,6 @@ public ArrayType withStaticTyping() { /********************************************************** */ - /** - * Handling of narrowing conversions for arrays is trickier: for now, - * it is not even allowed. - */ - @Override - @Deprecated // since 2.7 - protected JavaType _narrow(Class subclass) { - return _reportUnsupported(); - } - // Should not be called, as array types in Java are not extensible; but // let's not freak out even if it is called? @Override @@ -124,10 +114,6 @@ public JavaType refine(Class contentClass, TypeBindings bindings, return null; } - private JavaType _reportUnsupported() { - throw new UnsupportedOperationException("Cannot narrow or widen array types"); - } - /* /********************************************************** /* Overridden methods diff --git a/src/main/java/com/fasterxml/jackson/databind/type/CollectionLikeType.java b/src/main/java/com/fasterxml/jackson/databind/type/CollectionLikeType.java index fd4179a466..64422dc5f4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/CollectionLikeType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/CollectionLikeType.java @@ -89,14 +89,6 @@ public static CollectionLikeType upgradeFrom(JavaType baseType, JavaType element throw new IllegalArgumentException("Cannot upgrade from an instance of "+baseType.getClass()); } - @Override - @Deprecated // since 2.7 - protected JavaType _narrow(Class subclass) { - return new CollectionLikeType(subclass, _bindings, - _superClass, _superInterfaces, _elementType, - _valueHandler, _typeHandler, _asStatic); - } - @Override public JavaType withContentType(JavaType contentType) { if (_elementType == contentType) { diff --git a/src/main/java/com/fasterxml/jackson/databind/type/CollectionType.java b/src/main/java/com/fasterxml/jackson/databind/type/CollectionType.java index e8b176c500..ecf985dc9e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/CollectionType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/CollectionType.java @@ -61,13 +61,6 @@ public static CollectionType construct(Class rawType, JavaType elemT) { null, null, false); } - @Deprecated // since 2.7 - @Override - protected JavaType _narrow(Class subclass) { - return new CollectionType(subclass, _bindings, - _superClass, _superInterfaces, _elementType, null, null, _asStatic); - } - @Override public JavaType withContentType(JavaType contentType) { if (_elementType == contentType) { diff --git a/src/main/java/com/fasterxml/jackson/databind/type/MapLikeType.java b/src/main/java/com/fasterxml/jackson/databind/type/MapLikeType.java index d745e981e4..36342b9b81 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/MapLikeType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/MapLikeType.java @@ -87,15 +87,6 @@ public static MapLikeType construct(Class rawType, JavaType keyT, null, keyT, valueT, null, null, false); } - @Deprecated - // since 2.7 - @Override - protected JavaType _narrow(Class subclass) { - return new MapLikeType(subclass, _bindings, _superClass, - _superInterfaces, _keyType, _valueType, _valueHandler, - _typeHandler, _asStatic); - } - /** * @since 2.7 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/type/MapType.java b/src/main/java/com/fasterxml/jackson/databind/type/MapType.java index cec9166db3..a469298eea 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/MapType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/MapType.java @@ -57,14 +57,6 @@ public static MapType construct(Class rawType, JavaType keyT, JavaType valueT keyT, valueT, null, null, false); } - @Deprecated // since 2.7 - @Override - protected JavaType _narrow(Class subclass) { - return new MapType(subclass, _bindings, - _superClass, _superInterfaces, _keyType, _valueType, - _valueHandler, _typeHandler, _asStatic); - } - @Override public MapType withTypeHandler(Object h) { return new MapType(_class, _bindings, diff --git a/src/main/java/com/fasterxml/jackson/databind/type/PlaceholderForType.java b/src/main/java/com/fasterxml/jackson/databind/type/PlaceholderForType.java index 31b17de881..4ffa28fff4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/PlaceholderForType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/PlaceholderForType.java @@ -83,12 +83,6 @@ public JavaType refine(Class rawType, TypeBindings bindings, JavaType superCl return _unsupported(); } - @Override - @Deprecated // since 2.7 - protected JavaType _narrow(Class subclass) { - return _unsupported(); - } - @Override public boolean isContainerType() { return false; diff --git a/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java b/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java index 271c4a5458..7c0eea65a3 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java @@ -25,7 +25,10 @@ public class ReferenceType extends SimpleType * if being sub-classed. * * @since 2.8 + * + * @deprecated Since 2.16 */ + @Deprecated protected final JavaType _anchorType; protected ReferenceType(Class cls, TypeBindings bindings, @@ -174,22 +177,6 @@ protected String buildCanonicalName() return sb.toString(); } - /* - /********************************************************** - /* Narrow/widen - /********************************************************** - */ - - @Override - @Deprecated // since 2.7 - protected JavaType _narrow(Class subclass) - { - // Should we check that there is a sub-class relationship? - return new ReferenceType(subclass, _bindings, - _superClass, _superInterfaces, _referencedType, _anchorType, - _valueHandler, _typeHandler, _asStatic); - } - /* /********************************************************** /* Public API overrides @@ -237,6 +224,10 @@ public StringBuilder getGenericSignature(StringBuilder sb) /********************************************************** */ + /** + * @deprecated Since 2.16 + */ + @Deprecated public JavaType getAnchorType() { return _anchorType; } @@ -244,7 +235,10 @@ public JavaType getAnchorType() { /** * Convenience accessor that allows checking whether this is the anchor type * itself; if not, it must be one of supertypes that is also a {@link ReferenceType} + * + * @deprecated Since 2.16 */ + @Deprecated public boolean isAnchorType() { return (_anchorType == this); } diff --git a/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java b/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java index b6867d347c..9cd29a8825 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/ResolvedRecursiveType.java @@ -95,12 +95,6 @@ public JavaType withStaticTyping() { return this; } - @Deprecated // since 2.7 - @Override - protected JavaType _narrow(Class subclass) { - return this; - } - @Override public JavaType refine(Class rawType, TypeBindings bindings, JavaType superClass, JavaType[] superInterfaces) { diff --git a/src/main/java/com/fasterxml/jackson/databind/type/SimpleType.java b/src/main/java/com/fasterxml/jackson/databind/type/SimpleType.java index 4669d10020..a76310db54 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/SimpleType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/SimpleType.java @@ -122,54 +122,6 @@ public static SimpleType construct(Class cls) _buildSuperClass(cls.getSuperclass(), b), null, null, null, false); } - @Override - @Deprecated - protected JavaType _narrow(Class subclass) - { - if (_class == subclass) { - return this; - } - // Should we check that there is a sub-class relationship? - // 15-Jan-2016, tatu: Almost yes, but there are some complications with - // placeholder values (`Void`, `NoClass`), so cannot quite do yet. - // TODO: fix in 2.9 - if (!_class.isAssignableFrom(subclass)) { - /* - throw new IllegalArgumentException("Class "+subclass.getName()+" not sub-type of " - +_class.getName()); - */ - return new SimpleType(subclass, _bindings, this, _superInterfaces, - _valueHandler, _typeHandler, _asStatic); - } - // Otherwise, stitch together the hierarchy. First, super-class - Class next = subclass.getSuperclass(); - if (next == _class) { // straight up parent class? Great. - return new SimpleType(subclass, _bindings, this, - _superInterfaces, _valueHandler, _typeHandler, _asStatic); - } - if ((next != null) && _class.isAssignableFrom(next)) { - JavaType superb = _narrow(next); - return new SimpleType(subclass, _bindings, superb, - null, _valueHandler, _typeHandler, _asStatic); - } - // if not found, try a super-interface - Class[] nextI = subclass.getInterfaces(); - for (Class iface : nextI) { - if (iface == _class) { // directly implemented - return new SimpleType(subclass, _bindings, null, - new JavaType[] { this }, _valueHandler, _typeHandler, _asStatic); - } - if (_class.isAssignableFrom(iface)) { // indirect, so recurse - JavaType superb = _narrow(iface); - return new SimpleType(subclass, _bindings, null, - new JavaType[] { superb }, _valueHandler, _typeHandler, _asStatic); - } - } - // should not get here but... - throw new IllegalArgumentException("Internal error: Cannot resolve sub-type for Class "+subclass.getName()+" to " - +_class.getName()); - } - @Override public JavaType withContentType(JavaType contentType) { throw new IllegalArgumentException("Simple types have no content types; cannot call withContentType()"); diff --git a/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java b/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java index 2944e50c42..d70979d73e 100644 --- a/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java +++ b/src/test/java/com/fasterxml/jackson/databind/type/TestJavaType.java @@ -117,10 +117,6 @@ public void testDeprecated() assertNull(baseType.getContentValueHandler()); assertFalse(baseType.hasValueHandler()); assertFalse(baseType.hasHandlers()); - - assertSame(baseType, baseType.forcedNarrowBy(BaseType.class)); - JavaType sub = baseType.forcedNarrowBy(SubType.class); - assertTrue(sub.hasRawClass(SubType.class)); } public void testArrayType() From f878a669d2865a3268b5e3bcf72d1f103fd34c6e Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 22 May 2023 20:41:19 -0700 Subject: [PATCH 15/34] ... --- .../com/fasterxml/jackson/databind/type/ReferenceType.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java b/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java index 7c0eea65a3..11d2e8322b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/ReferenceType.java @@ -140,10 +140,9 @@ public ReferenceType withContentValueHandler(Object h) { if (h == _referencedType.getValueHandler()) { return this; } - JavaType refdType = _referencedType.withValueHandler(h); return new ReferenceType(_class, _bindings, - _superClass, _superInterfaces, refdType, _anchorType, - _valueHandler, _typeHandler, _asStatic); + _superClass, _superInterfaces, _referencedType.withValueHandler(h), + _anchorType, _valueHandler, _typeHandler, _asStatic); } @Override From 9991ffc501988cd6d6d32d5daa867b52e379fec0 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Fri, 19 May 2023 23:52:20 +0900 Subject: [PATCH 16/34] Backport findPolymorphicTypeInfo --- .../JacksonAnnotationIntrospector.java | 25 +++++++++++-------- .../jsontype/impl/StdTypeResolverBuilder.java | 5 ++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index dfeaee6888..134443ba2d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1508,24 +1508,29 @@ protected PropertyName _findConstructorName(Annotated a) protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { + // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 + final AnnotationIntrospector ai = config.getAnnotationIntrospector(); + JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); + + JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); + // First: maybe we have explicit type resolver? TypeResolverBuilder b; - JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class); if (resAnn != null) { - if (info == null) { + if (typeInfo == null) { return null; } // let's not try to force access override (would need to pass // settings through if we did, since that's not doable on some platforms) b = config.typeResolverBuilderInstance(ann, resAnn.value()); } else { // if not, use standard one, if indicated by annotations - if (info == null) { + if (typeInfo == null) { return null; } // bit special; must return 'marker' to block use of default typing: - if (info.use() == JsonTypeInfo.Id.NONE) { + if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } b = _constructStdTypeResolverBuilder(); @@ -1537,26 +1542,26 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } - b = b.init(info.use(), idRes); + b = b.init(typeInfo.getIdType(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = info.include(); + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { inclusion = JsonTypeInfo.As.PROPERTY; } b = b.inclusion(inclusion); - b = b.typeProperty(info.property()); - Class defaultImpl = info.defaultImpl(); + b = b.typeProperty(typeInfo.getPropertyName()); + Class defaultImpl = typeInfo.getDefaultImpl(); // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - if (defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { + if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { b = b.defaultImpl(defaultImpl); } - b = b.typeIdVisibility(info.visible()); + b = b.typeIdVisibility(typeInfo.getIdVisible()); return b; } 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 df9c66ed21..d1fd5a91ff 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 @@ -1,5 +1,6 @@ package com.fasterxml.jackson.databind.jsontype.impl; +import com.fasterxml.jackson.databind.introspect.Annotated; import java.util.Collection; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -488,11 +489,11 @@ protected boolean _strictTypeIdHandling(DeserializationConfig config, JavaType b * * @return true if the class has type resolver annotations, false otherwise * - * @since 2.15 + * @since 2.15, using {@code ai.findPolymorphicTypeInfo(config, ac)} since 2.16. */ protected boolean _hasTypeResolver(DeserializationConfig config, JavaType baseType) { AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config, baseType.getRawClass()); AnnotationIntrospector ai = config.getAnnotationIntrospector(); - return ai.findTypeResolver(config, ac, baseType) != null; + return ai.findPolymorphicTypeInfo(config, ac) != null; } } From 3cb02a4a9fc76b01fd57f43206def17081a19c28 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 00:01:19 +0900 Subject: [PATCH 17/34] Clean up unnccessary change. --- .../databind/introspect/JacksonAnnotationIntrospector.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 134443ba2d..2072eb537f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1512,8 +1512,6 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, final AnnotationIntrospector ai = config.getAnnotationIntrospector(); JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); - JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); - // First: maybe we have explicit type resolver? TypeResolverBuilder b; JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class); From bcb1c27fdc65e0604d485cd7c6e6ba2b68a5c6f2 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:23:27 +0900 Subject: [PATCH 18/34] Use Value class around TypeResolverBuilder --- .../JacksonAnnotationIntrospector.java | 29 ++++++----- .../jsontype/TypeResolverBuilder.java | 15 ++++++ .../jsontype/impl/StdTypeResolverBuilder.java | 49 +++++++++++++++++++ .../ser/jdk/MapKeySerializationTest.java | 22 +++++++++ 4 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 2072eb537f..521872d468 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1531,7 +1531,7 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } - b = _constructStdTypeResolverBuilder(); + b = _constructStdTypeResolverBuilder(config, typeInfo, baseType); } // Does it define a custom type id resolver? JsonTypeIdResolver idResInfo = _findAnnotation(ann, JsonTypeIdResolver.class); @@ -1540,35 +1540,38 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } - b = b.init(typeInfo.getIdType(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); - if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - inclusion = JsonTypeInfo.As.PROPERTY; + if (ann instanceof AnnotatedClass) { + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { + typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); + } } - b = b.inclusion(inclusion); - b = b.typeProperty(typeInfo.getPropertyName()); - Class defaultImpl = typeInfo.getDefaultImpl(); - + // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) + Class defaultImpl = typeInfo.getDefaultImpl(); if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { - b = b.defaultImpl(defaultImpl); + typeInfo = typeInfo.withDefaultImpl(defaultImpl); } - b = b.typeIdVisibility(typeInfo.getIdVisible()); + + b = b.init(typeInfo, idRes); return b; } /** * Helper method for constructing standard {@link TypeResolverBuilder} * implementation. + * + * @since 2.16, backported from 3.0 */ - protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() { - return new StdTypeResolverBuilder(); + protected TypeResolverBuilder _constructStdTypeResolverBuilder(MapperConfig config, + JsonTypeInfo.Value typeInfo, JavaType baseType) { + return new StdTypeResolverBuilder(typeInfo); } /** diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 10dfd83f12..041e751ba5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -97,6 +97,21 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); + + /** + * Initialization method that is called right after constructing + * the builder instance, in cases where information could not be + * passed directly (for example when instantiated for an annotation) + * + * @param settings Configuration settings to apply. + * + * @return Resulting builder instance (usually this builder, + * but not necessarily) + * + * @since 2.16 + */ + public T init(JsonTypeInfo.Value settings, TypeIdResolver res); + /** * Initialization method that is called right after constructing 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 d1fd5a91ff..e0fe9f6de6 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 @@ -35,6 +35,8 @@ public class StdTypeResolverBuilder * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; + + protected Boolean _requireTypeIdForSubtypes; /** * Default class to use in case type information is not available @@ -54,6 +56,27 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } + public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + _typeProperty = _propName(settings.getPropertyName(), _idType); + _typeIdVisible = settings.getIdVisible(); + _defaultImpl = settings.getDefaultImpl(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + } + + protected static String _propName(String propName, JsonTypeInfo.Id idType) { + if (propName == null) { + propName = idType.getDefaultPropertyName(); + } + return propName; + } + /** * @since 2.9 */ @@ -79,6 +102,7 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, _customIdResolver = base._customIdResolver; _defaultImpl = defaultImpl; + _requireTypeIdForSubtypes = base._requireTypeIdForSubtypes; } /** @@ -151,6 +175,31 @@ public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, return this; } + @Override + public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, + TypeIdResolver idRes) + { + _customIdResolver = idRes; + + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + + // Let's also initialize property name as per idType default + _typeProperty = settings.getPropertyName(); + if (_typeProperty == null) { + _typeProperty = _idType.getDefaultPropertyName(); + } + _typeIdVisible = settings.getIdVisible(); + _defaultImpl = settings.getDefaultImpl(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + return this; + } + @Override public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java index 2765ddb9d3..c9a77a84fa 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java @@ -256,6 +256,28 @@ public void testUnWrappedMapWithDefaultType() throws Exception{ assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); } + // [databind#838] + public void testUnWrappedMapWithDefaultTypeWithValue() throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + SimpleModule mod = new SimpleModule("test"); + mod.addKeySerializer(ABC.class, new ABCKeySerializer()); + mapper.registerModule(mod); + + TypeResolverBuilder typer = ObjectMapper.DefaultTypeResolverBuilder.construct( + ObjectMapper.DefaultTyping.NON_FINAL, mapper.getPolymorphicTypeValidator()); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NAME, JsonTypeInfo.As.PROPERTY, + null, null, true, null); + typer.init(typeInfo, null); + mapper.setDefaultTyping(typer); + + Map stuff = new HashMap(); + stuff.put(ABC.B, "bar"); + String json = mapper.writerFor(new TypeReference>() { + }) + .writeValueAsString(stuff); + assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); + } + // [databind#1552] public void testMapsWithBinaryKeys() throws Exception { From 0d472b356f03e988f5c78b36cef10694185b72d5 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:30:46 +0900 Subject: [PATCH 19/34] Clean up changes --- .../introspect/JacksonAnnotationIntrospector.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 521872d468..57245a4289 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1543,18 +1543,16 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - if (ann instanceof AnnotatedClass) { - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); - if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); - } + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { + typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); } - + Class defaultImpl = typeInfo.getDefaultImpl(); + // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - Class defaultImpl = typeInfo.getDefaultImpl(); if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { typeInfo = typeInfo.withDefaultImpl(defaultImpl); } From 8d63f6728525cda8655180e41a9c8dac5bf14c0d Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:58:43 +0900 Subject: [PATCH 20/34] Add version changes in StdTypeResolverBuilder --- .../jsontype/impl/StdTypeResolverBuilder.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 e0fe9f6de6..ae0697eb7b 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 @@ -35,7 +35,10 @@ public class StdTypeResolverBuilder * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; - + + /** + * @since 2.16 (backported from Jackson 3.0) + */ protected Boolean _requireTypeIdForSubtypes; /** @@ -56,6 +59,9 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } + /** + * @since 2.16 (backported from Jackson 3.0) + */ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { if (settings != null) { _idType = settings.getIdType(); @@ -70,6 +76,9 @@ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { } } + /** + * @since 2.16 (backported from Jackson 3.0) + */ protected static String _propName(String propName, JsonTypeInfo.Id idType) { if (propName == null) { propName = idType.getDefaultPropertyName(); From 94a66c6e12e5e1e4d46c65e0bdd61ce15029f7ea Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 21 May 2023 00:32:07 +0900 Subject: [PATCH 21/34] Replace usage of TypeResolverBuilder.init --- .../com/fasterxml/jackson/databind/ObjectMapper.java | 11 ++++++----- .../databind/jsontype/TypeResolverBuilder.java | 5 +++-- .../jsontype/impl/StdTypeResolverBuilder.java | 4 +++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 0ce19c8689..b263403d64 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -1993,8 +1993,9 @@ public ObjectMapper activateDefaultTyping(PolymorphicTypeValidator ptv, TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, ptv); // we'll always use full class name, when using defaulting - typer = typer.init(JsonTypeInfo.Id.CLASS, null); - typer = typer.inclusion(includeAs); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.CLASS, includeAs, + null, null, false, null); + typer = typer.init(typeInfo, null); return setDefaultTyping(typer); } @@ -2023,9 +2024,9 @@ public ObjectMapper activateDefaultTypingAsProperty(PolymorphicTypeValidator ptv TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, ptv); // we'll always use full class name, when using defaulting - typer = typer.init(JsonTypeInfo.Id.CLASS, null); - typer = typer.inclusion(JsonTypeInfo.As.PROPERTY); - typer = typer.typeProperty(propertyName); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.CLASS, JsonTypeInfo.As.PROPERTY, + propertyName, null, false, null); + typer = typer.init(typeInfo, null); return setDefaultTyping(typer); } diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 041e751ba5..8137fcd906 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -15,8 +15,9 @@ * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

- * Builder is first initialized by calling {@link #init} method, and then - * configured using 'set' methods like {@link #inclusion}. + * Builder is first initialized by calling {@link #init(JsonTypeInfo.Value, TypeIdResolver)} method, with + * configurations passed in through {@link JsonTypeInfo.Value} that is constructed by + * {@link JsonTypeInfo.Value#construct(JsonTypeInfo.Id, As, String, Class, boolean, Boolean)}. * Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed 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 ae0697eb7b..fa3d278ba4 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 @@ -140,7 +140,9 @@ protected static String _propName(String propName, JsonTypeInfo.Id idType) { } public static StdTypeResolverBuilder noTypeInfoBuilder() { - return new StdTypeResolverBuilder().init(JsonTypeInfo.Id.NONE, null); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, + null, null, false, null); + return new StdTypeResolverBuilder().init(typeInfo, null); } @Override From 3d5d2a806fad36040b7d4bd04a5f067f77873cd1 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Mon, 22 May 2023 12:54:41 +0900 Subject: [PATCH 22/34] Apply review --- .../introspect/JacksonAnnotationIntrospector.java | 3 +-- .../databind/jsontype/TypeResolverBuilder.java | 11 +++++++---- .../databind/ser/jdk/MapKeySerializationTest.java | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 57245a4289..2b94b737d9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1509,8 +1509,7 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 - final AnnotationIntrospector ai = config.getAnnotationIntrospector(); - JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); + JsonTypeInfo.Value typeInfo = findPolymorphicTypeInfo(config, ann); // First: maybe we have explicit type resolver? TypeResolverBuilder b; diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 8137fcd906..0d65d2f974 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -103,16 +103,19 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * Initialization method that is called right after constructing * the builder instance, in cases where information could not be * passed directly (for example when instantiated for an annotation) + *

+ * NOTE: This method will be abstract in Jackson 3.0. * * @param settings Configuration settings to apply. * * @return Resulting builder instance (usually this builder, * but not necessarily) - * - * @since 2.16 + * + * @since 2.16 (backported from Jackson 3.0) */ - public T init(JsonTypeInfo.Value settings, TypeIdResolver res); - + default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { + return init(settings.getIdType(), res); + } /** * Initialization method that is called right after constructing diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java index c9a77a84fa..a34d787b4f 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java @@ -256,7 +256,6 @@ public void testUnWrappedMapWithDefaultType() throws Exception{ assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); } - // [databind#838] public void testUnWrappedMapWithDefaultTypeWithValue() throws Exception { final ObjectMapper mapper = new ObjectMapper(); SimpleModule mod = new SimpleModule("test"); From c30d8a6eaee4b2cf33d3b618ed84affcea721195 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 23 May 2023 22:31:46 +0900 Subject: [PATCH 23/34] Remove unnccessary changes --- .../jsontype/TypeResolverBuilder.java | 23 +------- .../jsontype/impl/StdTypeResolverBuilder.java | 54 +------------------ 2 files changed, 4 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 0d65d2f974..10dfd83f12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -15,9 +15,8 @@ * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

- * Builder is first initialized by calling {@link #init(JsonTypeInfo.Value, TypeIdResolver)} method, with - * configurations passed in through {@link JsonTypeInfo.Value} that is constructed by - * {@link JsonTypeInfo.Value#construct(JsonTypeInfo.Id, As, String, Class, boolean, Boolean)}. + * Builder is first initialized by calling {@link #init} method, and then + * configured using 'set' methods like {@link #inclusion}. * Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed @@ -98,24 +97,6 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); - - /** - * Initialization method that is called right after constructing - * the builder instance, in cases where information could not be - * passed directly (for example when instantiated for an annotation) - *

- * NOTE: This method will be abstract in Jackson 3.0. - * - * @param settings Configuration settings to apply. - * - * @return Resulting builder instance (usually this builder, - * but not necessarily) - * - * @since 2.16 (backported from Jackson 3.0) - */ - default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { - return init(settings.getIdType(), res); - } /** * Initialization method that is called right after constructing 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 fa3d278ba4..b32b61c6f3 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 @@ -1,6 +1,5 @@ package com.fasterxml.jackson.databind.jsontype.impl; -import com.fasterxml.jackson.databind.introspect.Annotated; import java.util.Collection; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -59,33 +58,6 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } - /** - * @since 2.16 (backported from Jackson 3.0) - */ - public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { - if (settings != null) { - _idType = settings.getIdType(); - if (_idType == null) { - throw new IllegalArgumentException("idType cannot be null"); - } - _includeAs = settings.getInclusionType(); - _typeProperty = _propName(settings.getPropertyName(), _idType); - _typeIdVisible = settings.getIdVisible(); - _defaultImpl = settings.getDefaultImpl(); - _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); - } - } - - /** - * @since 2.16 (backported from Jackson 3.0) - */ - protected static String _propName(String propName, JsonTypeInfo.Id idType) { - if (propName == null) { - propName = idType.getDefaultPropertyName(); - } - return propName; - } - /** * @since 2.9 */ @@ -126,6 +98,8 @@ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { _includeAs = settings.getInclusionType(); _typeProperty = _propName(settings.getPropertyName(), _idType); _defaultImpl = settings.getDefaultImpl(); + _typeIdVisible = settings.getIdVisible(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); } } @@ -162,30 +136,6 @@ public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes) /** * @since 2.16 (backported from Jackson 3.0) */ - @Override - public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, - TypeIdResolver idRes) - { - _customIdResolver = idRes; - - if (settings != null) { - _idType = settings.getIdType(); - if (_idType == null) { - throw new IllegalArgumentException("idType cannot be null"); - } - _includeAs = settings.getInclusionType(); - - // Let's also initialize property name as per idType default - _typeProperty = settings.getPropertyName(); - if (_typeProperty == null) { - _typeProperty = _idType.getDefaultPropertyName(); - } - _typeIdVisible = settings.getIdVisible(); - _defaultImpl = settings.getDefaultImpl(); - } - return this; - } - @Override public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, TypeIdResolver idRes) From 3761d1bb540783b7368d9f368861b08e9643b754 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 23 May 2023 22:36:50 +0900 Subject: [PATCH 24/34] Remove conflicting change in TypeResolverBuilder --- .../jsontype/TypeResolverBuilder.java | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 0d65d2f974..10dfd83f12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -15,9 +15,8 @@ * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

- * Builder is first initialized by calling {@link #init(JsonTypeInfo.Value, TypeIdResolver)} method, with - * configurations passed in through {@link JsonTypeInfo.Value} that is constructed by - * {@link JsonTypeInfo.Value#construct(JsonTypeInfo.Id, As, String, Class, boolean, Boolean)}. + * Builder is first initialized by calling {@link #init} method, and then + * configured using 'set' methods like {@link #inclusion}. * Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed @@ -98,24 +97,6 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); - - /** - * Initialization method that is called right after constructing - * the builder instance, in cases where information could not be - * passed directly (for example when instantiated for an annotation) - *

- * NOTE: This method will be abstract in Jackson 3.0. - * - * @param settings Configuration settings to apply. - * - * @return Resulting builder instance (usually this builder, - * but not necessarily) - * - * @since 2.16 (backported from Jackson 3.0) - */ - default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { - return init(settings.getIdType(), res); - } /** * Initialization method that is called right after constructing From 90edb76ca1e3ccdbf1c96c8d561e3440255d25b8 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 23 May 2023 22:55:55 +0900 Subject: [PATCH 25/34] Revert "Merge branch 'Introduce-JsonTypeInfo.Value' of https://github.com/JooHyukKim/jackson-databind into Introduce-JsonTypeInfo.Value" This reverts commit 93983d3eb17e3cca569518d07a38516e81c13365, reversing changes made to c30d8a6eaee4b2cf33d3b618ed84affcea721195. --- .../jsontype/impl/StdTypeResolverBuilder.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) 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 97c1d06c01..b32b61c6f3 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 @@ -58,33 +58,6 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } - /** - * @since 2.16 (backported from Jackson 3.0) - */ - public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { - if (settings != null) { - _idType = settings.getIdType(); - if (_idType == null) { - throw new IllegalArgumentException("idType cannot be null"); - } - _includeAs = settings.getInclusionType(); - _typeProperty = _propName(settings.getPropertyName(), _idType); - _typeIdVisible = settings.getIdVisible(); - _defaultImpl = settings.getDefaultImpl(); - _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); - } - } - - /** - * @since 2.16 (backported from Jackson 3.0) - */ - protected static String _propName(String propName, JsonTypeInfo.Id idType) { - if (propName == null) { - propName = idType.getDefaultPropertyName(); - } - return propName; - } - /** * @since 2.9 */ @@ -113,8 +86,36 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, _requireTypeIdForSubtypes = base._requireTypeIdForSubtypes; } + /** + * @since 2.16 (backported from Jackson 3.0) + */ + public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + _typeProperty = _propName(settings.getPropertyName(), _idType); + _defaultImpl = settings.getDefaultImpl(); + _typeIdVisible = settings.getIdVisible(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + } + + /** + * @since 2.16 (backported from Jackson 3.0) + */ + protected static String _propName(String propName, JsonTypeInfo.Id idType) { + if (propName == null) { + propName = idType.getDefaultPropertyName(); + } + return propName; + } + public static StdTypeResolverBuilder noTypeInfoBuilder() { - JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, null, null, false, null); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, + null, null, false, null); return new StdTypeResolverBuilder().init(typeInfo, null); } @@ -155,6 +156,7 @@ public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, } _typeIdVisible = settings.getIdVisible(); _defaultImpl = settings.getDefaultImpl(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); } return this; } From 7fdc0e72a8531dc98e16a5f23e51ad1413db187a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Fri, 19 May 2023 23:52:20 +0900 Subject: [PATCH 26/34] Backport findPolymorphicTypeInfo --- .../JacksonAnnotationIntrospector.java | 35 +++++++++---------- .../jsontype/impl/StdTypeResolverBuilder.java | 1 + 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 2b94b737d9..dfeaee6888 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1508,29 +1508,27 @@ protected PropertyName _findConstructorName(Annotated a) protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { - // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 - JsonTypeInfo.Value typeInfo = findPolymorphicTypeInfo(config, ann); - // First: maybe we have explicit type resolver? TypeResolverBuilder b; + JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class); if (resAnn != null) { - if (typeInfo == null) { + if (info == null) { return null; } // let's not try to force access override (would need to pass // settings through if we did, since that's not doable on some platforms) b = config.typeResolverBuilderInstance(ann, resAnn.value()); } else { // if not, use standard one, if indicated by annotations - if (typeInfo == null) { + if (info == null) { return null; } // bit special; must return 'marker' to block use of default typing: - if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { + if (info.use() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } - b = _constructStdTypeResolverBuilder(config, typeInfo, baseType); + b = _constructStdTypeResolverBuilder(); } // Does it define a custom type id resolver? JsonTypeIdResolver idResInfo = _findAnnotation(ann, JsonTypeIdResolver.class); @@ -1539,36 +1537,35 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } + b = b.init(info.use(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + JsonTypeInfo.As inclusion = info.include(); if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); + inclusion = JsonTypeInfo.As.PROPERTY; } - Class defaultImpl = typeInfo.getDefaultImpl(); + b = b.inclusion(inclusion); + b = b.typeProperty(info.property()); + Class defaultImpl = info.defaultImpl(); // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { - typeInfo = typeInfo.withDefaultImpl(defaultImpl); + if (defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { + b = b.defaultImpl(defaultImpl); } - - b = b.init(typeInfo, idRes); + b = b.typeIdVisibility(info.visible()); return b; } /** * Helper method for constructing standard {@link TypeResolverBuilder} * implementation. - * - * @since 2.16, backported from 3.0 */ - protected TypeResolverBuilder _constructStdTypeResolverBuilder(MapperConfig config, - JsonTypeInfo.Value typeInfo, JavaType baseType) { - return new StdTypeResolverBuilder(typeInfo); + protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() { + return new StdTypeResolverBuilder(); } /** 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 b32b61c6f3..442ccbaa93 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 @@ -1,5 +1,6 @@ package com.fasterxml.jackson.databind.jsontype.impl; +import com.fasterxml.jackson.databind.introspect.Annotated; import java.util.Collection; import com.fasterxml.jackson.annotation.JsonTypeInfo; From d8d3990627100505f57d9723cef17dd3079125dc Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 00:01:19 +0900 Subject: [PATCH 27/34] Clean up unnccessary change. --- .../JacksonAnnotationIntrospector.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index dfeaee6888..2072eb537f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1508,24 +1508,27 @@ protected PropertyName _findConstructorName(Annotated a) protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { + // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 + final AnnotationIntrospector ai = config.getAnnotationIntrospector(); + JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); + // First: maybe we have explicit type resolver? TypeResolverBuilder b; - JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class); JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class); if (resAnn != null) { - if (info == null) { + if (typeInfo == null) { return null; } // let's not try to force access override (would need to pass // settings through if we did, since that's not doable on some platforms) b = config.typeResolverBuilderInstance(ann, resAnn.value()); } else { // if not, use standard one, if indicated by annotations - if (info == null) { + if (typeInfo == null) { return null; } // bit special; must return 'marker' to block use of default typing: - if (info.use() == JsonTypeInfo.Id.NONE) { + if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } b = _constructStdTypeResolverBuilder(); @@ -1537,26 +1540,26 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } - b = b.init(info.use(), idRes); + b = b.init(typeInfo.getIdType(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = info.include(); + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { inclusion = JsonTypeInfo.As.PROPERTY; } b = b.inclusion(inclusion); - b = b.typeProperty(info.property()); - Class defaultImpl = info.defaultImpl(); + b = b.typeProperty(typeInfo.getPropertyName()); + Class defaultImpl = typeInfo.getDefaultImpl(); // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - if (defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { + if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { b = b.defaultImpl(defaultImpl); } - b = b.typeIdVisibility(info.visible()); + b = b.typeIdVisibility(typeInfo.getIdVisible()); return b; } From dd6054a2178f551005f561c3feab2ae72c327ac4 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:23:27 +0900 Subject: [PATCH 28/34] Use Value class around TypeResolverBuilder --- .../JacksonAnnotationIntrospector.java | 29 +++++---- .../jsontype/TypeResolverBuilder.java | 15 +++++ .../jsontype/impl/StdTypeResolverBuilder.java | 60 +++++++------------ .../ser/jdk/MapKeySerializationTest.java | 1 + 4 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 2072eb537f..521872d468 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1531,7 +1531,7 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) { return _constructNoTypeResolverBuilder(); } - b = _constructStdTypeResolverBuilder(); + b = _constructStdTypeResolverBuilder(config, typeInfo, baseType); } // Does it define a custom type id resolver? JsonTypeIdResolver idResInfo = _findAnnotation(ann, JsonTypeIdResolver.class); @@ -1540,35 +1540,38 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, if (idRes != null) { idRes.init(baseType); } - b = b.init(typeInfo.getIdType(), idRes); // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); - if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - inclusion = JsonTypeInfo.As.PROPERTY; + if (ann instanceof AnnotatedClass) { + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { + typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); + } } - b = b.inclusion(inclusion); - b = b.typeProperty(typeInfo.getPropertyName()); - Class defaultImpl = typeInfo.getDefaultImpl(); - + // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) + Class defaultImpl = typeInfo.getDefaultImpl(); if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { - b = b.defaultImpl(defaultImpl); + typeInfo = typeInfo.withDefaultImpl(defaultImpl); } - b = b.typeIdVisibility(typeInfo.getIdVisible()); + + b = b.init(typeInfo, idRes); return b; } /** * Helper method for constructing standard {@link TypeResolverBuilder} * implementation. + * + * @since 2.16, backported from 3.0 */ - protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() { - return new StdTypeResolverBuilder(); + protected TypeResolverBuilder _constructStdTypeResolverBuilder(MapperConfig config, + JsonTypeInfo.Value typeInfo, JavaType baseType) { + return new StdTypeResolverBuilder(typeInfo); } /** diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 10dfd83f12..041e751ba5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -97,6 +97,21 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); + + /** + * Initialization method that is called right after constructing + * the builder instance, in cases where information could not be + * passed directly (for example when instantiated for an annotation) + * + * @param settings Configuration settings to apply. + * + * @return Resulting builder instance (usually this builder, + * but not necessarily) + * + * @since 2.16 + */ + public T init(JsonTypeInfo.Value settings, TypeIdResolver res); + /** * Initialization method that is called right after constructing 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 442ccbaa93..ffc1714aa6 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 @@ -35,10 +35,7 @@ public class StdTypeResolverBuilder * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; - - /** - * @since 2.16 (backported from Jackson 3.0) - */ + protected Boolean _requireTypeIdForSubtypes; /** @@ -59,6 +56,27 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } + public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + _typeProperty = _propName(settings.getPropertyName(), _idType); + _typeIdVisible = settings.getIdVisible(); + _defaultImpl = settings.getDefaultImpl(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + } + + protected static String _propName(String propName, JsonTypeInfo.Id idType) { + if (propName == null) { + propName = idType.getDefaultPropertyName(); + } + return propName; + } + /** * @since 2.9 */ @@ -87,37 +105,8 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, _requireTypeIdForSubtypes = base._requireTypeIdForSubtypes; } - /** - * @since 2.16 (backported from Jackson 3.0) - */ - public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { - if (settings != null) { - _idType = settings.getIdType(); - if (_idType == null) { - throw new IllegalArgumentException("idType cannot be null"); - } - _includeAs = settings.getInclusionType(); - _typeProperty = _propName(settings.getPropertyName(), _idType); - _defaultImpl = settings.getDefaultImpl(); - _typeIdVisible = settings.getIdVisible(); - _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); - } - } - - /** - * @since 2.16 (backported from Jackson 3.0) - */ - protected static String _propName(String propName, JsonTypeInfo.Id idType) { - if (propName == null) { - propName = idType.getDefaultPropertyName(); - } - return propName; - } - public static StdTypeResolverBuilder noTypeInfoBuilder() { - JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, - null, null, false, null); - return new StdTypeResolverBuilder().init(typeInfo, null); + return new StdTypeResolverBuilder().init(JsonTypeInfo.Id.NONE, null); } @Override @@ -134,9 +123,6 @@ public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes) return this; } - /** - * @since 2.16 (backported from Jackson 3.0) - */ @Override public StdTypeResolverBuilder init(JsonTypeInfo.Value settings, TypeIdResolver idRes) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java index a34d787b4f..c9a77a84fa 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java @@ -256,6 +256,7 @@ public void testUnWrappedMapWithDefaultType() throws Exception{ assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); } + // [databind#838] public void testUnWrappedMapWithDefaultTypeWithValue() throws Exception { final ObjectMapper mapper = new ObjectMapper(); SimpleModule mod = new SimpleModule("test"); From 43865031113bd69d3caf60f7f6ccb715e0b5dabe Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:30:46 +0900 Subject: [PATCH 29/34] Clean up changes --- .../introspect/JacksonAnnotationIntrospector.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 521872d468..57245a4289 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1543,18 +1543,16 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, // 13-Aug-2011, tatu: One complication; external id only works for properties; // so if declared for a Class, we will need to map it to "PROPERTY" // instead of "EXTERNAL_PROPERTY" - if (ann instanceof AnnotatedClass) { - JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); - if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { - typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); - } + JsonTypeInfo.As inclusion = typeInfo.getInclusionType(); + if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) { + typeInfo = typeInfo.withInclusionType(JsonTypeInfo.As.PROPERTY); } - + Class defaultImpl = typeInfo.getDefaultImpl(); + // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s); // and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead // use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no // valid use (cannot instantiate as default) - Class defaultImpl = typeInfo.getDefaultImpl(); if (defaultImpl != null && defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) { typeInfo = typeInfo.withDefaultImpl(defaultImpl); } From e628ddc979ca12f2a46a528291c1688b2a08bc75 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 20 May 2023 23:58:43 +0900 Subject: [PATCH 30/34] Add version changes in StdTypeResolverBuilder --- .../jsontype/impl/StdTypeResolverBuilder.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 ffc1714aa6..bfe90a1710 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 @@ -35,7 +35,10 @@ public class StdTypeResolverBuilder * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; - + + /** + * @since 2.16 (backported from Jackson 3.0) + */ protected Boolean _requireTypeIdForSubtypes; /** @@ -56,6 +59,9 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } + /** + * @since 2.16 (backported from Jackson 3.0) + */ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { if (settings != null) { _idType = settings.getIdType(); @@ -70,6 +76,9 @@ public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { } } + /** + * @since 2.16 (backported from Jackson 3.0) + */ protected static String _propName(String propName, JsonTypeInfo.Id idType) { if (propName == null) { propName = idType.getDefaultPropertyName(); From 5e5d3b43fef37b57f6efae1fcaf8417190a446c8 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 21 May 2023 00:32:07 +0900 Subject: [PATCH 31/34] Replace usage of TypeResolverBuilder.init --- .../jackson/databind/jsontype/TypeResolverBuilder.java | 5 +++-- .../databind/jsontype/impl/StdTypeResolverBuilder.java | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 041e751ba5..8137fcd906 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -15,8 +15,9 @@ * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

- * Builder is first initialized by calling {@link #init} method, and then - * configured using 'set' methods like {@link #inclusion}. + * Builder is first initialized by calling {@link #init(JsonTypeInfo.Value, TypeIdResolver)} method, with + * configurations passed in through {@link JsonTypeInfo.Value} that is constructed by + * {@link JsonTypeInfo.Value#construct(JsonTypeInfo.Id, As, String, Class, boolean, Boolean)}. * Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed 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 bfe90a1710..b3432755ca 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 @@ -115,7 +115,9 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, } public static StdTypeResolverBuilder noTypeInfoBuilder() { - return new StdTypeResolverBuilder().init(JsonTypeInfo.Id.NONE, null); + JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, + null, null, false, null); + return new StdTypeResolverBuilder().init(typeInfo, null); } @Override From 669ca8105a05c94f7e24870b794e120bb79f81e2 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Mon, 22 May 2023 12:54:41 +0900 Subject: [PATCH 32/34] Apply review --- .../introspect/JacksonAnnotationIntrospector.java | 3 +-- .../databind/jsontype/TypeResolverBuilder.java | 11 +++++++---- .../databind/ser/jdk/MapKeySerializationTest.java | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java index 57245a4289..2b94b737d9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java @@ -1509,8 +1509,7 @@ protected TypeResolverBuilder _findTypeResolver(MapperConfig config, Annotated ann, JavaType baseType) { // since 2.16 : backporting {@link JsonTypeInfo.Value} from 3.0 - final AnnotationIntrospector ai = config.getAnnotationIntrospector(); - JsonTypeInfo.Value typeInfo = ai.findPolymorphicTypeInfo(config, ann); + JsonTypeInfo.Value typeInfo = findPolymorphicTypeInfo(config, ann); // First: maybe we have explicit type resolver? TypeResolverBuilder b; diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 8137fcd906..0d65d2f974 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -103,16 +103,19 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * Initialization method that is called right after constructing * the builder instance, in cases where information could not be * passed directly (for example when instantiated for an annotation) + *

+ * NOTE: This method will be abstract in Jackson 3.0. * * @param settings Configuration settings to apply. * * @return Resulting builder instance (usually this builder, * but not necessarily) - * - * @since 2.16 + * + * @since 2.16 (backported from Jackson 3.0) */ - public T init(JsonTypeInfo.Value settings, TypeIdResolver res); - + default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { + return init(settings.getIdType(), res); + } /** * Initialization method that is called right after constructing diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java index c9a77a84fa..a34d787b4f 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/MapKeySerializationTest.java @@ -256,7 +256,6 @@ public void testUnWrappedMapWithDefaultType() throws Exception{ assertEquals("{\"@type\":\"HashMap\",\"xxxB\":\"bar\"}", json); } - // [databind#838] public void testUnWrappedMapWithDefaultTypeWithValue() throws Exception { final ObjectMapper mapper = new ObjectMapper(); SimpleModule mod = new SimpleModule("test"); From deee3a93d86139889313053690c28250a412120f Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 23 May 2023 22:36:50 +0900 Subject: [PATCH 33/34] Remove conflicting change in TypeResolverBuilder --- .../jsontype/TypeResolverBuilder.java | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java index 0d65d2f974..10dfd83f12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder.java @@ -15,9 +15,8 @@ * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

- * Builder is first initialized by calling {@link #init(JsonTypeInfo.Value, TypeIdResolver)} method, with - * configurations passed in through {@link JsonTypeInfo.Value} that is constructed by - * {@link JsonTypeInfo.Value#construct(JsonTypeInfo.Id, As, String, Class, boolean, Boolean)}. + * Builder is first initialized by calling {@link #init} method, and then + * configured using 'set' methods like {@link #inclusion}. * Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed @@ -98,24 +97,6 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); - - /** - * Initialization method that is called right after constructing - * the builder instance, in cases where information could not be - * passed directly (for example when instantiated for an annotation) - *

- * NOTE: This method will be abstract in Jackson 3.0. - * - * @param settings Configuration settings to apply. - * - * @return Resulting builder instance (usually this builder, - * but not necessarily) - * - * @since 2.16 (backported from Jackson 3.0) - */ - default T init(JsonTypeInfo.Value settings, TypeIdResolver res) { - return init(settings.getIdType(), res); - } /** * Initialization method that is called right after constructing From 176d9048790d3c92418991bdd64994bee315007a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 23 May 2023 22:55:55 +0900 Subject: [PATCH 34/34] Revert "Merge branch 'Introduce-JsonTypeInfo.Value' of https://github.com/JooHyukKim/jackson-databind into Introduce-JsonTypeInfo.Value" This reverts commit 93983d3eb17e3cca569518d07a38516e81c13365, reversing changes made to c30d8a6eaee4b2cf33d3b618ed84affcea721195. --- .../jsontype/impl/StdTypeResolverBuilder.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) 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 b3432755ca..32da2e1795 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 @@ -59,33 +59,6 @@ public class StdTypeResolverBuilder public StdTypeResolverBuilder() { } - /** - * @since 2.16 (backported from Jackson 3.0) - */ - public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { - if (settings != null) { - _idType = settings.getIdType(); - if (_idType == null) { - throw new IllegalArgumentException("idType cannot be null"); - } - _includeAs = settings.getInclusionType(); - _typeProperty = _propName(settings.getPropertyName(), _idType); - _typeIdVisible = settings.getIdVisible(); - _defaultImpl = settings.getDefaultImpl(); - _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); - } - } - - /** - * @since 2.16 (backported from Jackson 3.0) - */ - protected static String _propName(String propName, JsonTypeInfo.Id idType) { - if (propName == null) { - propName = idType.getDefaultPropertyName(); - } - return propName; - } - /** * @since 2.9 */ @@ -114,6 +87,33 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base, _requireTypeIdForSubtypes = base._requireTypeIdForSubtypes; } + /** + * @since 2.16 (backported from Jackson 3.0) + */ + public StdTypeResolverBuilder(JsonTypeInfo.Value settings) { + if (settings != null) { + _idType = settings.getIdType(); + if (_idType == null) { + throw new IllegalArgumentException("idType cannot be null"); + } + _includeAs = settings.getInclusionType(); + _typeProperty = _propName(settings.getPropertyName(), _idType); + _defaultImpl = settings.getDefaultImpl(); + _typeIdVisible = settings.getIdVisible(); + _requireTypeIdForSubtypes = settings.getRequireTypeIdForSubtypes(); + } + } + + /** + * @since 2.16 (backported from Jackson 3.0) + */ + protected static String _propName(String propName, JsonTypeInfo.Id idType) { + if (propName == null) { + propName = idType.getDefaultPropertyName(); + } + return propName; + } + public static StdTypeResolverBuilder noTypeInfoBuilder() { JsonTypeInfo.Value typeInfo = JsonTypeInfo.Value.construct(JsonTypeInfo.Id.NONE, null, null, null, false, null);