我正在尝试使用杰克逊的功能将未知字段反序列化到地图中,使用
@JsonAnySetter
。这对于字段用 @JsonAnySetter
注释的 Java 类来说效果很好,但不适用于记录:
public class SerdeTest {
private static final String CONTENT = "{ \"name\": \"foo\", \"bar\": \"baz\" }";
private ObjectMapper om = new ObjectMapper();
static class ThisWorks {
public String name;
@JsonAnySetter Map<String, String> others;
}
@Test
public void deserClass() throws IOException {
var data = om.readValue(CONTENT, ThisWorks.class);
assertThat(data.name, equalTo("foo"));
assertThat(data.others.get("bar"), equalTo("baz"));
}
record ThisDoesnt(String name, @JsonAnySetter Map<String, String> others) {}
@Test
public void deserRecord() throws IOException {
var data = om.readValue(CONTENT, ThisDoesnt.class);
assertThat(data.name, equalTo("foo"));
assertThat(data.others.get("bar"), equalTo("baz"));
}
}
如何将此注释与记录一起使用?
记录尚未像您期望的那样干净地支持
@JsonAnySetter
- 参考此 GitHub 问题。
恕我直言,使用
record
类型的概念与您与 @JsonAnySetter Map<String, String> others
一起寻求的灵活性相矛盾。虽然您使用减少的样板代码来声明不可变类型,但另一方面,在实践中您正在寻求更新实体的属性而不遵守固定的构造。
作为链接线程的替代方案,您可以尝试重写
others
属性的自定义构造函数和访问器,如下所示以使其工作:
record ThisDoes(String name, @JsonAnySetter Map<String, String> others) {
@JsonCreator
ThisDoes(@JsonProperty("name") String name) {
this(name, new HashMap<>());
}
public Map<String, String> others() {
return Collections.unmodifiableMap(others);
}
@JsonAnySetter
private void updateProperty(String name, String value) {
others.put(name, value);
}
}
(用
v-2.15.3
验证)
但请注意,这也消除了在向
record
表示迁移期间可能寻求的好处的样板代码的减少。