【发布时间】:2019-11-26 16:59:45
【问题描述】:
我有以下类,我想通过 Jackson (2.9.10) 使用其 ID 引用对象进行 JSON 序列化/反序列化。
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Key {
@JsonProperty("id")
private String id;
@JsonProperty("random_field_key")
private boolean randomFieldKey;
// Getters and setters
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Value {
@JsonProperty("id")
private String id;
@JsonProperty("random_field_value")
private boolean randomFieldValue;
// Getters and setters
}
@JsonPropertyOrder({"keys", "values", "relationships"})
public class Relationship {
@JsonProperty("keys")
private List<Key> keys;
@JsonProperty("values")
private List<Value> values;
@JsonProperty("relationships")
private Map<Key, Value> relationships;
// Getters and setters
}
public class Main {
private static final ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws IOException {
Value value = new Value();
value.setId("valueId");
value.setRandomFieldValue(true);
Key key = new Key();
key.setId("keyId");
key.setRandomFieldKey(false);
Map<Key, Value> map = new HashMap<Key, Value>();
map.put(key, value);
Relationship relationship = new Relationship();
relationship.setKeys(Collections.singletonList(key));
relationship.setValues(Collections.singletonList(value));
relationship.setRelationships(map);
String serialisedRelationship = mapper.writeValueAsString(relationship);
Relationship deserialisedRelationship = mapper.readValue(serialisedRelationship, Relationship.class);
}
}
预期结果如下:
{
"keys": [
{
"id": "keyId",
"random_field_key": false
}
],
"values": [
{
"id": "valueId",
"random_field_value": true
}
],
"relationships": {
"keyId": "valueId"
}
}
相反,我得到:
{
"keys": [
{
"id": "keyId",
"random_field_key": false
}
],
"values": [
{
"id": "valueId",
"random_field_value": true
}
],
"relationships": {
"util.teststack.Key@8646db9": "valueId"
}
}
我添加了一个自定义序列化器,它允许将 Key 序列化为 Id(我认为 JsonIdentityInfo 注释会解决这个问题)并设法获得预期的结果。
public class KeySerializer extends JsonSerializer<Key> {
@Override
public void serialize(Key value,
JsonGenerator gen,
SerializerProvider serializers)
throws IOException {
gen.writeFieldName(value.getId());
}
}
@JsonPropertyOrder({"keys", "values", "relationships"})
public class Relationship {
@JsonProperty("keys")
private List<Key> keys;
@JsonProperty("values")
private List<Value> values;
@JsonSerialize(keyUsing = KeySerializer.class)
@JsonProperty("relationships")
private Map<Key, Value> relationships;
// Getters and setters
}
我似乎无法反序列化 JSON,但我总是遇到异常:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot find a (Map) Key deserializer for type [simple type, class util.teststack.Key]
虽然添加自定义反序列化器也是一个好主意,但我很难理解如何引用“外部”(已经实例化)的 Key 实例。我在 DeserializerContext 中似乎能做的就是实例化一个新的密钥,而不是引用之前创建的密钥。
检查 DeserializerContext 我可以看到我需要的所有实例都在那里,但我不明白如何引用(并返回它们)。 令人惊讶的是,映射值的引用在没有序列化器/反序列化器的情况下也能正常工作。
public class KeyDeserializer extends com.fasterxml.jackson.databind.KeyDeserializer {
@Override
public Key deserializeKey(
String key,
DeserializationContext ctxt) {
Key newKey = new Key();
newKey.setId(key);
return newKey;
}
}
@JsonPropertyOrder({"keys", "values", "relationships"})
public class Relationship {
@JsonProperty("keys")
private List<Key> keys;
@JsonProperty("values")
private List<Value> values;
@JsonSerialize(keyUsing = KeySerializer.class)
@JsonDeserialize(keyUsing = KeyDeserializer.class)
@JsonProperty("relationships")
private Map<Key, Value> relationships;
}
我实现了接受的答案,以这种方式解决问题:
public class KeyDeSerializer extends com.fasterxml.jackson.databind.KeyDeserializer {
@Override
public Key deserializeKey(String key, DeserializationContext ctxt) {
Relationship obj = (Relationship) ctxt.getParser().getParsingContext().getParent().getCurrentValue();
return getKey(key, obj);
}
private Key getKey(String key, Relationship obj) {
for (Key ck : obj.getKeys()) {
if (ck.getId().equals(key)) {
return ck;
}
}
return null;
}
}
【问题讨论】:
-
我很好奇:自从接受了答案,你最后是怎么解决的?
-
我使用公认的解决方案来导航 JSON 并检索与密钥关联的正确对象并在 KeyDeserializer 中返回它。我应该在哪里发布带有工作解决方案的 MWE?
标签: java json serialization jackson