杰克逊反序列化带有额外字段的地图
Jackson serialise map with extra fields
如果 class 扩展一个 Map 并包含一些额外的字段。例如上次修改日期,Jackson 似乎忽略了地图 属性 中未包含的任何内容。
我有一个 class 看起来像下面这样的东西:
import java.io.IOException;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Objects;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Foo extends HashMap<String, String> {
private OffsetDateTime lastModifiedTime;
public Foo() {
super();
lastModifiedTime = OffsetDateTime.now();
}
public void setLastModifiedTime(OffsetDateTime newTime) {
this.lastModifiedTime = newTime;
}
public OffsetDateTime getLastModifiedTime() {
return this.lastModifiedTime;
}
public static void main(String[] args) throws IOException {
Foo f = new Foo();
f.put("hello", "world");
ObjectMapper om = new ObjectMapper();
om.findAndRegisterModules();
String result = om.writeValueAsString(f);
if(f.equals(om.readValue(result, Foo.class))) {
System.out.println("Wooo");
} else {
System.out.println("Booo: " + result);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Foo)) {
return false;
}
if (!super.equals(obj)) {
return false;
}
Foo foo = (Foo) obj;
return Objects.equals(getLastModifiedTime(), foo.getLastModifiedTime());
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), getLastModifiedTime());
}
}
运行时输出 booo: {"hello":"world"}
其中不包括最后修改日期。
我已经尝试将 @JsonInclude
注释添加到 属性 和吸气剂,但这不会导致它包含额外的字段。
让 Jackson 包含这个额外字段的正确方法是什么?
默认情况下,您的地图将落入 MapSerializer
。您可以注册序列化器修饰符来添加自定义 属性,但最好将地图嵌套为 Foo
的 属性 并展开它:
@JsonUnwrapped
private HashMap<String, String> fooMap;
通常认为扩展 HashMap 是不好的做法。相反,您应该创建一个 class,其中 具有 地图和附加字段。
这将解决您的问题,但还有其他好处:
- 您将能够封装规则(例如防止添加某些 keys/values 等)
- 如果需要,您将能够更改 Map 实现(LinkedHashMap、同步映射、并发映射)
您可以像这样使用 @JsonAnyGetter
和 @JsonAnySetter
而不是 @JsonUnwrapped
:
public class Foo {
private OffsetDateTime lastModifiedTime;
private HashMap<String, String> additionalProperties = new HashMap<String, String>();
public Foo() {
super();
lastModifiedTime = OffsetDateTime.now();
}
public void setLastModifiedTime(OffsetDateTime newTime) {
this.lastModifiedTime = newTime;
}
public OffsetDateTime getLastModifiedTime() {
return this.lastModifiedTime;
}
@JsonAnyGetter
public Map<String, String> any() {
return this.additionalProperties;
}
@JsonAnySetter
public void set(String name, String value) {
this.additionalProperties.put(name, value);
}
}
如果 class 扩展一个 Map 并包含一些额外的字段。例如上次修改日期,Jackson 似乎忽略了地图 属性 中未包含的任何内容。
我有一个 class 看起来像下面这样的东西:
import java.io.IOException;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Objects;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Foo extends HashMap<String, String> {
private OffsetDateTime lastModifiedTime;
public Foo() {
super();
lastModifiedTime = OffsetDateTime.now();
}
public void setLastModifiedTime(OffsetDateTime newTime) {
this.lastModifiedTime = newTime;
}
public OffsetDateTime getLastModifiedTime() {
return this.lastModifiedTime;
}
public static void main(String[] args) throws IOException {
Foo f = new Foo();
f.put("hello", "world");
ObjectMapper om = new ObjectMapper();
om.findAndRegisterModules();
String result = om.writeValueAsString(f);
if(f.equals(om.readValue(result, Foo.class))) {
System.out.println("Wooo");
} else {
System.out.println("Booo: " + result);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Foo)) {
return false;
}
if (!super.equals(obj)) {
return false;
}
Foo foo = (Foo) obj;
return Objects.equals(getLastModifiedTime(), foo.getLastModifiedTime());
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), getLastModifiedTime());
}
}
运行时输出 booo: {"hello":"world"}
其中不包括最后修改日期。
我已经尝试将 @JsonInclude
注释添加到 属性 和吸气剂,但这不会导致它包含额外的字段。
让 Jackson 包含这个额外字段的正确方法是什么?
默认情况下,您的地图将落入 MapSerializer
。您可以注册序列化器修饰符来添加自定义 属性,但最好将地图嵌套为 Foo
的 属性 并展开它:
@JsonUnwrapped
private HashMap<String, String> fooMap;
通常认为扩展 HashMap 是不好的做法。相反,您应该创建一个 class,其中 具有 地图和附加字段。
这将解决您的问题,但还有其他好处:
- 您将能够封装规则(例如防止添加某些 keys/values 等)
- 如果需要,您将能够更改 Map 实现(LinkedHashMap、同步映射、并发映射)
您可以像这样使用 @JsonAnyGetter
和 @JsonAnySetter
而不是 @JsonUnwrapped
:
public class Foo {
private OffsetDateTime lastModifiedTime;
private HashMap<String, String> additionalProperties = new HashMap<String, String>();
public Foo() {
super();
lastModifiedTime = OffsetDateTime.now();
}
public void setLastModifiedTime(OffsetDateTime newTime) {
this.lastModifiedTime = newTime;
}
public OffsetDateTime getLastModifiedTime() {
return this.lastModifiedTime;
}
@JsonAnyGetter
public Map<String, String> any() {
return this.additionalProperties;
}
@JsonAnySetter
public void set(String name, String value) {
this.additionalProperties.put(name, value);
}
}