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

com.jonnymatts.jzonbie.response.DefaultingQueueDeserializer Maven / Gradle / Ivy

package com.jonnymatts.jzonbie.response;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.*;
import com.jonnymatts.jzonbie.model.AppResponse;
import com.jonnymatts.jzonbie.model.AppResponseBuilder;
import com.jonnymatts.jzonbie.model.content.BodyContent;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static com.jonnymatts.jzonbie.model.content.ArrayBodyContent.arrayBody;
import static com.jonnymatts.jzonbie.model.content.BodyContent.TYPE_IDENTIFIER;
import static com.jonnymatts.jzonbie.model.content.LiteralBodyContent.literalBody;
import static com.jonnymatts.jzonbie.model.content.ObjectBodyContent.objectBody;
import static com.jonnymatts.jzonbie.model.content.StringBodyContent.stringBody;
import static com.jonnymatts.jzonbie.response.DefaultAppResponse.StaticDefaultAppResponse.staticDefault;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

public class DefaultingQueueDeserializer extends StdDeserializer {

    public DefaultingQueueDeserializer() {
        this(null);
    }

    public DefaultingQueueDeserializer(Class vc) {
        super(vc);
    }

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

        final JsonNode defaultNode = node.get("default");
        final DefaultAppResponse defaultAppResponse = (defaultNode == null || defaultNode instanceof NullNode || defaultNode instanceof TextNode) ? null
                : staticDefault(convertObjectNodeToAppResponse(defaultNode));

        final List appResponses = StreamSupport.stream(node.get("primed").spliterator(), false)
                .map(this::convertObjectNodeToAppResponse)
                .collect(toList());

        return new DefaultingQueue(){{
            add(appResponses);
            setDefault(defaultAppResponse);
        }};
    }

    private AppResponse convertObjectNodeToAppResponse(JsonNode queueNode) {
        final AppResponseBuilder builder = AppResponse.builder(queueNode.get("statusCode").intValue());
        final BodyContent body = getBodyContent(queueNode.get("body"));
        if(body != null) {
            builder.withBody(body);
        }
        final Map headers = (Map) convertJsonNodeToObject(queueNode.get("headers"));
        if(headers != null) {
            headers.entrySet().forEach(e -> builder.withHeader(e.getKey(), e.getValue()));
        }
        return builder.build();
    }

    // TODO: Handle null here
    private BodyContent getBodyContent(JsonNode bodyNode) {
        final Object object = convertJsonNodeToObject(bodyNode);
        if(object == null) return null;
        if(bodyNode instanceof ObjectNode) {
            final Map map = (Map) object;
            map.remove(TYPE_IDENTIFIER);
            return objectBody(map);
        } else {
            final List list = (List) object;
            final String bodyContentType = (String)list.get(0);
            switch (bodyContentType) {
                case "J_STRING":
                    return stringBody((String)list.get(1));
                case "J_ARRAY":
                    list.remove(0);
                    return arrayBody((List)list.get(0));
                default:
                    return literalBody(list.get(1));
            }
        }
    }

    private Map getMapFromObjectNode(ObjectNode objectNode) {
        final Map map = iteratorToStream(objectNode.fields()).collect(
                toMap(
                        Map.Entry::getKey,
                        e -> convertJsonNodeToObject(e.getValue())
                )
        );
        return map;
    }

    private List getListFromArrayNode(ArrayNode arrayNode) {
        return iteratorToStream(arrayNode.elements())
                .map(this::convertJsonNodeToObject)
                .collect(toList());
    }

    private Object convertJsonNodeToObject(JsonNode node) {
        if(node == null) return null;
        if(node instanceof NullNode) return null;
        if(node instanceof TextNode) return node.textValue();
        if(node instanceof IntNode) return node.intValue();
        if(node instanceof LongNode) return node.longValue();
        if(node instanceof BooleanNode) return node.booleanValue();
        if(node instanceof ArrayNode) return getListFromArrayNode((ArrayNode) node);
        if(node instanceof ObjectNode) return getMapFromObjectNode((ObjectNode) node);
        throw new RuntimeException("Unknown node type: " + node.getNodeType());
    }

    private static  Stream iteratorToStream(final Iterator iterator) {
        Iterable iterable = () -> iterator;
        return StreamSupport.stream(iterable.spliterator(), false);
    }
}