[英]how to resolve object references with a custom Jackson deserializer
{
"name": "test",
"columns": [
{
"name": "a",
"type": "TEXT"
},
{
"name": "b",
"type": "TEXT"
}
],
"rules": [
{
"production": {
"a": "[b]"
},
"filters": {
"a": [
"",
"ALL",
false
]
},
"refcolumns": [
"b"
]
}
]
}
The JSON document has a property columns
that contains a Set of Column
objects (could also be a map using the property name as a key). JSON 文档有一个属性columns
,其中包含一组Column
对象(也可以是使用属性名称作为键的 map)。 This is the only spot where the columns objects are fully serialized in JSON.这是 JSON 中列对象完全序列化的唯一地方。 Everywhere else, columns are referenced using the name
property that is unique在其他任何地方,列都是使用唯一的name
属性引用的
Reference can be used for map keys and values参考可用于 map 键和值
I would like to deserialize this document and:我想反序列化此文档并:
columns
property在columns
属性中解析对其对应 object 的引用Column
every time.使用相同的 java object实例(列 class 是不可变的)并且不要每次都创建一个新Column
。 (I want to reduce the number of objects) (我想减少对象的数量)JsonIdentityInfodoesnt work for map keys. JsonIdentityInfo 不适用于 map 键。 So I use custom serializers所以我使用自定义序列化程序
Here how is serialized the Rule class, JsonColumnKeySerializer
just return the "name" property of Column这里如何序列化规则 class, JsonColumnKeySerializer
只返回 Column 的“名称”属性
class Rule {
@JsonSerialize(keyUsing = Column.JsonColumnKeySerializer.class)
private HashMap<Column, RuleFormula> productions = new HashMap<>();
@JsonSerialize(keyUsing = Column.JsonColumnKeySerializer.class)
private Map<Column, RuleFilter> filters = new LinkedHashMap<>();
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name")
@JsonIdentityReference(alwaysAsId=true) // for testing purposes...
private Set<Column> refcolumns = new HashSet<>();
}
I guess jackson should be able to do it for you, but i couldn't figure out how.我想 jackson 应该可以为你做,但我不知道怎么做。 As a workaround you can write custom deserializer, in which you can cache the results by name property:作为一种解决方法,您可以编写自定义反序列化器,您可以在其中按名称属性缓存结果:
public class CachingColumnDeserializer extends JsonDeserializer<Column> {
private static final Map<String, Column> MAP = new HashMap<>();
@Override
public Column deserialize(JsonParser parser, DeserializationContext context) throws IOException, JacksonException {
JsonNode node = parser.getCodec().readTree(parser);
String name = node.get("name").asText();
return MAP.computeIfAbsent(name, nameKey -> new Column(nameKey, node.get("type").asText()));
}
public static Map<String, Column> getMap() {
return Collections.unmodifiableMap(MAP);
}
}
We need the static instance of the map in order to share it with KeyDeserializer
, getMap() returns unmodifiableMap so we can't change it by mistake.我们需要 map 的 static 实例以便与KeyDeserializer
共享它, getMap() 返回 unmodifiableMap 所以我们不能错误地更改它。 Then your KeyDeserializer
will use that map to get existing instances.然后您的KeyDeserializer
将使用该 map 来获取现有实例。
public class CachedColumnKeyDeserializer extends KeyDeserializer {
private final Map<String, Column> map;
public CachedColumnKeyDeserializer() {
this.map = CachingColumnDeserializer.getMap();
}
@Override
public Object deserializeKey(String key, DeserializationContext context) throws IOException {
Column column = this.map.get(key);
if (column == null) {
return new Column(key, null);
}
return column;
}
}
Specify how to deserialize Column
class指定如何反序列化Column
class
@JsonDeserialize(using = CachingColumnDeserializer.class, keyUsing = CachedColumnKeyDeserializer.class)
Just to be on the safe side you can specify you need to deserialize columns before other properties为了安全起见,您可以指定需要在其他属性之前反序列化列
@JsonPropertyOrder({"name", "columns", ...})
I implemented the solution proposed here Serialize and Deserialize Map<Object, Object> Jackson我实现了这里提出的解决方案Serialize and Deserialize Map<Object, Object> Jackson
I had to crawl up to the Root parent to find the data.我必须爬到 Root 父级才能找到数据。
Compared to the I changed the Set<Column>
to a Map<String,Column>
.与我将Set<Column>
更改为Map<String,Column>
相比。
public class JsonColumnKeyDeserializer extends com.fasterxml.jackson.databind.KeyDeserializer {
@Override
public Object deserializeKey(String key, DeserializationContext context) throws IOException {
final MyRootClass root = (MyRootClass ) getRoot(context);
final Map<String, Column> columns = root.getColumns();
return columns.get(key);
}
private Object getRoot(DeserializationContext context) {
JsonStreamContext parent = context.getParser().getParsingContext().getParent();
while (parent.getParent() != null && !parent.getParent().inRoot()) {
parent = parent.getParent();
}
return parent.getCurrentValue();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.