All Downloads are FREE. Search and download functionalities are using the official Maven repository.

estonlabs.cxtl.common.stream.managed.AbstractInboundDeserializer Maven / Gradle / Ivy

There is a newer version: 1.4.14
Show newest version
package estonlabs.cxtl.common.stream.managed;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.JsonPath;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import net.minidev.json.JSONArray;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * This class can deserialize a Json message to an Inbound message based on a value of one of the nodes
 * The value of the node is mapped to a Type in a Map
 * @param 
 */
public abstract class AbstractInboundDeserializer extends JsonDeserializer {
    private final List targets;
    protected AbstractInboundDeserializer(List targets) {
        this.targets = targets;
    }

    @Override
    public final T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        ObjectNode node = jp.getCodec().readTree(jp);

        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        return wrap(mapper.treeToValue(node, determineTargetClass(node, mapper)));
    }

    protected abstract T wrap(InboundMessage message);

    private Class determineTargetClass(JsonNode node, ObjectMapper mapper) throws IOException {
        for(Target t : targets){
            if (t.matches(node, mapper)) return t.getType(node, mapper);
        }
        throw new IOException("Type identifier not found");
    }


    protected interface Target {
        boolean matches(JsonNode root, ObjectMapper mapper);
        @NonNull Class getType(JsonNode root, ObjectMapper mapper) throws IOException;

    }

    protected static abstract class SingleNodeTarget implements Target {
        abstract String getId();
        abstract Class get(String s);

        @Override
        public boolean matches(JsonNode root, ObjectMapper mapper) {
            return root.get(this.getId()) != null;
        }


        @Override
        public  @NonNull Class getType(JsonNode root, ObjectMapper mapper) {
            JsonNode jsonNode = root.get(this.getId());
            String type = jsonNode.asText();
            return get(type);
        }
    }

    @RequiredArgsConstructor
    @Getter
    protected static class JsonPathTarget implements Target {
        final String path;
        final Map> mappings;

        @Override
        public boolean matches(JsonNode root, ObjectMapper mapper) {
            try {
                String json = mapper.writeValueAsString(root);
                if ( getPath().startsWith("$")) {
                    JSONArray array = JsonPath.read(json, getPath());
                    return array.size() == 1;
                }
                else {
                    return JsonPath.read(json, getPath()).toString() != null;
                }
            }
            catch(Exception e) {
                return false;
            }
        }
        @Override
        public  @NonNull Class getType(JsonNode root, ObjectMapper mapper) throws IOException {
            String key = null;
            String json = null;
            try {
                 json = mapper.writeValueAsString(root);
            }
            catch(Exception e) {
                throw new IOException(e);
            }
            if ( getPath().startsWith("$")) {
                JSONArray array = JsonPath.read(json, getPath());
                key = (array.get(0)).toString();
            }
            else {
                key = JsonPath.read(json, getPath()).toString();
            }
            if(key != null) {
                if ( mappings.containsKey(key)) {
                    return mappings.get(key);
                }
            }
            throw new IOException("Unknown type identifier: " + key);
        }
    }

    @RequiredArgsConstructor
    @Getter
    protected static final class MapTarget extends SingleNodeTarget{
        final String id;
        final Map> mappings;
        public Class get(String s){
            return mappings.get(s);
        }
    }

    @RequiredArgsConstructor
    @Getter
    protected static final class StaticMapping extends SingleNodeTarget{
        final String id;
        final Class type;
        public Class get(String s){
            return type;
        }
    }

    @RequiredArgsConstructor
    @Getter
    protected static final class ContainsTarget extends SingleNodeTarget{
        final String id;
        final Map> mappings;
        public Class get(String s){
            for(Map.Entry> e : mappings.entrySet()){
                if(s.contains(e.getKey())) return e.getValue();
            }
            return null;
        }
    }

}