Skip to content

Commit

Permalink
Add support for processing big JSON.
Browse files Browse the repository at this point in the history
  • Loading branch information
kinmanc committed May 5, 2015
1 parent 7362ba3 commit c70cfaa
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 144 deletions.
153 changes: 141 additions & 12 deletions api/src/main/java/javax/json/stream/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@

import java.io.Closeable;
import java.math.BigDecimal;
import java.util.stream.Stream;
import java.util.Map;

import javax.json.JsonValue;
import javax.json.JsonObject;
import javax.json.JsonArray;

/**
* Provides forward, read-only access to JSON data in a streaming way. This
* is the most efficient way for reading JSON data. The class
* is the most efficient way for reading JSON data.
* This is the only way to JSON data that are too big to be loaded in memory.
* <p>The class
* {@link javax.json.Json} contains methods to create parsers from input
* sources ({@link java.io.InputStream} and {@link java.io.Reader}).
*
Expand Down Expand Up @@ -120,7 +128,7 @@
* }<B>END_OBJECT</B>
* </pre>
*
* The methods {@code next()} and {@code hasNext()} enable iteration over
* The methods {@link #next()} and {@link #hasNext()} enable iteration over
* parser events to process JSON data. {@code JsonParser} provides get methods
* to obtain the value at the current state of the parser. For example, the
* following code shows how to obtain the value "John" from the JSON above:
Expand All @@ -134,6 +142,41 @@
* </code>
* </pre>
*
* The methods {@link #getArray} and {@link #getObject} can be used to read in
* a {@code JsonArray} or {@code JsonObject}. For example, the following code
* shows how to obtain the phoneNumber in a JsonArray, from the JSON above:
*
* <pre><code>
* while (parser.hasNext() {
* Event event = parser.next();
* if (event == JsonParser.Event.KEY_NAME ) {
* String key = getString();
* event = parser.next();
* if (key.equals("phoneNumber") {
* JsonArray phones = parser.getArray();
* }
* }
* }
* </code></pre>
*
* The methods {@link #getArrayStream} and {@link #getObjectStream} can be used
* to get a stream of the elements of a {@code JsonArray} or {@code JsonObject}.
* For example, the following code shows another way to obtain John's phoneNumber
* in a {@code JsonArray} :
*
* <pre>{@code
* Event event = parser.next(); // START)OBJECT
* JsonArray phones = (JsonArray)
* parser.getObjectStream.filter(e->getKey().equals("phoneNumber"))
* .map(e->e.getValue())
* .findFirst()
* .get();
* }</pre>
*
* The methods {@link #skipArray} and {@link #skipObject} can be used to
* skip tokens and position the parser to {@code END_ARRAY} or
* {@code END_OBJECT}.
*
* @see javax.json.Json
* @see JsonParserFactory
*/
Expand Down Expand Up @@ -313,22 +356,109 @@ enum Event {
JsonLocation getLocation();

/**
* getJsonValue(JsonObject.class) is valid in the START_OBJECT state and
* moves the cursor to END_OBJECT.
* Returns a {@code JsonObject} and advances the parser to the
* corresponding {@code END_OBJECT}.
*
* @return the {@code JsonObject} at the current parser position
*
* @throws IllegalStateException when the parser state is not
* {@code START_OBJECT}
* @since 1.1
*/
default public JsonObject getObject() {
throw new UnsupportedOperationException();
}

/**
* Returns a {@code JsonValue} at the current parser position.
* If the parser state is {@code START_ARRAY}, the behavior is
* the same as {@link #getArray}. If the parser state is
* {@code START_OBJECT}, the behavior is the same as
* {@link #getObject}. For all other cases, the value is
* read and returned, and the parser position is not advanced.
*
* @return the {@code JsonValue} at the current parser position.
*
* @since 1.1
*/
default public JsonValue getValue() {
throw new UnsupportedOperationException();
}

/**
* Returns a {@code JsonArray} and advance the parser to the
* the corresponding {@code END_ARRAY}.
*
* getJsonValue(JsonArray.class) is valid in the START_ARRAY state
* and moves the cursor to END_ARRAY.
* @return the {@code JsonArray} at the current parser position
*
* getJsonValue(JsonString.class) is valid in the VALUE_STRING state.
* @throws IllegalStateException when the parser state is not
* {@code START_ARRAY}
* @since 1.1
*/
default public JsonArray getArray() {
throw new UnsupportedOperationException();
}

/**
* Returns a stream of the {@code JsonArray} elements.
* The parser state must be {@code START_ARRAY}.
* The elements are read lazily, on a as-needed basis, as
* required by the stream operations.
* If the stream operations do not consume
* all of the array elements, {@link skipArray} can be used to
* skip the unprocessed array elements.
*
* getJsonValue(JsonNumber.class) is valid in the VALUE_NUMBER state.
* @return a stream of elements of the {@code JsonArray}
*
* @throws IllegalStateException when the parser state is not
* {@code START_ARRAY}
*/
default public Stream<JsonValue> getArrayStream() {
throw new UnsupportedOperationException();
}

/**
* Returns a stream of the {@code JsonObject}'s
* name/value pairs. The parser state must be {@code START_OBJECT}.
* The name/value paris are read lazily, on a as-needed basis, as
* required by the stream operations.
* If the stream operations do not consume
* all of the object's name/value pairs, {@link skipObject} can be
* used to skip the unprocessed elements.
*
* @param clazz
* @return
* @return a stream of name/value paris of the {@code JsonObject}
*
public <T extends JsonValue> T getJsonValue(Class<T> clazz);
* @throws IllegalStateException when the parser state is not
* {@code START_OBJECT}
*/
default public Stream<Map.Entry<String,JsonValue>> getObjectStream() {
throw new UnsupportedOperationException();
}

/**
* Advance the parser to {@code END_ARRAY}.
* If the parser is in array context, i.e. it has previously
* encountered a {@code START_ARRAY} without encountereing the
* corresponding {@code END_ARRAY}, the parser is advanced to
* the corresponding {@code END_ARRAY}.
* If the parser is not in any array context, nothing happens.
*/
default public void skipArray() {
throw new UnsupportedOperationException();
}

/**
* Advance the parser to {@code END_OBJECT}.
* If the parser is in object context, i.e. it has previously
* encountered a {@code START_OBJECT} without encountereing the
* corresponding {@code END_OBJECT}, the parser is advanced to
* the corresponding {@code END_OBJECT}.
* If the parser is not in any object context, nothing happens.
*/
default public void skipObject() {
throw new UnsupportedOperationException();
}

/**
* Closes this parser and frees any resources associated with the
* parser. This method closes the underlying input source.
Expand All @@ -338,5 +468,4 @@ enum Event {
*/
@Override
void close();

}
16 changes: 8 additions & 8 deletions impl/src/main/java/org/glassfish/json/JsonMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ static String PARSER_GETBIGDECIMAL_ERR(JsonParser.Event event) {
return localize("parser.getBigDecimal.err", event);
}

static String PARSER_GETARRAY_ERR(JsonParser.Event event) {
return localize("parser.getArray.err", event);
}

static String PARSER_GETOBJECT_ERR(JsonParser.Event event) {
return localize("parser.getObject.err", event);
}

static String PARSER_EXPECTED_EOF(JsonTokenizer.JsonToken token) {
return localize("parser.expected.eof", token);
}
Expand Down Expand Up @@ -145,14 +153,6 @@ static String READER_READ_ALREADY_CALLED() {
return localize("reader.read.already.called");
}

static String READER_EXPECTED_ARRAY_GOT_OBJECT() {
return localize("reader.expected.array.got.object");
}

static String READER_EXPECTED_OBJECT_GOT_ARRAY() {
return localize("reader.expected.object.got.array");
}


// obj builder messages
static String OBJBUILDER_NAME_NULL() {
Expand Down

0 comments on commit c70cfaa

Please sign in to comment.