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

org.eclipse.yasson.internal.JsonbRiParser Maven / Gradle / Ivy

Go to download

Eclipse Yasson. Reference implementation of JSR-367 (JSON-B).

There is a newer version: 3.0.4
Show newest version
/*******************************************************************************
 * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
 * which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 * Roman Grigoriadi
 ******************************************************************************/

package org.eclipse.yasson.internal;

import org.eclipse.yasson.internal.properties.MessageKeys;
import org.eclipse.yasson.internal.properties.Messages;

import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonValue;
import javax.json.bind.JsonbException;
import javax.json.stream.JsonLocation;
import javax.json.stream.JsonParser;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;
import java.util.Stack;
import java.util.stream.Stream;

/**
 * Decorator for JSONP parser used by JSONB.
 *
 * @author Roman Grigoriadi
 */
public class JsonbRiParser implements JsonParser, JsonbParser {

    /**
     * State holder for current json structure level.
     */
    public static class LevelContext {
        private final LevelContext parent;
        private JsonParser.Event lastEvent;
        private String lastKeyName;
        private boolean parsed;

        /**
         * Creates an instance.
         *
         * @param parent Parent context.
         */
        public LevelContext(LevelContext parent) {
            this.parent = parent;
        }

        /**
         * Gets last event.
         *
         * @return Last event.
         */
        public JsonParser.Event getLastEvent() {
            return lastEvent;
        }

        private void setLastEvent(JsonParser.Event lastEvent) {
            this.lastEvent = lastEvent;
        }

        /**
         * Gets last key name.
         *
         * @return Last key name.
         */
        public String getLastKeyName() {
            return lastKeyName;
        }

        private void setLastKeyName(String lastKeyName) {
            this.lastKeyName = lastKeyName;
        }

        /**
         * Get parent.
         *
         * @return Parent.
         */
        public LevelContext getParent() {
            return parent;
        }

        /**
         * Getter for parsed property.
         *
         * @return True or false.
         */
        public boolean isParsed() {
            return parsed;
        }

        private void finish() {
            if (parsed) {
                throw new IllegalStateException("Level already parsed");
            }
            parsed = true;
        }
    }

    private final JsonParser jsonParser;

    private final Stack level = new Stack<>();

    private final LevelContext root = new LevelContext(null);

    /**
     * Creates a parser.
     *
     * @param jsonParser JSON-P parser to decorate.
     */
    public JsonbRiParser(JsonParser jsonParser) {
        this.jsonParser = jsonParser;
    }

    @Override
    public boolean hasNext() {
        return  jsonParser.hasNext();
    }

    @Override
    public long getLong() {
        return jsonParser.getLong();
    }

    @Override
    public int getInt() {
        return jsonParser.getInt();
    }

    @Override
    public JsonParser.Event next() {
        final JsonParser.Event next = jsonParser.next();
        final boolean rootLevel = level.empty();
        if (rootLevel) {
            root.setLastEvent(next);
        } else {
            level.peek().setLastEvent(next);
        }
        switch (next) {
            case START_ARRAY:
            case START_OBJECT:
                final LevelContext newLevel = new LevelContext(rootLevel ? root : level.peek());
                newLevel.setLastEvent(next);
                level.push(newLevel);
                break;
            case END_ARRAY:
            case END_OBJECT:
                level.pop().finish();
                break;
            case KEY_NAME:
                getCurrentLevel().setLastKeyName(jsonParser.getString());
                break;
            default:
                break;
        }
        return next;
    }

    @Override
    public boolean isIntegralNumber() {
        return jsonParser.isIntegralNumber();
    }

    @Override
    public BigDecimal getBigDecimal() {
        return jsonParser.getBigDecimal();
    }

    @Override
    public JsonLocation getLocation() {
        return jsonParser.getLocation();
    }

    @Override
    public void close() {
        jsonParser.close();
    }

    @Override
    public String getString() {
        return jsonParser.getString();
    }

    @Override
    public void moveTo(JsonParser.Event required) {
        if (!level.empty() && level.peek().getLastEvent() == required) {
            return;
        }

        final Event next = next();
        if (next == required) {
            return;
        }

        throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Event " + required + " not found." + getLastDataMsg()));
    }

    @Override
    public Event moveToValue() {
        return moveTo(Event.VALUE_STRING, Event.VALUE_NUMBER, Event.VALUE_FALSE, Event.VALUE_TRUE, Event.VALUE_NULL);
    }

    @Override
    public Event moveToStartStructure() {
        return moveTo(Event.START_OBJECT, Event.START_ARRAY);
    }

    private Event moveTo(Event... events) {
        if (!level.empty() && contains(events, level.peek().getLastEvent())) {
            return level.peek().getLastEvent();
        }

        final Event next = next();
        if (contains(events, next)) {
            return next;
        }

        throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Parser event ["+Arrays.toString(events)+"] not found." + getLastDataMsg()));
    }

    private boolean contains(Event[] events, Event candidate) {
        for (Event event : events) {
            if (event == candidate) {
                return true;
            }
        }
        return false;
    }

    private String getLastDataMsg() {
        StringBuilder builder = new StringBuilder();
        final LevelContext currentLevel = getCurrentLevel();
        builder.append(" Last data: [").append("EVENT: ").append(currentLevel.getLastEvent()).append(" KEY_NAME: ")
                .append(currentLevel.getLastKeyName()).append("]");
        return builder.toString();
    }

    @Override
    public LevelContext getCurrentLevel() {
        if (level.empty()) {
            return root;
        }
        return level.peek();
    }

    @Override
    public void skipJsonStructure() {
        final LevelContext currentLevel = level.peek();
        switch (currentLevel.getLastEvent()) {
            case START_ARRAY:
            case START_OBJECT:
                while (!currentLevel.isParsed()) {
                    next();
                }
                return;
            default:
                return;
        }
    }

    @Override
    public JsonObject getObject() {
        JsonObject object = jsonParser.getObject();
        level.pop();
        return object;
    }

    @Override
    public JsonValue getValue() {
        return jsonParser.getValue();
    }

    @Override
    public JsonArray getArray() {
        JsonArray result = jsonParser.getArray();
        level.pop();
        return result;
    }

    @Override
    public Stream getArrayStream() {
        return jsonParser.getArrayStream();
    }

    @Override
    public Stream> getObjectStream() {
        return jsonParser.getObjectStream();
    }

    @Override
    public Stream getValueStream() {
        return jsonParser.getValueStream();
    }

    @Override
    public void skipArray() {
        jsonParser.skipArray();
        level.pop();
    }

    @Override
    public void skipObject() {
        jsonParser.skipObject();
        level.pop();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy