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()); } }