From 6b13aeb6b12ea00fcdf45c129e0a959e67d452c5 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Mon, 19 Feb 2024 12:39:14 +0900 Subject: [PATCH 01/18] Add test --- .../databind/ser/JsonPropertyOrderTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java new file mode 100644 index 0000000000..b175588f24 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java @@ -0,0 +1,141 @@ +package com.fasterxml.jackson.databind.ser; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import com.fasterxml.jackson.databind.ObjectMapper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import static com.fasterxml.jackson.databind.BaseMapTest.newJsonMapper; +import static com.fasterxml.jackson.databind.BaseTest.a2q; + +/** + * Test to verify that the order of properties is preserved when using @JsonPropertyOrder + * with @JsonUnwrapped and @JsonAnyGetter + * + */ +public class JsonPropertyOrderTest { + + // Base class with properties + static class BaseWithProperties { + public String entityName; + public int entityId; + public Integer totalTests; + @JsonAnyGetter + public Map products; + @JsonUnwrapped + public Location childEntities; + } + + // @JsonAnyGetter, with different property order + @JsonPropertyOrder({"childEntities", "entityId", "totalTests", "entityName", "products"}) + static class PojoPropertyVersion1 extends BaseWithProperties { + } + + // @JsonAnyGetter, with different property order + @JsonPropertyOrder({"entityId", "totalTests", "childEntities", "entityName", "products"}) + static class PojoPropertyVersion2 extends BaseWithProperties { + } + + // @JsonUnwrapped, with different property order + @JsonPropertyOrder({"childEntities", "entityId", "totalTests", "entityName", "products"}) + static class PojoUnwrappedVersion1 extends BaseWithProperties { + } + + // @JsonUnwrapped, with different property order + @JsonPropertyOrder({"entityId", "totalTests", "childEntities", "entityName", "products"}) + static class PojoUnwrappedVersion2 extends BaseWithProperties { + } + + static class Location { + public int child1; + public int child2; + } + + private final ObjectMapper MAPPER = newJsonMapper(); + + @Test + public void testSerializationOrderVersion1() throws Exception { + PojoPropertyVersion1 input = new PojoPropertyVersion1(); + _configureValues(input); + + String json = MAPPER.writeValueAsString(input); + + assertEquals(a2q("{" + + "'child1':3," + + "'child2':3," + + "'entityId':1," + + "'totalTests':2," + + "'entityName':'Bob'," + + "'product1':4}"), + json); + } + + @Test + public void testSerializationOrderVersion2() throws Exception { + PojoPropertyVersion2 input = new PojoPropertyVersion2(); + _configureValues(input); + + String json = MAPPER.writeValueAsString(input); + + assertEquals(a2q("{" + + "'entityId':1," + + "'totalTests':2," + + "'child1':3," + + "'child2':3," + + "'entityName':'Bob'," + + "'product1':4}"), + json); + } + + @Test + public void testSerializationOrderUnwrappedVersion1() throws Exception { + PojoUnwrappedVersion1 input = new PojoUnwrappedVersion1(); + _configureValues(input); + + String json = MAPPER.writeValueAsString(input); + + assertEquals(a2q("{" + + "'child1':3," + + "'child2':3," + + "'entityId':1," + + "'totalTests':2," + + "'entityName':'Bob'," + + "'product1':4}"), + json); + } + + @Test + public void testSerializationOrderUnwrappedVersion2() throws Exception { + PojoUnwrappedVersion2 input = new PojoUnwrappedVersion2(); + _configureValues(input); + + String json = MAPPER.writeValueAsString(input); + + assertEquals(a2q("{" + + "'entityId':1," + + "'totalTests':2," + + "'child1':3," + + "'child2':3," + + "'entityName':'Bob'," + + "'product1':4}"), + json); + } + + private void _configureValues(BaseWithProperties base) { + base.entityId = 1; + base.entityName = "Bob"; + base.totalTests = 2; + base.childEntities = new Location(); + base.childEntities.child1 = 3; + base.childEntities.child2 = 3; + base.products = new HashMap<>(); + base.products.put("product1", 4); + } +} From 85422ed06e52f55cbf4d6fbd335043efc6ef7be6 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Mon, 19 Feb 2024 12:40:45 +0900 Subject: [PATCH 02/18] Clean up test utils --- .../jackson/databind/ser/JsonPropertyOrderTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java index b175588f24..8549ff7ed0 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java @@ -9,18 +9,18 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; import static org.junit.jupiter.api.Assertions.assertEquals; -import static com.fasterxml.jackson.databind.BaseMapTest.newJsonMapper; -import static com.fasterxml.jackson.databind.BaseTest.a2q; /** * Test to verify that the order of properties is preserved when using @JsonPropertyOrder * with @JsonUnwrapped and @JsonAnyGetter * */ -public class JsonPropertyOrderTest { +public class JsonPropertyOrderTest extends DatabindTestUtil +{ // Base class with properties static class BaseWithProperties { From 8fe3a1f869450d809feb2d6a0a1c727d665fd8d7 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 19 Feb 2024 11:22:34 -0800 Subject: [PATCH 03/18] Rename test to include issue related --- ...PropertyOrderTest.java => JsonPropertyOrder4388Test.java} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename src/test/java/com/fasterxml/jackson/databind/ser/{JsonPropertyOrderTest.java => JsonPropertyOrder4388Test.java} (97%) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java similarity index 97% rename from src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java rename to src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index 8549ff7ed0..202f4aa7b5 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -17,11 +17,9 @@ /** * Test to verify that the order of properties is preserved when using @JsonPropertyOrder * with @JsonUnwrapped and @JsonAnyGetter - * */ -public class JsonPropertyOrderTest extends DatabindTestUtil +public class JsonPropertyOrder4388Test extends DatabindTestUtil { - // Base class with properties static class BaseWithProperties { public String entityName; @@ -60,6 +58,7 @@ static class Location { private final ObjectMapper MAPPER = newJsonMapper(); + // For [databind#4388] @Test public void testSerializationOrderVersion1() throws Exception { PojoPropertyVersion1 input = new PojoPropertyVersion1(); From 7a067d9123e5d77b241ff096f9a8ce603f1dc63b Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 19 Feb 2024 11:27:00 -0800 Subject: [PATCH 04/18] Change test to show how "Any properties" are not ordered as expected. --- .../jackson/databind/ser/JsonPropertyOrder4388Test.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index 202f4aa7b5..68af7c26f5 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -37,7 +37,7 @@ static class PojoPropertyVersion1 extends BaseWithProperties { } // @JsonAnyGetter, with different property order - @JsonPropertyOrder({"entityId", "totalTests", "childEntities", "entityName", "products"}) + @JsonPropertyOrder({"entityId", "totalTests", "childEntities", "products", "entityName"}) static class PojoPropertyVersion2 extends BaseWithProperties { } @@ -88,8 +88,8 @@ public void testSerializationOrderVersion2() throws Exception { "'totalTests':2," + "'child1':3," + "'child2':3," + - "'entityName':'Bob'," + - "'product1':4}"), + "'product1':4," + + "'entityName':'Bob'}"), json); } From 8f3a3011f07f6264e12133eb0fa57920b560d110 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Thu, 22 Feb 2024 09:03:50 +0900 Subject: [PATCH 05/18] Implement @JsonProperyOrder fixer --- .../introspect/POJOPropertiesCollector.java | 3 +-- .../jackson/databind/ser/AnyGetterWriter.java | 20 ++++++++++++++++- .../databind/ser/BeanSerializerFactory.java | 22 ++++++++++++++++++- .../databind/ser/std/BeanSerializerBase.java | 8 +++++++ .../jackson/databind/ser/AnyGetterTest.java | 3 +-- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java index 1f773be54a..670c46327c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java @@ -550,8 +550,8 @@ protected void _addFields(Map props) _anySetterField = new LinkedList<>(); } _anySetterField.add(f); + continue; } - continue; } String implName = ai.findImplicitPropertyName(f); if (implName == null) { @@ -1049,7 +1049,6 @@ protected void _addGetterMethod(Map props, _anyGetters = new LinkedList<>(); } _anyGetters.add(m); - return; } // @JsonKey? if (Boolean.TRUE.equals(ai.hasAsKey(_config, m))) { diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java index c50bd0b85d..14cf0ca5f7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java @@ -12,7 +12,7 @@ * for serializing {@link com.fasterxml.jackson.annotation.JsonAnyGetter} annotated * (Map) properties */ -public class AnyGetterWriter +public class AnyGetterWriter extends BeanPropertyWriter { protected final BeanProperty _property; @@ -25,6 +25,19 @@ public class AnyGetterWriter protected MapSerializer _mapSerializer; + @SuppressWarnings("unchecked") + public AnyGetterWriter(BeanPropertyWriter parent, BeanProperty property, + AnnotatedMember accessor, JsonSerializer serializer) + { + super(parent); + _accessor = accessor; + _property = property; + _serializer = (JsonSerializer) serializer; + if (serializer instanceof MapSerializer) { + _mapSerializer = (MapSerializer) serializer; + } + } + @SuppressWarnings("unchecked") public AnyGetterWriter(BeanProperty property, AnnotatedMember accessor, JsonSerializer serializer) @@ -65,6 +78,11 @@ public void getAndSerialize(Object bean, JsonGenerator gen, SerializerProvider p _serializer.serialize(value, gen, provider); } + @Override + public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception { + getAndSerialize(bean, gen, prov); + } + /** * @since 2.3 */ 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 0f70bd9717..10b5cfcf69 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -440,6 +440,19 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid AnnotatedMember anyGetter = beanDesc.findAnyGetter(); if (anyGetter != null) { + BeanPropertyWriter anyGetterProp = null; + int anyGetterIndex = -1; + // find anyProp + // TODO: Better way to handdle this... + // This does not seem the most efficient way to do this.... + for (int i = 0; i < props.size(); i++) { + BeanPropertyWriter prop = props.get(i); + if (Objects.equals(prop.getMember().getMember(), anyGetter.getMember())) { + anyGetterProp = prop; + anyGetterIndex = i; + break; + } + } JavaType anyType = anyGetter.getType(); // copied from BasicSerializerFactory.buildMapSerializer(): JavaType valueType = anyType.getContentType(); @@ -457,7 +470,14 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid PropertyName name = PropertyName.construct(anyGetter.getName()); BeanProperty.Std anyProp = new BeanProperty.Std(name, valueType, null, anyGetter, PropertyMetadata.STD_OPTIONAL); - builder.setAnyGetter(new AnyGetterWriter(anyProp, anyGetter, anySer)); + + // TODO: find way to merge these two cases together + if (anyGetterIndex != -1 && anyGetterProp != null) { + AnyGetterWriter anyGetterWriter = new AnyGetterWriter(anyGetterProp, anyProp, anyGetter, anySer); + props.set(anyGetterIndex, anyGetterWriter); + } else { + builder.setAnyGetter(new AnyGetterWriter(anyProp, anyGetter, anySer)); + } } // Next: need to gather view information, if any: processViews(config, builder); diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java index 742d14d44e..70b54bf398 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java @@ -401,6 +401,14 @@ public void resolve(SerializerProvider provider) prop.assignSerializer(ser); } + // also, any-getter may need to be resolved + for (int i = 0; i < _props.length; i++) { + BeanPropertyWriter prop = _props[i]; + if (prop instanceof AnyGetterWriter) { + ((AnyGetterWriter) prop).resolve(provider); + } + } + // also, any-getter may need to be resolved if (_anyGetterWriter != null) { // 23-Feb-2015, tatu: Misleading, as this actually triggers call to contextualization... diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java index 9bab0dfebe..2e5155c575 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java @@ -299,8 +299,7 @@ public void testAnyGetterWithMapperDefaultIncludeNonEmptyAndFilterOnBean() throw input.add("empty", ""); input.add("null", null); String json = mapper.writeValueAsString(input); - // Unfortunately path for bean with filter is different. It still skips nulls. - assertEquals("{\"non-empty\":\"property\",\"empty\":\"\"}", json); + assertEquals("{\"non-empty\":\"property\"}", json); } // [databind#2592] From d62c15438033d3038fd8f5937a67386e9c798837 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sat, 24 Feb 2024 22:53:03 +0900 Subject: [PATCH 06/18] Add test wrt @JsonIgnore and @JsonIgnoreProperties --- .../ser/JsonPropertyOrder4388Test.java | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index 68af7c26f5..d9130d23c2 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -5,9 +5,7 @@ import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonUnwrapped; +import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; @@ -56,6 +54,30 @@ static class Location { public int child2; } + @JsonIgnoreProperties("b") + static class IgnorePropertiesOnFieldPojo { + public int a = 1; + public int b = 2; + @JsonAnyGetter + public Map map = new HashMap<>(); + } + + static class IgnorePropertiesOnAnyGetterPojo { + public int a = 1; + public int b = 2; + @JsonIgnoreProperties("b") + @JsonAnyGetter + public Map map = new HashMap<>(); + } + + static class IgnoreOnFieldPojo { + public int a = 1; + @JsonIgnore + public int b = 2; + @JsonAnyGetter + public Map map = new HashMap<>(); + } + private final ObjectMapper MAPPER = newJsonMapper(); // For [databind#4388] @@ -137,4 +159,22 @@ private void _configureValues(BaseWithProperties base) { base.products = new HashMap<>(); base.products.put("product1", 4); } + + @Test + public void testIgnoreProperties() throws Exception { + // Respsect @JsonIgnoreProperties 'b' from Pojo, but not from map + IgnorePropertiesOnFieldPojo bean = new IgnorePropertiesOnFieldPojo(); + bean.map.put("b", 3); + assertEquals(a2q("{'a':1,'b':3}"), MAPPER.writeValueAsString(bean)); + + // Respect @JsonIgnoreProperties 'b' from Pojo, but not from map + IgnorePropertiesOnAnyGetterPojo bean2 = new IgnorePropertiesOnAnyGetterPojo(); + bean2.map.put("b", 3); + assertEquals(a2q("{'a':1,'b':2}"), MAPPER.writeValueAsString(bean2)); + + // Respect @JsonIgnore from Pojo, but not from map + IgnoreOnFieldPojo bean3 = new IgnoreOnFieldPojo(); + bean3.map.put("b", 3); + assertEquals(a2q("{'a':1,'b':3}"), MAPPER.writeValueAsString(bean3)); + } } From 0cfc627e3c7aae835b6c103f701097b784101044 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sat, 24 Feb 2024 23:12:17 +0900 Subject: [PATCH 07/18] Add test wrt @JsonPropertyOrder --- .../ser/JsonPropertyOrder4388Test.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index d9130d23c2..cc4324c32d 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -1,6 +1,7 @@ package com.fasterxml.jackson.databind.ser; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.Test; @@ -78,6 +79,21 @@ static class IgnoreOnFieldPojo { public Map map = new HashMap<>(); } + static class AlphabeticOrderOnAnyGetterBean { + @JsonPropertyOrder(alphabetic = true) + @JsonAnyGetter + public Map map = new LinkedHashMap<>(); + } + + @JsonPropertyOrder(alphabetic = true) + static class AlphabeticOrderOnClassBean { + public int c = 3; + public int a = 1; + public int b = 2; + @JsonAnyGetter + public Map map = new LinkedHashMap<>(); + } + private final ObjectMapper MAPPER = newJsonMapper(); // For [databind#4388] @@ -177,4 +193,35 @@ public void testIgnoreProperties() throws Exception { bean3.map.put("b", 3); assertEquals(a2q("{'a':1,'b':3}"), MAPPER.writeValueAsString(bean3)); } + + // Sorting works on @JsonAnyGetter, when adding @JsonPropertyOrder directly on the AnyGetter method + @Test + public void testSortingOnAnyGetter() throws Exception { + AlphabeticOrderOnAnyGetterBean bean = new AlphabeticOrderOnAnyGetterBean(); + bean.map.put("zd", 4); + bean.map.put("zc", 3); + bean.map.put("za", 1); + bean.map.put("zb", 2); + assertEquals(a2q("{" + + "'za':1," + + "'zb':2," + + "'zc':3," + + "'zd':4}"), MAPPER.writeValueAsString(bean)); + } + + // Sorting does not work on @JsonAnyGetter, when adding @JsonPropertyOrder on the class + @Test + public void testSortingOnClassNotPropagateToAnyGetter() throws Exception { + AlphabeticOrderOnClassBean bean = new AlphabeticOrderOnClassBean(); + bean.map.put("zc", 3); + bean.map.put("za", 1); + bean.map.put("zb", 2); + assertEquals(a2q("{" + + "'a':1," + + "'b':2," + + "'c':3," + + "'zc':3," + + "'za':1," + + "'zb':2}"), MAPPER.writeValueAsString(bean)); + } } From daf659dc884d24af0b1adc2b32b82db15695cd60 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 27 Feb 2024 09:15:05 +0900 Subject: [PATCH 08/18] Add test with link/unlink property --- .../ser/JsonPropertyOrder4388Test.java | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index cc4324c32d..21050878af 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -12,13 +12,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; - /** * Test to verify that the order of properties is preserved when using @JsonPropertyOrder * with @JsonUnwrapped and @JsonAnyGetter */ -public class JsonPropertyOrder4388Test extends DatabindTestUtil -{ +public class JsonPropertyOrder4388Test extends DatabindTestUtil { // Base class with properties static class BaseWithProperties { public String entityName; @@ -94,6 +92,28 @@ static class AlphabeticOrderOnClassBean { public Map map = new LinkedHashMap<>(); } + static class LinkUnlinkConflictPojo { + private Map properties = new HashMap<>(); + + @JsonAnyGetter + public Map getProperties() { + properties.put("key", "value"); + return properties; + } + + @JsonIgnore + public String getProperties(String key) { + // This method is unrelated to the any-getter and should not affect serialization + return "unrelated"; + } + + @JsonIgnore + public String getKey() { + // This method is unrelated to the any-getter and should not affect serialization + return "unrelated"; + } + } + private final ObjectMapper MAPPER = newJsonMapper(); // For [databind#4388] @@ -165,17 +185,6 @@ public void testSerializationOrderUnwrappedVersion2() throws Exception { json); } - private void _configureValues(BaseWithProperties base) { - base.entityId = 1; - base.entityName = "Bob"; - base.totalTests = 2; - base.childEntities = new Location(); - base.childEntities.child1 = 3; - base.childEntities.child2 = 3; - base.products = new HashMap<>(); - base.products.put("product1", 4); - } - @Test public void testIgnoreProperties() throws Exception { // Respsect @JsonIgnoreProperties 'b' from Pojo, but not from map @@ -224,4 +233,23 @@ public void testSortingOnClassNotPropagateToAnyGetter() throws Exception { "'za':1," + "'zb':2}"), MAPPER.writeValueAsString(bean)); } + + @Test + public void testLinkUnlinkWithJsonIgnore() throws Exception { + LinkUnlinkConflictPojo pojo = new LinkUnlinkConflictPojo(); + String json = MAPPER.writeValueAsString(pojo); + + assertEquals(a2q("{'key':'value'}"), json); + } + + private void _configureValues(BaseWithProperties base) { + base.entityId = 1; + base.entityName = "Bob"; + base.totalTests = 2; + base.childEntities = new Location(); + base.childEntities.child1 = 3; + base.childEntities.child2 = 3; + base.products = new HashMap<>(); + base.products.put("product1", 4); + } } From 7e97e1fea9d9170d36b75d5c2534c32a67d5dc81 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sat, 2 Mar 2024 23:35:09 +0900 Subject: [PATCH 09/18] Add more tests --- .../jackson/databind/ser/AnyGetterTest.java | 31 +++++++++++++++++ .../ser/JsonPropertyOrder4388Test.java | 33 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java index 2e5155c575..b05cbe3275 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java @@ -185,6 +185,25 @@ public void set(String name, String value) { } } + // [databind#1458]: Allow `@JsonAnyGetter` on fields too + @Test + static class DynaFieldOrderedBean { + public int id = 123; + + @JsonPropertyOrder(alphabetic = true) + @JsonAnyGetter + @JsonAnySetter + private HashMap other = new LinkedHashMap<>(); + + public Map any() { + return other; + } + + public void set(String name, String value) { + other.put(name, value); + } + } + // [databind#1458]: Allow `@JsonAnyGetter` on fields too @Test public void testDynaFieldBean() throws Exception @@ -199,6 +218,18 @@ public void testDynaFieldBean() throws Exception assertEquals("Joe", result.other.get("name")); } + // [databind#4388]: Allow `@JsonPropertyOrder` AND `@JsonAnyGetter` on fields too + @Test + public void testDynaFieldOrderedBean() throws Exception + { + DynaFieldOrderedBean b = new DynaFieldOrderedBean(); + b.set("nameC", "Cilly"); + b.set("nameB", "Billy"); + b.set("nameA", "Ailly"); + + assertEquals("{\"id\":123,\"nameA\":\"Ailly\",\"nameB\":\"Billy\",\"nameC\":\"Cilly\"}", MAPPER.writeValueAsString(b)); + } + /* /********************************************************** /* Test methods diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index 21050878af..599560d4e9 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -114,8 +114,41 @@ public String getKey() { } } + @JsonPropertyOrder({ "firstProperty", "secondProperties", "thirdProperty", "forthProperty" }) + static class PrivateAnyGetterPojo { + public int firstProperty = 1; + public int forthProperty = 4; + public int thirdProperty = 3; + + @JsonAnyGetter + private Map secondProperties = new HashMap<>(); + + public PrivateAnyGetterPojo add(String key, Object value) { + secondProperties.put(key, value); + return this; + } + + public Map props() { + return secondProperties; + } + } + private final ObjectMapper MAPPER = newJsonMapper(); + @Test + public void testPrivateAnyGetter() throws Exception { + PrivateAnyGetterPojo pojo = new PrivateAnyGetterPojo(); + pojo.add("secondProperty", 2); + String json = MAPPER.writeValueAsString(pojo); + + assertEquals(a2q("{" + + "'firstProperty':1," + + "'secondProperty':2," + + "'thirdProperty':3," + + "'forthProperty':4}"), + json); + } + // For [databind#4388] @Test public void testSerializationOrderVersion1() throws Exception { From 9262fdef17484e4a89d11404a4d50b41ffead3e5 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sun, 3 Mar 2024 15:33:21 +0900 Subject: [PATCH 10/18] Remove _anyGetterWriter entirely --- .../jackson/databind/ser/BeanSerializer.java | 1 - .../databind/ser/std/BeanSerializerBase.java | 23 ------------------- 2 files changed, 24 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java index 61add225d9..e974c093d9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializer.java @@ -147,7 +147,6 @@ protected BeanSerializerBase asArraySerializer() * - have per-property filters */ if ((_objectIdWriter == null) - && (_anyGetterWriter == null) && (_propertyFilterId == null) ) { return new BeanAsArraySerializer(this); diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java index 70b54bf398..a61e1fb38c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java @@ -66,12 +66,6 @@ public abstract class BeanSerializerBase */ final protected BeanPropertyWriter[] _filteredProps; - /** - * Handler for {@link com.fasterxml.jackson.annotation.JsonAnyGetter} - * annotated properties - */ - final protected AnyGetterWriter _anyGetterWriter; - /** * Id of the bean property filter to use, if any; null if none. */ @@ -119,13 +113,11 @@ protected BeanSerializerBase(JavaType type, BeanSerializerBuilder builder, // 20-Sep-2019, tatu: Actually not just that but also "dummy" serializer for // case of no bean properties, too _typeId = null; - _anyGetterWriter = null; _propertyFilterId = null; _objectIdWriter = null; _serializationShape = null; } else { _typeId = builder.getTypeId(); - _anyGetterWriter = builder.getAnyGetter(); _propertyFilterId = builder.getFilterId(); _objectIdWriter = builder.getObjectIdWriter(); final JsonFormat.Value format = builder.getBeanDescription().findExpectedFormat(); @@ -142,7 +134,6 @@ protected BeanSerializerBase(BeanSerializerBase src, _filteredProps = filteredProperties; _typeId = src._typeId; - _anyGetterWriter = src._anyGetterWriter; _objectIdWriter = src._objectIdWriter; _propertyFilterId = src._propertyFilterId; _serializationShape = src._serializationShape; @@ -166,7 +157,6 @@ protected BeanSerializerBase(BeanSerializerBase src, _filteredProps = src._filteredProps; _typeId = src._typeId; - _anyGetterWriter = src._anyGetterWriter; _objectIdWriter = objectIdWriter; _propertyFilterId = filterId; _serializationShape = src._serializationShape; @@ -210,7 +200,6 @@ protected BeanSerializerBase(BeanSerializerBase src, Set toIgnore, Set Date: Sun, 3 Mar 2024 15:37:43 +0900 Subject: [PATCH 11/18] Apply filter functionality --- .../jackson/databind/ser/impl/SimpleBeanPropertyFilter.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/SimpleBeanPropertyFilter.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/SimpleBeanPropertyFilter.java index fad1693391..c3b017f897 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/SimpleBeanPropertyFilter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/SimpleBeanPropertyFilter.java @@ -218,6 +218,8 @@ public void serializeAsField(Object pojo, JsonGenerator jgen, writer.serializeAsField(pojo, jgen, provider); } else if (!jgen.canOmitFields()) { // since 2.3 writer.serializeAsOmittedField(pojo, jgen, provider); + } else if (writer instanceof AnyGetterWriter) { + ((AnyGetterWriter) writer).getAndFilter(pojo, jgen, provider, this); } } From 6ce6510855193cf7cece51280318e85be4f6f014 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sun, 3 Mar 2024 15:37:51 +0900 Subject: [PATCH 12/18] Add tests --- .../ser/JsonPropertyOrder4388Test.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java index 599560d4e9..5743179be7 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java @@ -55,15 +55,13 @@ static class Location { @JsonIgnoreProperties("b") static class IgnorePropertiesOnFieldPojo { - public int a = 1; - public int b = 2; + public int a = 1, b = 2; @JsonAnyGetter public Map map = new HashMap<>(); } static class IgnorePropertiesOnAnyGetterPojo { - public int a = 1; - public int b = 2; + public int a = 1, b = 2; @JsonIgnoreProperties("b") @JsonAnyGetter public Map map = new HashMap<>(); @@ -85,9 +83,7 @@ static class AlphabeticOrderOnAnyGetterBean { @JsonPropertyOrder(alphabetic = true) static class AlphabeticOrderOnClassBean { - public int c = 3; - public int a = 1; - public int b = 2; + public int c = 3, a = 1, b = 2; @JsonAnyGetter public Map map = new LinkedHashMap<>(); } @@ -116,9 +112,7 @@ public String getKey() { @JsonPropertyOrder({ "firstProperty", "secondProperties", "thirdProperty", "forthProperty" }) static class PrivateAnyGetterPojo { - public int firstProperty = 1; - public int forthProperty = 4; - public int thirdProperty = 3; + public int firstProperty = 1, forthProperty = 4, thirdProperty = 3; @JsonAnyGetter private Map secondProperties = new HashMap<>(); @@ -128,7 +122,7 @@ public PrivateAnyGetterPojo add(String key, Object value) { return this; } - public Map props() { + public Map secondProperties() { return secondProperties; } } @@ -143,9 +137,10 @@ public void testPrivateAnyGetter() throws Exception { assertEquals(a2q("{" + "'firstProperty':1," + - "'secondProperty':2," + "'thirdProperty':3," + - "'forthProperty':4}"), + "'forthProperty':4," + + "'secondProperty':2" + // private accesor, wont' work here + "}"), json); } From 6a0e2fddf12b5562c150cb66495ce0c0b7617bd9 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sun, 3 Mar 2024 15:38:06 +0900 Subject: [PATCH 13/18] Simplify logic --- .../databind/ser/BeanSerializerFactory.java | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 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 10b5cfcf69..d65e65c89c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -25,11 +25,7 @@ import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer; import com.fasterxml.jackson.databind.ser.std.ToEmptyObjectSerializer; import com.fasterxml.jackson.databind.type.ReferenceType; -import com.fasterxml.jackson.databind.util.BeanUtil; -import com.fasterxml.jackson.databind.util.ClassUtil; -import com.fasterxml.jackson.databind.util.Converter; -import com.fasterxml.jackson.databind.util.IgnorePropertiesUtil; -import com.fasterxml.jackson.databind.util.NativeImageUtil; +import com.fasterxml.jackson.databind.util.*; /** * Factory class that can provide serializers for any regular Java beans @@ -440,19 +436,6 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid AnnotatedMember anyGetter = beanDesc.findAnyGetter(); if (anyGetter != null) { - BeanPropertyWriter anyGetterProp = null; - int anyGetterIndex = -1; - // find anyProp - // TODO: Better way to handdle this... - // This does not seem the most efficient way to do this.... - for (int i = 0; i < props.size(); i++) { - BeanPropertyWriter prop = props.get(i); - if (Objects.equals(prop.getMember().getMember(), anyGetter.getMember())) { - anyGetterProp = prop; - anyGetterIndex = i; - break; - } - } JavaType anyType = anyGetter.getType(); // copied from BasicSerializerFactory.buildMapSerializer(): JavaType valueType = anyType.getContentType(); @@ -471,12 +454,26 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid BeanProperty.Std anyProp = new BeanProperty.Std(name, valueType, null, anyGetter, PropertyMetadata.STD_OPTIONAL); - // TODO: find way to merge these two cases together - if (anyGetterIndex != -1 && anyGetterProp != null) { + BeanPropertyWriter anyGetterProp = null; + int anyGetterIndex = -1; + for (int i = 0; i < props.size(); i++) { + BeanPropertyWriter prop = props.get(i); + if (Objects.equals(prop.getName(), anyGetter.getName()) + || Objects.equals(prop.getMember().getMember(), anyGetter.getMember())) { + anyGetterProp = prop; + anyGetterIndex = i; + break; + } + } + if (anyGetterIndex != -1) { + // Prop is already in place, just need to replace it AnyGetterWriter anyGetterWriter = new AnyGetterWriter(anyGetterProp, anyProp, anyGetter, anySer); props.set(anyGetterIndex, anyGetterWriter); } else { - builder.setAnyGetter(new AnyGetterWriter(anyProp, anyGetter, anySer)); + // Otherwise add it at the end, but won't be sorted... + BeanPropertyDefinition anyGetterPropDef = SimpleBeanPropertyDefinition.construct(config, anyGetter, name); + BeanPropertyWriter anyPropWriter = _constructWriter(prov, anyGetterPropDef, new PropertyBuilder(config, beanDesc), staticTyping, anyGetter); + props.add(new AnyGetterWriter(anyPropWriter, anyProp, anyGetter, anySer)); } } // Next: need to gather view information, if any: From 9b7a14a101d926c5434d4f72070eeb9a6b5fe573 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sun, 3 Mar 2024 15:43:22 +0900 Subject: [PATCH 14/18] Modify test name --- ...onPropertyOrderWithAnyGetter4388Test.java} | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) rename src/test/java/com/fasterxml/jackson/databind/ser/{JsonPropertyOrder4388Test.java => JsonPropertyOrderWithAnyGetter4388Test.java} (90%) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderWithAnyGetter4388Test.java similarity index 90% rename from src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java rename to src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderWithAnyGetter4388Test.java index 5743179be7..7ca21f9a7b 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrder4388Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/JsonPropertyOrderWithAnyGetter4388Test.java @@ -16,7 +16,7 @@ * Test to verify that the order of properties is preserved when using @JsonPropertyOrder * with @JsonUnwrapped and @JsonAnyGetter */ -public class JsonPropertyOrder4388Test extends DatabindTestUtil { +public class JsonPropertyOrderWithAnyGetter4388Test extends DatabindTestUtil { // Base class with properties static class BaseWithProperties { public String entityName; @@ -127,23 +127,15 @@ public Map secondProperties() { } } - private final ObjectMapper MAPPER = newJsonMapper(); - - @Test - public void testPrivateAnyGetter() throws Exception { - PrivateAnyGetterPojo pojo = new PrivateAnyGetterPojo(); - pojo.add("secondProperty", 2); - String json = MAPPER.writeValueAsString(pojo); - - assertEquals(a2q("{" + - "'firstProperty':1," + - "'thirdProperty':3," + - "'forthProperty':4," + - "'secondProperty':2" + // private accesor, wont' work here - "}"), - json); + @JsonPropertyOrder({ "firstProperty", "secondProperties", "thirdProperty", "forthProperty" }) + static class PrivateAnyGetterPojoSorted extends PrivateAnyGetterPojo { + public Map getSecondProperties() { + return super.secondProperties; + } } + private final ObjectMapper MAPPER = newJsonMapper(); + // For [databind#4388] @Test public void testSerializationOrderVersion1() throws Exception { @@ -270,6 +262,35 @@ public void testLinkUnlinkWithJsonIgnore() throws Exception { assertEquals(a2q("{'key':'value'}"), json); } + + @Test + public void testPrivateAnyGetter() throws Exception { + PrivateAnyGetterPojo pojo = new PrivateAnyGetterPojo(); + pojo.add("secondProperty", 2); + String json = MAPPER.writeValueAsString(pojo); + + assertEquals(a2q("{" + + "'firstProperty':1," + + "'thirdProperty':3," + + "'forthProperty':4," + + "'secondProperty':2}"), // private accesor, wont' work here + 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 941b3207788d98d900754182fb0e5cb53e24c569 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sun, 3 Mar 2024 15:49:54 +0900 Subject: [PATCH 15/18] Clean up --- .../jackson/databind/ser/AnyGetterWriter.java | 13 +++++++------ .../jackson/databind/ser/BeanSerializerFactory.java | 5 ++++- .../databind/ser/impl/BeanAsArraySerializer.java | 4 ---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java index 14cf0ca5f7..f838550153 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java @@ -25,6 +25,9 @@ public class AnyGetterWriter extends BeanPropertyWriter protected MapSerializer _mapSerializer; + /** + * @since 2.19 + */ @SuppressWarnings("unchecked") public AnyGetterWriter(BeanPropertyWriter parent, BeanProperty property, AnnotatedMember accessor, JsonSerializer serializer) @@ -38,16 +41,14 @@ public AnyGetterWriter(BeanPropertyWriter parent, BeanProperty property, } } + /** + * @deprecated Since 2.19, use one that takes {@link BeanPropertyWriter} instead. + */ @SuppressWarnings("unchecked") public AnyGetterWriter(BeanProperty property, AnnotatedMember accessor, JsonSerializer serializer) { - _accessor = accessor; - _property = property; - _serializer = (JsonSerializer) serializer; - if (serializer instanceof MapSerializer) { - _mapSerializer = (MapSerializer) serializer; - } + this(null, property, accessor, serializer); } /** 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 d65e65c89c..123977fd3f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -458,8 +458,11 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid int anyGetterIndex = -1; 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()) - || Objects.equals(prop.getMember().getMember(), anyGetter.getMember())) { + // or as method + || Objects.equals(prop.getMember().getMember(), anyGetter.getMember())) + { anyGetterProp = prop; anyGetterIndex = i; break; diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/BeanAsArraySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/BeanAsArraySerializer.java index 02f01cec00..017780c284 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/BeanAsArraySerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/BeanAsArraySerializer.java @@ -215,10 +215,6 @@ protected final void serializeAsArray(Object bean, JsonGenerator gen, Serializer prop.serializeAsElement(bean, gen, provider); } } - // NOTE: any getters cannot be supported either - //if (_anyGetterWriter != null) { - // _anyGetterWriter.getAndSerialize(bean, gen, provider); - //} } catch (Exception e) { wrapAndThrow(provider, e, bean, props[i].getName()); } catch (StackOverflowError e) { From b3947a3157e52bb0fcb79f5492a9d580fac97d38 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Sun, 3 Mar 2024 15:59:12 +0900 Subject: [PATCH 16/18] Add more comment --- .../jackson/databind/ser/BeanSerializerFactory.java | 6 ++++-- 1 file changed, 4 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 123977fd3f..a4244c9641 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -454,6 +454,7 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid BeanProperty.Std anyProp = new BeanProperty.Std(name, valueType, null, anyGetter, PropertyMetadata.STD_OPTIONAL); + // Check if there is a accessor exposed for the anyGetter BeanPropertyWriter anyGetterProp = null; int anyGetterIndex = -1; for (int i = 0; i < props.size(); i++) { @@ -469,11 +470,12 @@ protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvid } } if (anyGetterIndex != -1) { - // Prop is already in place, just need to replace it + // There is prop is already in place, just need to replace it AnyGetterWriter anyGetterWriter = new AnyGetterWriter(anyGetterProp, anyProp, anyGetter, anySer); props.set(anyGetterIndex, anyGetterWriter); } else { - // Otherwise add it at the end, but won't be sorted... + // Otherwise just add it at the end, but won't be sorted... + // This is case where JsonAnyGetter is private/protected, BeanPropertyDefinition anyGetterPropDef = SimpleBeanPropertyDefinition.construct(config, anyGetter, name); BeanPropertyWriter anyPropWriter = _constructWriter(prov, anyGetterPropDef, new PropertyBuilder(config, beanDesc), staticTyping, anyGetter); props.add(new AnyGetterWriter(anyPropWriter, anyProp, anyGetter, anySer)); From 46af6cbff801cb40897aefecb35be4cf898912a2 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Fri, 31 May 2024 12:46:47 +0900 Subject: [PATCH 17/18] Fix test POJO annotated with @Test --- .../java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java index b05cbe3275..0ac7a5d45a 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/AnyGetterTest.java @@ -186,7 +186,6 @@ public void set(String name, String value) { } // [databind#1458]: Allow `@JsonAnyGetter` on fields too - @Test static class DynaFieldOrderedBean { public int id = 123; From 9411e9ca895957479f592020a5417a87b77e48e3 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sat, 20 Jul 2024 17:51:32 -0700 Subject: [PATCH 18/18] Minor comment adds --- .../jackson/databind/introspect/POJOPropertiesCollector.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java index bddf659fdc..64fa293b0d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java @@ -550,6 +550,8 @@ protected void _addFields(Map props) _anySetterField = new LinkedList<>(); } _anySetterField.add(f); + // 20-July-2024: [databind#4396]: Skip the rest of processing, but only + // for "any-setter', not any-getter continue; } } @@ -1084,6 +1086,8 @@ protected void _addGetterMethod(Map props, _anyGetters = new LinkedList<>(); } _anyGetters.add(m); + // 20-Jul-2024: [databind#4396] Do not stop processing here + // (used to return) } // @JsonKey? if (Boolean.TRUE.equals(ai.hasAsKey(_config, m))) {