Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ protected JsonSerializer<Object> 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())
Copy link
Member

@cowtowncoder cowtowncoder Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this one: why is the change necessary/correct?
At least requires a comment on why we are looking at method/field name of concrete accessor, instead of processed property name.

// or as method
|| Objects.equals(prop.getMember().getMember(), anyGetter.getMember()))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
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<String, Object> additionalProperties;
@JsonProperty(value = "additionalProperties")
private Map<String, Object> hidden;
Comment on lines +22 to +23
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified to hidden, so we get better view of what's actually conflicting --@JsonProperty(value = "additionalProperties")


@JsonAnySetter
private void additionalProperties(String key, Object value) {
if (additionalProperties == null) {
additionalProperties = new HashMap<>();
}
additionalProperties.put(key.replace("\\.", "."), value);
}

@JsonAnyGetter
public Map<String, Object> additionalProperties() {
return additionalProperties;
}

public Map<String, Object> hidden() {
return hidden;
}

public void hidden(Map<String, Object> additionalPropertiesProperty) {
this.hidden = additionalPropertiesProperty;
}
}

private final ObjectMapper MAPPER = newJsonMapper();

@Test
public void testOverwrite()
throws Exception
{
Pojo5342 pojo = new Pojo5342();
pojo.additionalProperties("foo", "bar");

Map<String, Object> 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.hidden().size());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public Map<String, Object> secondProperties() {
}
}

//
@JsonPropertyOrder({ "firstProperty", "secondProperties", "thirdProperty", "forthProperty" })
static class PrivateAnyGetterPojoSorted extends PrivateAnyGetterPojo {
public Map<String, Object> getSecondProperties() {
Expand Down Expand Up @@ -277,20 +278,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);
}

Comment on lines -280 to -293
Copy link
Member Author

@JooHyukKim JooHyukKim Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I deleted so we have better visibility on subject matter)
@cowtowncoder May I ask for a bit of help on what the correct behavior should be?

So this one is now failing.
@JsonPropertyOrder specified via line 131 does work now.
Now it serializes into...

{
    "firstProperty":1,"
    secondProperties":{"secondProperty":2}, // <---- as configured
    "thirdProperty":3,
    "forthProperty":4,
    "secondProperty":2
}

... this, but I can't figure out why there is trailing "secondProperty":2 at the end.

Moreover, I am more confused because it the ordering like above should've worked even before since we have

public Map<String, Object> getSecondProperties() {
...

declared at line 133.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know for sure, but my guess is that the change broke linkage between

        @JsonAnyGetter
        private Map<String, Object> secondProperties = new HashMap<>();```

and

    public Map<String, Object> getSecondProperties() {
        return super.secondProperties;

so that "extra" one is for `@JsonAnyGetter` annotated field.

This whole set of tests and set up is very complicated and quite hard to reason about, unfortunately.

private void _configureValues(BaseWithProperties base) {
base.entityId = 1;
base.entityName = "Bob";
Expand Down
Loading