how to resolve object references with a custom Jackson deserializer
Solution 1:
I guess jackson should be able to do it for you, but i couldn't figure out how. 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. Then your KeyDeserializer
will use that map to get existing instances.
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
@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", ...})