Skip to content

Commit

Permalink
Address concerns provided in the PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
vietj committed Aug 31, 2017
1 parent 52bdf0f commit ec296c7
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 33 deletions.
58 changes: 43 additions & 15 deletions src/main/asciidoc/java/parsetools.adoc
Expand Up @@ -51,7 +51,7 @@ For more details, check out the `link:../../apidocs/io/vertx/core/parsetools/Rec


== Json Parser == Json Parser


You can easily parse JSON structures but that requires to provide the JSON string at once, but it You can easily parse JSON structures but that requires to provide the JSON content at once, but it
may not be convenient when you need to parse very large structures. may not be convenient when you need to parse very large structures.


The non-blocking JSON parser is an event driven parser able to deal with very large structures. The non-blocking JSON parser is an event driven parser able to deal with very large structures.
Expand All @@ -78,7 +78,7 @@ parser.handler(event -> {
break; break;
case VALUE: case VALUE:
// Handle a value // Handle a value
String field = event.field(); String field = event.fieldName();
if (field != null) { if (field != null) {
// In an object // In an object
} else { } else {
Expand All @@ -94,7 +94,7 @@ parser.handler(event -> {
}); });
---- ----


The parser is non-blocking and emitted events are driven by the input buffers The parser is non-blocking and emitted events are driven by the input buffers.


[source, java] [source, java]
---- ----
Expand Down Expand Up @@ -122,8 +122,8 @@ parser.handle(Buffer.buffer("]"));
parser.end(); parser.end();
---- ----


Event driven parsing provides more control but comes at the price of flexibility. The parser allows you Event driven parsing provides more control but comes at the price of dealing with fine grained events, which can be
to handle JSON structures as values when it is desired: inconvenient sometimes. The JSON parser allows you to handle JSON structures as values when it is desired:


[source, java] [source, java]
---- ----
Expand All @@ -150,7 +150,7 @@ parser.end();
---- ----


The value mode can be set and unset during the parsing allowing you to switch between fine grained The value mode can be set and unset during the parsing allowing you to switch between fine grained
events or JSON object/array value events. events or JSON object value events.


[source, java] [source, java]
---- ----
Expand All @@ -167,7 +167,7 @@ parser.handler(event -> {
case VALUE: case VALUE:
// Handle each object // Handle each object
// Get the field in which this object was parsed // Get the field in which this object was parsed
String id = event.field(); String id = event.fieldName();
System.out.println("User with id " + id + " : " + event.value()); System.out.println("User with id " + id + " : " + event.value());
break; break;
case END_OBJECT: case END_OBJECT:
Expand All @@ -181,15 +181,45 @@ parser.handle(Buffer.buffer("{\"39877483847\":{\"firstName\":\"Bob\"},\"lastName
parser.end(); parser.end();
---- ----


You can do the same with arrays as well

[source, java]
----
JsonParser parser = JsonParser.newParser();
parser.handler(event -> {
// Start the object
switch (event.type()) {
case START_OBJECT:
// Set array value mode to handle each entry, from now on the parser won't emit start array events
parser.arrayValueMode();
break;
case VALUE:
// Handle each array
// Get the field in which this object was parsed
System.out.println("Value : " + event.value());
break;
case END_OBJECT:
// Set the array event mode so the parser emits start/end object events again
parser.arrayEventMode();
break;
}
});
parser.handle(Buffer.buffer("[0,1,2,3,4,...]"));
parser.end();
----

You can also decode POJOs You can also decode POJOs


[source, java] [source, java]
---- ----
parser.handler(event -> { parser.handler(event -> {
// Handle each object // Handle each object
// Get the field in which this object was parsed // Get the field in which this object was parsed
String id = event.field(); String id = event.fieldName();
User user = event.as(User.class); User user = event.mapTo(User.class);
System.out.println("User with id " + id + " : " + user.firstName + " " + user.lastName); System.out.println("User with id " + id + " : " + user.firstName + " " + user.lastName);
}); });
---- ----
Expand All @@ -198,12 +228,10 @@ Whenever the parser fails to process a buffer, an exception will be thrown unles


[source, java] [source, java]
---- ----
parser.handler(event -> { JsonParser parser = JsonParser.newParser();
// Handle each object
// Get the field in which this object was parsed parser.exceptionHandler(err -> {
String id = event.field(); // Catch any parsing or decoding error
User user = event.as(User.class);
System.out.println("User with id " + id + " : " + user.firstName + " " + user.lastName);
}); });
---- ----


Expand Down
32 changes: 30 additions & 2 deletions src/main/java/examples/ParseToolsExamples.java
Expand Up @@ -143,12 +143,40 @@ public void jsonParserExample4() {
parser.end(); parser.end();
} }


public void jsonParserExample5() {

JsonParser parser = JsonParser.newParser();

parser.handler(event -> {
// Start the object

switch (event.type()) {
case START_OBJECT:
// Set array value mode to handle each entry, from now on the parser won't emit start array events
parser.arrayValueMode();
break;
case VALUE:
// Handle each array
// Get the field in which this object was parsed
System.out.println("Value : " + event.value());
break;
case END_OBJECT:
// Set the array event mode so the parser emits start/end object events again
parser.arrayEventMode();
break;
}
});

parser.handle(Buffer.buffer("[0,1,2,3,4,...]"));
parser.end();
}

private static class User { private static class User {
private String firstName; private String firstName;
private String lastName; private String lastName;
} }


public void jsonParserExample5(JsonParser parser) { public void jsonParserExample6(JsonParser parser) {
parser.handler(event -> { parser.handler(event -> {
// Handle each object // Handle each object
// Get the field in which this object was parsed // Get the field in which this object was parsed
Expand All @@ -158,7 +186,7 @@ public void jsonParserExample5(JsonParser parser) {
}); });
} }


public void jsonParserExample6() { public void jsonParserExample7() {


JsonParser parser = JsonParser.newParser(); JsonParser parser = JsonParser.newParser();


Expand Down
4 changes: 3 additions & 1 deletion src/main/java/io/vertx/core/parsetools/JsonEvent.java
Expand Up @@ -18,6 +18,7 @@
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.codegen.annotations.VertxGen; import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;


Expand Down Expand Up @@ -107,7 +108,7 @@ public interface JsonEvent {
* @throws java.lang.ClassCastException if the value is not a String * @throws java.lang.ClassCastException if the value is not a String
* @throws java.lang.IllegalArgumentException if the String value is not a legal Base64 encoded value * @throws java.lang.IllegalArgumentException if the String value is not a legal Base64 encoded value
*/ */
byte[] binaryValue(); Buffer binaryValue();


/** /**
* Return the {@code Instant} value. * Return the {@code Instant} value.
Expand All @@ -120,6 +121,7 @@ public interface JsonEvent {
* @throws java.lang.ClassCastException if the value is not a String * @throws java.lang.ClassCastException if the value is not a String
* @throws java.time.format.DateTimeParseException if the String value is not a legal ISO 8601 encoded value * @throws java.time.format.DateTimeParseException if the String value is not a legal ISO 8601 encoded value
*/ */
@GenIgnore
Instant instantValue(); Instant instantValue();


/** /**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/vertx/core/parsetools/JsonEventType.java
Expand Up @@ -38,7 +38,7 @@ public enum JsonEventType {
START_ARRAY, START_ARRAY,


/** /**
* Signals the end of a JSON object. * Signals the end of a JSON array.
*/ */
END_ARRAY, END_ARRAY,


Expand Down
Expand Up @@ -17,6 +17,7 @@


import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.util.TokenBuffer; import com.fasterxml.jackson.databind.util.TokenBuffer;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.DecodeException; import io.vertx.core.json.DecodeException;
import io.vertx.core.json.Json; import io.vertx.core.json.Json;
import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonArray;
Expand Down Expand Up @@ -184,8 +185,8 @@ public String stringValue() {
} }


@Override @Override
public byte[] binaryValue() { public Buffer binaryValue() {
return value != null ? Base64.getDecoder().decode((String) value) : null; return value != null ? Buffer.buffer(Base64.getDecoder().decode((String) value)) : null;
} }


@Override @Override
Expand Down
21 changes: 14 additions & 7 deletions src/main/java/io/vertx/core/parsetools/package-info.java
Expand Up @@ -57,7 +57,7 @@
* *
* == Json Parser * == Json Parser
* *
* You can easily parse JSON structures but that requires to provide the JSON string at once, but it * You can easily parse JSON structures but that requires to provide the JSON content at once, but it
* may not be convenient when you need to parse very large structures. * may not be convenient when you need to parse very large structures.
* *
* The non-blocking JSON parser is an event driven parser able to deal with very large structures. * The non-blocking JSON parser is an event driven parser able to deal with very large structures.
Expand All @@ -68,41 +68,48 @@
* {@link examples.ParseToolsExamples#jsonParserExample1()} * {@link examples.ParseToolsExamples#jsonParserExample1()}
* ---- * ----
* *
* The parser is non-blocking and emitted events are driven by the input buffers * The parser is non-blocking and emitted events are driven by the input buffers.
* *
* [source, $lang] * [source, $lang]
* ---- * ----
* {@link examples.ParseToolsExamples#jsonParserExample2} * {@link examples.ParseToolsExamples#jsonParserExample2}
* ---- * ----
* *
* Event driven parsing provides more control but comes at the price of flexibility. The parser allows you * Event driven parsing provides more control but comes at the price of dealing with fine grained events, which can be
* to handle JSON structures as values when it is desired: * inconvenient sometimes. The JSON parser allows you to handle JSON structures as values when it is desired:
* *
* [source, $lang] * [source, $lang]
* ---- * ----
* {@link examples.ParseToolsExamples#jsonParserExample3} * {@link examples.ParseToolsExamples#jsonParserExample3}
* ---- * ----
* *
* The value mode can be set and unset during the parsing allowing you to switch between fine grained * The value mode can be set and unset during the parsing allowing you to switch between fine grained
* events or JSON object/array value events. * events or JSON object value events.
* *
* [source, $lang] * [source, $lang]
* ---- * ----
* {@link examples.ParseToolsExamples#jsonParserExample4} * {@link examples.ParseToolsExamples#jsonParserExample4}
* ---- * ----
* *
* You can also decode POJOs * You can do the same with arrays as well
* *
* [source, $lang] * [source, $lang]
* ---- * ----
* {@link examples.ParseToolsExamples#jsonParserExample5} * {@link examples.ParseToolsExamples#jsonParserExample5}
* ---- * ----
* *
* You can also decode POJOs
*
* [source, $lang]
* ----
* {@link examples.ParseToolsExamples#jsonParserExample6}
* ----
*
* Whenever the parser fails to process a buffer, an exception will be thrown unless you set an exception handler: * Whenever the parser fails to process a buffer, an exception will be thrown unless you set an exception handler:
* *
* [source, $lang] * [source, $lang]
* ---- * ----
* {@link examples.ParseToolsExamples#jsonParserExample5} * {@link examples.ParseToolsExamples#jsonParserExample7}
* ---- * ----
* *
* For more details, check out the {@link io.vertx.core.parsetools.JsonParser} class. * For more details, check out the {@link io.vertx.core.parsetools.JsonParser} class.
Expand Down
22 changes: 17 additions & 5 deletions src/test/java/io/vertx/test/core/JsonParserTest.java
Expand Up @@ -150,9 +150,15 @@ public void testParseObjectValue() {
parser.handler(event -> { parser.handler(event -> {
assertEquals(0, status.getAndIncrement()); assertEquals(0, status.getAndIncrement());
assertEquals(JsonEventType.VALUE, event.type()); assertEquals(JsonEventType.VALUE, event.type());
assertEquals(new JsonObject().put("number", 3).put("true", true).put("false", false).put("string", "s").putNull("null"), event.value()); assertEquals(new JsonObject().put("number", 3)
.put("true", true)
.put("false", false)
.put("string", "s")
.put("object", new JsonObject().put("foo", "bar"))
.put("array", new JsonArray().add(0).add(1).add(2))
.putNull("null"), event.value());
}); });
parser.handle(Buffer.buffer("{\"number\":3,\"true\":true,\"false\":false,\"string\":\"s\",\"null\":null}")); parser.handle(Buffer.buffer("{\"number\":3,\"true\":true,\"false\":false,\"string\":\"s\",\"null\":null,\"object\":{\"foo\":\"bar\"},\"array\":[0,1,2]}"));
assertEquals(1, status.get()); assertEquals(1, status.get());
} }


Expand All @@ -162,10 +168,16 @@ public void testParseArrayValue() {
AtomicInteger status = new AtomicInteger(); AtomicInteger status = new AtomicInteger();
parser.arrayValueMode(); parser.arrayValueMode();
parser.handler(event -> { parser.handler(event -> {
assertEquals(new JsonArray().add(1).add(2).add(3), event.value()); assertEquals(new JsonArray().add(3)
.add(true)
.add(false)
.add("s")
.addNull()
.add(new JsonObject().put("foo", "bar"))
.add(new JsonArray().add(0).add(1).add(2)), event.value());
assertEquals(0, status.getAndIncrement()); assertEquals(0, status.getAndIncrement());
}); });
parser.handle(Buffer.buffer("[1,2,3]")); parser.handle(Buffer.buffer("[3,true,false,\"s\",null,{\"foo\":\"bar\"},[0,1,2]]"));
assertEquals(1, status.get()); assertEquals(1, status.get());
} }


Expand Down Expand Up @@ -246,7 +258,7 @@ public void testBinaryValue() {
assertFalse(event.isBoolean()); assertFalse(event.isBoolean());
assertTrue(event.isString()); assertTrue(event.isString());
assertEquals(encoded, event.stringValue()); assertEquals(encoded, event.stringValue());
assertTrue(Arrays.equals(value, event.binaryValue())); assertEquals(Buffer.buffer(value), event.binaryValue());
assertThrowCCE(event, assertThrowCCE(event,
JsonEvent::integerValue, JsonEvent::integerValue,
JsonEvent::longValue, JsonEvent::longValue,
Expand Down

0 comments on commit ec296c7

Please sign in to comment.