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

oracle.nosql.driver.values.JsonReader Maven / Gradle / Ivy

There is a newer version: 5.4.16
Show newest version
/*-
 * Copyright (c) 2011, 2020 Oracle and/or its affiliates.  All rights reserved.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 *  https://oss.oracle.com/licenses/upl/
 */

package oracle.nosql.driver.values;

import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.util.Iterator;

import oracle.nosql.driver.JsonParseException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.io.JsonEOFException;

/**
 * JsonReader reads a file or string that has JSON objects in it that may
 * represent rows and makes them available using the Iterable interface. The
 * source of the JSON, either a File or String, is expected to contain one or
 * more JSON objects, separated by white, or no space. While white space, or no
 * space between objects is explicitly supported, the JSON parser is flexible
 * and forgiving and will silently ignore and skip unexpected characters
 * between JSON objects.
 * 

* As an iteration proceeds it may return any number of valid MapValue * instances before it encounters a problem in the input stream such as a bad * object or unexpected end of file. It is up to the application to handle * error conditions. There is no mechanism for restarting in the middle of * a file or string. If a {@link JsonParseException} is thrown it will * contain the location of the exception in the parse stream to help isolate * problems. *

* An instance of this class can only be used to create a single iterator. * This is to ensure that the Iterator can be closed explicitly by the * caller. If an attempt is made to create an additional iterator * IllegalArgumentException is thrown. *

* Instances of this class must be closed when done to free parser resources. * It implements AutoCloseable to assist but in the event it is not called * inside a try-with-resources block an explicit close() should be used. */ public class JsonReader implements Iterable, AutoCloseable { private final MapValueJsonIterator iterator; private boolean iteratorUsed; /** * Creates an iterator over JSON objects in the specified file. * * @param file the file to be used * @param options if desired, this can be null */ public JsonReader(File file, JsonOptions options) { iterator = new MapValueJsonIterator(file, options); } /** * Creates an iterator over JSON objects in a string. * * @param jsonString the String to use * @param options if desired, this can be null */ public JsonReader(String jsonString, JsonOptions options) { iterator = new MapValueJsonIterator(jsonString, options); } /** * Creates an iterator over JSON objects provided by the * InputStream. The caller is responsible for closing the InputStream * if necessary. * * @param input the InputStream to use * @param options if desired, this can be null */ public JsonReader(InputStream input, JsonOptions options) { iterator = new MapValueJsonIterator(input, options); } /** * Returns an Iterator<MapValue> over the source provided. * This method can only be called once for a given instance of JsonReader. * An additional call will result in IllegalArgumentException being thrown. * * @throws IllegalArgumentException if called twice */ @Override public Iterator iterator() { if (iteratorUsed) { throw new IllegalArgumentException( "JsonReader can only create one iterator instance. If " + "another is needed, create a new instance of JsonReader"); } iteratorUsed = true; return iterator; } @Override public void close() { iterator.close(); } static class MapValueJsonIterator implements Iterator, AutoCloseable { final JsonParser parser; private final JsonOptions options; boolean closed = false; public MapValueJsonIterator(File file, JsonOptions options) { this.options = options; parser = JsonUtils.createParserWithOptions(file, options); } public MapValueJsonIterator(String json, JsonOptions options) { this.options = options; parser = JsonUtils.createParserWithOptions(json, options); } public MapValueJsonIterator(InputStream input, JsonOptions options) { this.options = options; parser = JsonUtils.createParserWithOptions(input, options); } @Override public boolean hasNext() { if (closed) { return false; } if (parser.currentToken() == JsonToken.START_OBJECT) { return true; } while(true) { try { JsonToken token = parser.nextToken(); if (token == null) { return false; } if (token == JsonToken.START_OBJECT) { return true; } } catch (JsonEOFException eof) { return false; } catch (IOException ignored) { /* Ignore parsing error, find next START_OBJECT */ } } } @Override public MapValue next() { if (hasNext()) { return makeValue(); } close(); return null; } @Override public void close() { if (!closed) { closed = true; try { parser.close(); } catch (IOException ioe) {} } } private MapValue makeValue() { FieldValue value = JsonUtils.createValueFromJson(parser, false, options); if (!(value instanceof MapValue)) { throw new IllegalArgumentException( "Invalid JSON encountered in input. Input stream must " + "contain only complete objects"); } return (MapValue) value; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy