I did such test.
First define a pojo:
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class ESModel {
private Long id;
@JsonUnwrapped
private Result result;
private Map<String, Object> extra = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getExtra() {
return extra;
}
@JsonAnySetter
public void set(String key, Object value) {
extra.put(key, value);
}
@Data
public static class Result {
private String name;
}
}
Then test serialization:
@Test
public void test001() {
ESModel esModel = new ESModel();
ESModel.Result child = new ESModel.Result();
child.setName("aaa");
Map<String, Object> map = new HashMap<>();
map.put("age", 12);
esModel.setId(1L);
esModel.setResult(child);
esModel.setExtra(map);
System.out.println(JSON.toJSONString(esModel));
}
The output is following which I expected.
{"id":1,"name":"aaa","age":12}
And then test deserialization:
String json = "{\"id\":1,\"name\":\"aaa\",\"age\":12}";
ESModel model = JSON.parseObject(json, ESModel.class);
System.out.println(model);
The output is following which out of my expectation. The property 'name' has been deserialized twice.
ESModel(id=1, result=ESModel.Result(name=aaa), extra={name=aaa, age=12})
PS:The JSON utitliy class is follow:
public abstract class JSON {
private static ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.setTimeZone(TimeZone.getDefault());
objectMapper.setSerializationInclusion(NON_ABSENT);
objectMapper.disable(FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.disable(READ_DATE_TIMESTAMPS_AS_NANOSECONDS);
objectMapper.disable(WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
objectMapper.disable(DEFAULT_VIEW_INCLUSION);
objectMapper.enable(ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER);
objectMapper.enable(PROPAGATE_TRANSIENT_MARKER);
}
/*-----------------------deserialization-----------------------*/
public static <T> T parseObject(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
/*-----------------------serialization-----------------------*/
public static String toJSONString(Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
}
Comment From: cowtowncoder
Unfortunately the way unwrapped handling is implemented there is no way for parent deserializer to know which properties it has might be handled by child deserializers, and as a result, any-setter will be given anything not consumed by deserializer itself.
With 3.0 handling can be changed and hope is this could be resolved then.
Comment From: Bijnagte
I just ran into a different flavor of this bug involving record classes which completely fail to deserialize when both annotations are present. Order of properties does not matter. Example code:
record NameId(String id, String name) {}
@JsonInclude(JsonInclude.Include.NON_NULL)
record Nested(
@JsonUnwrapped NameId nameId,
@JsonAnySetter @JsonAnyGetter Map<String, Object> additionalProperties) {}
String json =
"""
{ "id": "12345",
"name": "Test",
"otherProperty": "value"
}
""";
ObjectMapper objectMapper = new ObjectMapper();
Nested nested = objectMapper.readValue(json, Nested.class);
throws an exception like:
java.lang.ClassCastException: Cannot construct instance of `Nested`, problem: Nested cannot be cast to class java.util.Map
Comment From: JooHyukKim
@Bijnagte Did your case Worked before, then stopped working? If so, could you provide which version behavior changed?
And have you tried the latest version out there? 2.19 or 2.20
Comment From: cowtowncoder
As per originally reported issue, combination does not work -- I think this is just a different symptom.
One possibility here would be to catch conflict on POJOPropertiesCollector when collecting information and fail cleanly, as the combination will not work. Instead of at runtime working wrong way.
Comment From: Bijnagte
@Bijnagte Did your case Worked before, then stopped working? If so, could you provide which version behavior changed?
And have you tried the latest version out there? 2.19 or 2.20
As @cowtowncoder said, this is just a different symptom I think, and it never worked to my knowledge. I ran into this open issue when looking for why I was getting that error. I figured it was worth pointing out so if a fix eventually gets introduced it would also cover the record case but I didn't think of it as a distinct issue. BTW thank you for all your work on an awesome library!
Should I raise a different issue or do anything else?
Comment From: cowtowncoder
I think this issue is clear enough, so no need to file separate issue.