package alien4cloud.json.deserializer;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Maps;
/**
* Manages polymorphism deserialization for Jackson through discriminator property (based on property value).
*/
public class AbstractFieldValueDiscriminatorPolymorphicDeserializer<T> extends StdDeserializer<T> {
private Map<String, Class<? extends T>> registry = Maps.newHashMap();
private String propertyDiscriminatorName;
public AbstractFieldValueDiscriminatorPolymorphicDeserializer(String fieldDiscriminatorName, Class<T> clazz) {
super(clazz);
this.propertyDiscriminatorName = fieldDiscriminatorName;
}
protected void addToRegistry(String discriminator, Class<? extends T> clazz) {
registry.put(discriminator, clazz);
}
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = mapper.readTree(jp);
return deserializeAfterRead(jp, ctxt, mapper, root);
}
protected T deserializeAfterRead(JsonParser jp, DeserializationContext ctxt, ObjectMapper mapper, ObjectNode root) throws JsonProcessingException {
Class<? extends T> parameterClass = null;
Iterator<Map.Entry<String, JsonNode>> elementsIterator = root.fields();
while (elementsIterator.hasNext()) {
Map.Entry<String, JsonNode> element = elementsIterator.next();
String name = element.getKey();
if (propertyDiscriminatorName.equals(name)) {
String value = element.getValue().asText();
if (registry.containsKey(value)) {
parameterClass = registry.get(value);
break;
}
}
}
if (parameterClass == null) {
return null;
}
return mapper.treeToValue(root, parameterClass);
}
protected void failedToFindImplementation(JsonParser jp, ObjectNode root) throws JsonParseException {
throw new JsonParseException("Failed to find implementation for node " + root + " from registry " + registry, jp.getCurrentLocation());
}
}