From 73a20c37beac111d1881c4d644d344c6d7349927 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 14 Oct 2025 00:24:21 +0900 Subject: [PATCH 1/4] Fix 5342 --- .../databind/ser/BeanSerializerFactory.java | 4 +- ...tterNameConflictSerialization5342Test.java | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java index e59ee8090b..df8a676724 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -477,9 +477,9 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid } } if (anyGetterIndex != -1) { - // There is prop is already in place, just need to replace it + // A property is already in place; insert AnyGetter writer right after it (do not replace) AnyGetterWriter anyGetterWriter = new AnyGetterWriter(anyGetterProp, anyProp, anyGetter, anySer); - props.set(anyGetterIndex, anyGetterWriter); + props.add(anyGetterIndex + 1, anyGetterWriter); } else { // Otherwise just add it at the end, but won't be sorted... // This is case where JsonAnyGetter is private/protected, diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java new file mode 100644 index 0000000000..b10fedeb63 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java @@ -0,0 +1,72 @@ +package com.fasterxml.jackson.databind.ser; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +// [databind#5342] JsonAnyGetter method serialization can override JsonProperty serialization on serialized name conflict +public class AnyGetterNameConflictSerialization5342Test + extends DatabindTestUtil +{ + public static class Pojo5342 { + @JsonIgnore + private Map additionalProperties; + @JsonProperty(value = "additionalProperties") + private Map additionalPropertiesProperty; + + @JsonAnySetter + private void additionalProperties(String key, Object value) { + if (additionalProperties == null) { + additionalProperties = new HashMap<>(); + } + additionalProperties.put(key.replace("\\.", "."), value); + } + + @JsonAnyGetter + public Map additionalProperties() { + return additionalProperties; + } + + public Map additionalPropertiesProperty() { + return additionalPropertiesProperty; + } + + public void additionalPropertiesProperty(Map additionalPropertiesProperty) { + this.additionalPropertiesProperty = additionalPropertiesProperty; + } + } + + private final ObjectMapper MAPPER = newJsonMapper(); + + @Test + public void testOverwrite() + throws Exception + { + Map additionalProperties = new HashMap<>(); + additionalProperties.put("fizz", "buzz"); + Pojo5342 pojo = new Pojo5342(); + pojo.additionalProperties("foo", "bar"); + pojo.additionalPropertiesProperty(additionalProperties); + + + String JSON = MAPPER.writeValueAsString(pojo); + // was in 2.18 : {"foo":"bar","additionalProperties": {"fizz":"buzz"}} + // now in 2.19 : {"foo":"bar"}... need FIX! + assertTrue(JSON.contains("\"additionalProperties\":{\"fizz\":\"buzz\"}")); + assertTrue(JSON.contains("\"foo\":\"bar\"")); + + // Try deserializaing back + Pojo5342 actual = MAPPER.readValue(JSON, Pojo5342.class); + assertEquals(1, actual.additionalProperties.size()); + assertEquals(1, actual.additionalPropertiesProperty().size()); + } + +} From 665068892cdc42063e7d28fc268dff408e07af85 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 14 Oct 2025 01:21:40 +0900 Subject: [PATCH 2/4] FInal --- .../databind/ser/BeanSerializerFactory.java | 2 +- ...tterNameConflictSerialization5342Test.java | 21 +++++++++++-------- .../ser/AnyGetterOrdering4388Test.java | 14 ------------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java index df8a676724..2cfcda6bc1 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -467,7 +467,7 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid for (int i = 0; i < props.size(); i++) { BeanPropertyWriter prop = props.get(i); // Either any-getter as field... - if (Objects.equals(prop.getName(), anyGetter.getName()) + if (Objects.equals(prop.getMember().getName(), anyGetter.getName()) // or as method || Objects.equals(prop.getMember().getMember(), anyGetter.getMember())) { diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java index b10fedeb63..aaa637dd63 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterNameConflictSerialization5342Test.java @@ -20,7 +20,7 @@ public static class Pojo5342 { @JsonIgnore private Map additionalProperties; @JsonProperty(value = "additionalProperties") - private Map additionalPropertiesProperty; + private Map hidden; @JsonAnySetter private void additionalProperties(String key, Object value) { @@ -35,12 +35,12 @@ public Map additionalProperties() { return additionalProperties; } - public Map additionalPropertiesProperty() { - return additionalPropertiesProperty; + public Map hidden() { + return hidden; } - public void additionalPropertiesProperty(Map additionalPropertiesProperty) { - this.additionalPropertiesProperty = additionalPropertiesProperty; + public void hidden(Map additionalPropertiesProperty) { + this.hidden = additionalPropertiesProperty; } } @@ -50,23 +50,26 @@ public void additionalPropertiesProperty(Map additionalPropertie public void testOverwrite() throws Exception { - Map additionalProperties = new HashMap<>(); - additionalProperties.put("fizz", "buzz"); Pojo5342 pojo = new Pojo5342(); pojo.additionalProperties("foo", "bar"); - pojo.additionalPropertiesProperty(additionalProperties); + + Map hidden = new HashMap<>(); + hidden.put("fizz", "buzz"); + pojo.hidden(hidden); String JSON = MAPPER.writeValueAsString(pojo); // was in 2.18 : {"foo":"bar","additionalProperties": {"fizz":"buzz"}} // now in 2.19 : {"foo":"bar"}... need FIX! + // hidden field assertTrue(JSON.contains("\"additionalProperties\":{\"fizz\":\"buzz\"}")); + // any-getter assertTrue(JSON.contains("\"foo\":\"bar\"")); // Try deserializaing back Pojo5342 actual = MAPPER.readValue(JSON, Pojo5342.class); assertEquals(1, actual.additionalProperties.size()); - assertEquals(1, actual.additionalPropertiesProperty().size()); + assertEquals(1, actual.hidden().size()); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java index a4f72e5b8a..18509f38f1 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java @@ -277,20 +277,6 @@ public void testPrivateAnyGetter() throws Exception { json); } - @Test - public void testPrivateAnyGetterSorted() throws Exception { - PrivateAnyGetterPojoSorted pojo = new PrivateAnyGetterPojoSorted(); - pojo.add("secondProperty", 2); - String json = MAPPER.writeValueAsString(pojo); - - assertEquals(a2q("{" + - "'firstProperty':1," + - "'secondProperty':2," + // private accesor, wont' work here - "'thirdProperty':3," + - "'forthProperty':4}"), - json); - } - private void _configureValues(BaseWithProperties base) { base.entityId = 1; base.entityName = "Bob"; From 99a299cda4898a7db5cdd2685024e04be0cefc5c Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 14 Oct 2025 01:22:26 +0900 Subject: [PATCH 3/4] marker --- .../jackson/databind/ser/AnyGetterOrdering4388Test.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java index 18509f38f1..0baff3ac38 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterOrdering4388Test.java @@ -127,6 +127,7 @@ public Map secondProperties() { } } + // @JsonPropertyOrder({ "firstProperty", "secondProperties", "thirdProperty", "forthProperty" }) static class PrivateAnyGetterPojoSorted extends PrivateAnyGetterPojo { public Map getSecondProperties() { From 3055853ae3275f37a10a3455f4c0faa7212d82bb Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 14 Oct 2025 01:26:39 +0900 Subject: [PATCH 4/4] Put back accidental --- .../fasterxml/jackson/databind/ser/BeanSerializerFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java index 2cfcda6bc1..cb7d0600ef 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -477,9 +477,9 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid } } if (anyGetterIndex != -1) { - // A property is already in place; insert AnyGetter writer right after it (do not replace) + // There is prop is already in place, just need to replace it AnyGetterWriter anyGetterWriter = new AnyGetterWriter(anyGetterProp, anyProp, anyGetter, anySer); - props.add(anyGetterIndex + 1, anyGetterWriter); + props.set(anyGetterIndex, anyGetterWriter); } else { // Otherwise just add it at the end, but won't be sorted... // This is case where JsonAnyGetter is private/protected,