From 71e8735e58954074b71ac0f763947f034732fbb7 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 5 Mar 2025 11:20:53 +0100 Subject: [PATCH 1/5] add JsonMapper builderWithJackson2Defaults() --- .../databind/DeserializationFeature.java | 4 +-- .../jackson/databind/json/JsonMapper.java | 35 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main/java/tools/jackson/databind/DeserializationFeature.java b/src/main/java/tools/jackson/databind/DeserializationFeature.java index ceac1f54d8..c6a7ca206f 100644 --- a/src/main/java/tools/jackson/databind/DeserializationFeature.java +++ b/src/main/java/tools/jackson/databind/DeserializationFeature.java @@ -318,7 +318,7 @@ public enum DeserializationFeature implements ConfigFeature *

* NOTE: only single wrapper Array is allowed: if multiple attempted, exception * will be thrown. - * + *

* Feature is disabled by default. */ UNWRAP_SINGLE_VALUE_ARRAYS(false), @@ -330,7 +330,7 @@ public enum DeserializationFeature implements ConfigFeature * a single property with expected root name. If not, a * {@link DatabindException} is thrown; otherwise value of the wrapped property * will be deserialized as if it was the root value. - *

+ *

* Feature is disabled by default. */ UNWRAP_ROOT_VALUE(false), diff --git a/src/main/java/tools/jackson/databind/json/JsonMapper.java b/src/main/java/tools/jackson/databind/json/JsonMapper.java index bb942a337c..2649185b0e 100644 --- a/src/main/java/tools/jackson/databind/json/JsonMapper.java +++ b/src/main/java/tools/jackson/databind/json/JsonMapper.java @@ -1,10 +1,14 @@ package tools.jackson.databind.json; +import tools.jackson.core.StreamReadFeature; import tools.jackson.core.Version; import tools.jackson.core.json.JsonFactory; +import tools.jackson.core.json.JsonFactoryBuilder; import tools.jackson.core.json.JsonReadFeature; import tools.jackson.core.json.JsonWriteFeature; +import tools.jackson.databind.DeserializationFeature; import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.SerializationFeature; import tools.jackson.databind.cfg.MapperBuilder; import tools.jackson.databind.cfg.MapperBuilderState; import tools.jackson.databind.cfg.PackageVersion; @@ -142,7 +146,7 @@ public JsonMapper(Builder b) { /********************************************************************** */ - public static JsonMapper.Builder builder() { + public static Builder builder() { return new Builder(new JsonFactory()); } @@ -150,9 +154,36 @@ public static Builder builder(JsonFactory streamFactory) { return new Builder(streamFactory); } + /** + * Modifies the settings of this builder to more closely match the default configs used + * in Jackson 2.x versions. + *

+ * This method is still a work in progress and may not yet fully replicate the + * default settings of Jackson 2.x. + *

+ */ + public static Builder builderWithJackson2Defaults() { + // TODO replace with call in https://github.com/FasterXML/jackson-core/pull/1411 + final JsonFactoryBuilder factoryBuilder = JsonFactory.builder() + .disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES) + .disable(JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8) + .disable(StreamReadFeature.USE_FAST_DOUBLE_PARSER) + .disable(StreamReadFeature.USE_FAST_BIG_NUMBER_PARSER); + return new Builder(factoryBuilder.build()) + .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .enable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) + .disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) + .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES) + .disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS) + .disable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + } + + @SuppressWarnings("unchecked") @Override - public JsonMapper.Builder rebuild() { + public Builder rebuild() { return new Builder((Builder.StateImpl)_savedBuilderState); } From 32d89cd609230bb2fe20830e9bcf16d24525de48 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 5 Mar 2025 15:33:21 +0100 Subject: [PATCH 2/5] add test --- .../databind/json/JsonMapperBuilderTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/test/java/tools/jackson/databind/json/JsonMapperBuilderTest.java diff --git a/src/test/java/tools/jackson/databind/json/JsonMapperBuilderTest.java b/src/test/java/tools/jackson/databind/json/JsonMapperBuilderTest.java new file mode 100644 index 0000000000..7d2563966d --- /dev/null +++ b/src/test/java/tools/jackson/databind/json/JsonMapperBuilderTest.java @@ -0,0 +1,37 @@ +package tools.jackson.databind.json; + +import org.junit.jupiter.api.Test; +import tools.jackson.core.StreamReadFeature; +import tools.jackson.core.json.JsonFactory; +import tools.jackson.core.json.JsonWriteFeature; +import tools.jackson.databind.DeserializationFeature; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.SerializationFeature; +import tools.jackson.databind.testutil.DatabindTestUtil; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +// Test(s) to verify behaviors in JsonMapper.Builder +public class JsonMapperBuilderTest extends DatabindTestUtil +{ + + @Test + public void testBuilderWithJackson2Defaults() + { + ObjectMapper mapper = JsonMapper.builderWithJackson2Defaults().build(); + JsonFactory jsonFactory = (JsonFactory) mapper.tokenStreamFactory(); + assertFalse(mapper.isEnabled(StreamReadFeature.USE_FAST_DOUBLE_PARSER)); + assertFalse(mapper.isEnabled(StreamReadFeature.USE_FAST_BIG_NUMBER_PARSER)); + assertFalse(jsonFactory.isEnabled(JsonWriteFeature.ESCAPE_FORWARD_SLASHES)); + assertFalse(jsonFactory.isEnabled(JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8)); + assertTrue(mapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)); + assertTrue(mapper.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)); + assertTrue(mapper.isEnabled(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)); + assertFalse(mapper.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)); + assertTrue(mapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)); + assertFalse(mapper.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)); + assertFalse(mapper.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)); + assertFalse(mapper.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)); + } +} From a6de4d5c3dee00033337133ab9f788662ce2ceb0 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Thu, 6 Mar 2025 09:05:00 +0100 Subject: [PATCH 3/5] add configureForJackson2 --- .../jackson/databind/cfg/MapperBuilder.java | 21 +++++++++++++++++++ .../jackson/databind/json/JsonMapper.java | 21 ++----------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java b/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java index 06d812fd04..1dcd971ece 100644 --- a/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java @@ -798,6 +798,27 @@ public B configure(DatatypeFeature feature, boolean state) { return _this(); } + /** + * The builder returned uses default settings more closely + * matching the default configs used in Jackson 2.x versions. + *

+ * This method is still a work in progress and may not yet fully replicate the + * default settings of Jackson 2.x. + *

+ */ + public B configureForJackson2() { + return disable(StreamReadFeature.USE_FAST_DOUBLE_PARSER) + .disable(StreamReadFeature.USE_FAST_BIG_NUMBER_PARSER) + .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .enable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) + .disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) + .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES) + .disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS) + .disable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + } + /* /********************************************************************** /* Changing features: parser, generator diff --git a/src/main/java/tools/jackson/databind/json/JsonMapper.java b/src/main/java/tools/jackson/databind/json/JsonMapper.java index 2649185b0e..7bdb122bf1 100644 --- a/src/main/java/tools/jackson/databind/json/JsonMapper.java +++ b/src/main/java/tools/jackson/databind/json/JsonMapper.java @@ -1,14 +1,10 @@ package tools.jackson.databind.json; -import tools.jackson.core.StreamReadFeature; import tools.jackson.core.Version; import tools.jackson.core.json.JsonFactory; -import tools.jackson.core.json.JsonFactoryBuilder; import tools.jackson.core.json.JsonReadFeature; import tools.jackson.core.json.JsonWriteFeature; -import tools.jackson.databind.DeserializationFeature; import tools.jackson.databind.ObjectMapper; -import tools.jackson.databind.SerializationFeature; import tools.jackson.databind.cfg.MapperBuilder; import tools.jackson.databind.cfg.MapperBuilderState; import tools.jackson.databind.cfg.PackageVersion; @@ -163,21 +159,8 @@ public static Builder builder(JsonFactory streamFactory) { *

*/ public static Builder builderWithJackson2Defaults() { - // TODO replace with call in https://github.com/FasterXML/jackson-core/pull/1411 - final JsonFactoryBuilder factoryBuilder = JsonFactory.builder() - .disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES) - .disable(JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8) - .disable(StreamReadFeature.USE_FAST_DOUBLE_PARSER) - .disable(StreamReadFeature.USE_FAST_BIG_NUMBER_PARSER); - return new Builder(factoryBuilder.build()) - .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .enable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) - .disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) - .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) - .disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES) - .disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS) - .disable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + return builder(JsonFactory.builderWithJackson2Defaults().build()) + .configureForJackson2(); } From 27702b8e464336a9aca19bfa98f529c0db2be21e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Thu, 6 Mar 2025 09:09:21 +0100 Subject: [PATCH 4/5] Update JsonMapper.java --- .../tools/jackson/databind/json/JsonMapper.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/tools/jackson/databind/json/JsonMapper.java b/src/main/java/tools/jackson/databind/json/JsonMapper.java index 7bdb122bf1..3cfd415dfa 100644 --- a/src/main/java/tools/jackson/databind/json/JsonMapper.java +++ b/src/main/java/tools/jackson/databind/json/JsonMapper.java @@ -100,6 +100,21 @@ public Builder configure(JsonWriteFeature feature, boolean state) return this; } + /** + * The builder returned uses default settings more closely + * matching the default configs used in Jackson 2.x versions. + *

+ * This method is still a work in progress and may not yet fully replicate the + * default settings of Jackson 2.x. + *

+ */ + @Override + public Builder configureForJackson2() { + return super.configureForJackson2() + .disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES) + .disable(JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8); + } + protected static class StateImpl extends MapperBuilderState implements java.io.Serializable // important! { From b89d580ba89ec71e05d0c0b8185c0d76a17c336f Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 7 Mar 2025 00:21:29 +0100 Subject: [PATCH 5/5] remove some factory based changes --- .../tools/jackson/databind/cfg/MapperBuilder.java | 4 +--- .../tools/jackson/databind/json/JsonMapper.java | 15 --------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java b/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java index 1dcd971ece..bdfe968a82 100644 --- a/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/tools/jackson/databind/cfg/MapperBuilder.java @@ -807,9 +807,7 @@ public B configure(DatatypeFeature feature, boolean state) { *

*/ public B configureForJackson2() { - return disable(StreamReadFeature.USE_FAST_DOUBLE_PARSER) - .disable(StreamReadFeature.USE_FAST_BIG_NUMBER_PARSER) - .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + return enable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .enable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) .disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) diff --git a/src/main/java/tools/jackson/databind/json/JsonMapper.java b/src/main/java/tools/jackson/databind/json/JsonMapper.java index 3cfd415dfa..7bdb122bf1 100644 --- a/src/main/java/tools/jackson/databind/json/JsonMapper.java +++ b/src/main/java/tools/jackson/databind/json/JsonMapper.java @@ -100,21 +100,6 @@ public Builder configure(JsonWriteFeature feature, boolean state) return this; } - /** - * The builder returned uses default settings more closely - * matching the default configs used in Jackson 2.x versions. - *

- * This method is still a work in progress and may not yet fully replicate the - * default settings of Jackson 2.x. - *

- */ - @Override - public Builder configureForJackson2() { - return super.configureForJackson2() - .disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES) - .disable(JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8); - } - protected static class StateImpl extends MapperBuilderState implements java.io.Serializable // important! {