You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/01/26 01:32:58 UTC
[juneau] branch master updated: Add support for parsing continuous
streams.
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 1687de4 Add support for parsing continuous streams.
1687de4 is described below
commit 1687de48602c3fde1c8fdcd8aa8f77b0c26a670e
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Jan 25 20:32:56 2018 -0500
Add support for parsing continuous streams.
---
.../juneau/CloseableByteArrayInputStream.java | 38 ++++++
.../org/apache/juneau/CloseableStringReader.java | 45 +++++++
.../java/org/apache/juneau/ParserReaderTest.java | 2 +-
.../src/test/java/org/apache/juneau/TestUtils.java | 7 --
.../org/apache/juneau/json/JsonParserTest.java | 51 ++++++++
.../apache/juneau/msgpack/MsgPackParserTest.java | 137 +++++++++++++++++++++
...ialzierTest.java => MsgPackSerializerTest.java} | 5 +-
.../{urlencoding => uon}/CommonParser_UonTest.java | 3 +-
.../{urlencoding => uon}/Common_UonTest.java | 12 +-
.../{urlencoding => uon}/UonParserReaderTest.java | 3 +-
.../juneau/{urlencoding => uon}/UonParserTest.java | 54 +++++++-
.../{urlencoding => uon}/UonSerializerTest.java | 3 +-
.../org/apache/juneau/jena/RdfParserBuilder.java | 24 ++++
.../org/apache/juneau/csv/CsvParserBuilder.java | 24 ++++
.../org/apache/juneau/jso/JsoParserBuilder.java | 24 ++++
.../java/org/apache/juneau/json/JsonParser.java | 53 +++++++-
.../org/apache/juneau/json/JsonParserBuilder.java | 64 ++++++++++
.../org/apache/juneau/json/JsonParserSession.java | 9 ++
.../juneau/msgpack/MsgPackParserBuilder.java | 24 ++++
.../main/java/org/apache/juneau/parser/Parser.java | 115 ++++++++++++++++-
.../org/apache/juneau/parser/ParserBuilder.java | 75 +++++++++++
.../apache/juneau/parser/ParserGroupBuilder.java | 74 +++++++++++
.../java/org/apache/juneau/parser/ParserPipe.java | 33 +++--
.../org/apache/juneau/parser/ParserReader.java | 12 +-
.../org/apache/juneau/parser/ParserSession.java | 6 +-
.../juneau/plaintext/PlainTextParserBuilder.java | 24 ++++
.../main/java/org/apache/juneau/uon/UonParser.java | 44 ++++++-
.../org/apache/juneau/uon/UonParserBuilder.java | 62 ++++++++++
.../org/apache/juneau/uon/UonParserSession.java | 6 +-
.../org/apache/juneau/xml/XmlParserBuilder.java | 24 ++++
.../juneau/yaml/proto/YamlParserBuilder.java | 24 ++++
juneau-doc/src/main/javadoc/overview.html | 75 +++++++++--
.../juneau/rest/client/RestClientBuilder.java | 73 +++++++++++
.../java/org/apache/juneau/rest/RestUtils.java | 2 +-
34 files changed, 1182 insertions(+), 49 deletions(-)
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/CloseableByteArrayInputStream.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/CloseableByteArrayInputStream.java
new file mode 100644
index 0000000..46ddce8
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/CloseableByteArrayInputStream.java
@@ -0,0 +1,38 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau;
+
+import java.io.*;
+
+/**
+ * A ByteArrayInputStream with a usable close() method.
+ */
+public class CloseableByteArrayInputStream extends ByteArrayInputStream {
+ boolean isClosed;
+
+ public CloseableByteArrayInputStream(byte[] buf) {
+ super(buf);
+ }
+
+ @Override
+ public int read() {
+ if (isClosed)
+ throw new RuntimeException("Stream is closed");
+ return super.read();
+ }
+
+ @Override
+ public void close() {
+ isClosed = true;
+ }
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/CloseableStringReader.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/CloseableStringReader.java
new file mode 100644
index 0000000..79a5480
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/CloseableStringReader.java
@@ -0,0 +1,45 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau;
+
+import java.io.*;
+
+/**
+ * A StringReader with a usable close() method.
+ */
+public class CloseableStringReader extends StringReader {
+ boolean isClosed;
+
+ public CloseableStringReader(String in) {
+ super(in);
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (isClosed)
+ throw new RuntimeException("Reader is closed");
+ return super.read();
+ }
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ if (isClosed)
+ throw new RuntimeException("Reader is closed");
+ return super.read(cbuf, off, len);
+ }
+
+ @Override
+ public void close() {
+ isClosed = true;
+ }
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ParserReaderTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ParserReaderTest.java
index 49a8918..cfd23c0 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ParserReaderTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ParserReaderTest.java
@@ -181,6 +181,6 @@ public class ParserReaderTest {
}
private ParserReader createParserReader(Object in) throws Exception {
- return new ParserReader(new ParserPipe(in, false, false, null, null));
+ return new ParserReader(new ParserPipe(in, false, false, false, false, null, null));
}
}
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/TestUtils.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/TestUtils.java
index 5254707..899b687 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/TestUtils.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/TestUtils.java
@@ -426,13 +426,6 @@ public class TestUtils {
return sb.toString();
}
- public static String toReadableBytes2(byte[] b) {
- StringBuilder sb = new StringBuilder();
- for (byte b2 : b)
- sb.append(String.format("%02X ", b2));
- return sb.toString().trim();
- }
-
/**
* Tries to turn the serialized output to a String.
* If it's a byte[], convert it to a UTF-8 encoded String.
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java
index fc61db3..03dfd09 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java
@@ -12,8 +12,11 @@
// ***************************************************************************************************************************
package org.apache.juneau.json;
+import static org.apache.juneau.TestUtils.*;
import static org.junit.Assert.*;
+import java.io.*;
+
import org.apache.juneau.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.serializer.*;
@@ -322,4 +325,52 @@ public class JsonParserTest {
return "f="+f;
}
}
+
+ //====================================================================================================
+ // testStreamsAutoClose
+ // Validates PARSER_autoCloseStreams.
+ //====================================================================================================
+ @Test
+ public void testStreamsAutoClose() throws Exception {
+ ReaderParser p = JsonParser.DEFAULT.builder().autoCloseStreams().build();
+ Object x;
+ Reader r;
+
+ r = reader("{foo:'bar'}{baz:'qux'}");
+ x = p.parse(r, ObjectMap.class);
+ assertObjectEquals("{foo:'bar'}", x);
+ try {
+ x = p.parse(r, ObjectMap.class);
+ fail("Exception expected");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Reader is closed"));
+ }
+ }
+
+ //====================================================================================================
+ // testMultipleObjectsInStream
+ // Validates that readers are not closed so that we can read streams of POJOs.
+ //====================================================================================================
+ @Test
+ public void testMultipleObjectsInStream() throws Exception {
+ ReaderParser p = JsonParser.create().unbuffered().build();
+ Object x;
+ Reader r;
+
+ r = reader("{foo:'bar'}{baz:'qux'}");
+ x = p.parse(r, ObjectMap.class);
+ assertObjectEquals("{foo:'bar'}", x);
+ x = p.parse(r, ObjectMap.class);
+ assertObjectEquals("{baz:'qux'}", x);
+
+ r = reader("[123][456]");
+ x = p.parse(r, ObjectList.class);
+ assertObjectEquals("[123]", x);
+ x = p.parse(r, ObjectList.class);
+ assertObjectEquals("[456]", x);
+ }
+
+ private Reader reader(String in) {
+ return new CloseableStringReader(in);
+ }
}
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackParserTest.java
new file mode 100644
index 0000000..9cfdf28
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackParserTest.java
@@ -0,0 +1,137 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.msgpack;
+
+import static org.apache.juneau.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.io.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.junit.*;
+
+/**
+ * Tests the {@link MsgPackParser} class.
+ */
+public class MsgPackParserTest {
+
+ //====================================================================================================
+ // testStreamsAutoClose
+ // Validates PARSER_autoCloseStreams.
+ //====================================================================================================
+ @Test
+ public void testStreamsAutoClose() throws Exception {
+ InputStreamParser p = MsgPackParser.DEFAULT.builder().autoCloseStreams().build();
+ Object r;
+ InputStream is;
+
+ is = is("00 01");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("0", r);
+ try {
+ r = p.parse(is, Object.class);
+ fail("Exception expected");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Stream is closed"));
+ }
+ }
+
+ //====================================================================================================
+ // testMultipleObjectsInStream
+ // Validates that input streams are not closed so that we can read streams of POJOs.
+ //====================================================================================================
+ @Test
+ public void testMultipleObjectsInStream() throws Exception {
+ InputStreamParser p = MsgPackParser.DEFAULT;
+ Object r;
+ InputStream is;
+
+ is = is("00 01");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("0", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("1", r);
+
+ is = is("D1 00 80 D1 00 81");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("128", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("129", r);
+
+ is = is("D2 00 00 80 00 D2 00 00 80 01");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("32768", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("32769", r);
+
+ is = is("CA 00 00 00 00 CA 3F 80 00 00");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("0.0", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("1.0", r);
+
+ is = is("CB 3F F0 00 00 00 00 00 00 CB BF F0 00 00 00 00 00 00");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("1.0", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("-1.0", r);
+
+ is = is("A0 A0");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("''", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("''", r);
+
+ is = is("BF 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 BF 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", r);
+
+ is = is("D9 20 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 D9 20 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", r);
+
+ is = is("90 90");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("[]", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("[]", r);
+
+ is = is("91 01 91 02");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("[1]", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("[2]", r);
+
+ is = is("80 80");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("{}", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("{}", r);
+
+ is = is("81 A1 31 01 81 A1 31 02");
+ r = p.parse(is, Object.class);
+ assertObjectEquals("{'1':1}", r);
+ r = p.parse(is, Object.class);
+ assertObjectEquals("{'1':2}", r);
+ }
+
+ private InputStream is(String spacedHex) throws Exception {
+ return new CloseableByteArrayInputStream(StringUtils.fromSpacedHex(spacedHex));
+ }
+}
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackSerialzierTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackSerializerTest.java
similarity index 96%
rename from juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackSerialzierTest.java
rename to juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackSerializerTest.java
index 450d7ee..030bb03 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackSerialzierTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/msgpack/MsgPackSerializerTest.java
@@ -15,10 +15,11 @@ package org.apache.juneau.msgpack;
import static org.junit.Assert.*;
import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
import org.junit.*;
@SuppressWarnings({"javadoc"})
-public class MsgPackSerialzierTest {
+public class MsgPackSerializerTest {
//====================================================================================================
// testBasic
@@ -210,6 +211,6 @@ public class MsgPackSerialzierTest {
private void test(Object input, String expected) throws Exception {
byte[] b = MsgPackSerializer.DEFAULT.serialize(input);
- assertEquals(expected, TestUtils.toReadableBytes2(b));
+ assertEquals(expected, StringUtils.toSpacedHex(b));
}
}
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/CommonParser_UonTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/CommonParser_UonTest.java
similarity index 96%
rename from juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/CommonParser_UonTest.java
rename to juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/CommonParser_UonTest.java
index 05c99d0..4dc26e7 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/CommonParser_UonTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/CommonParser_UonTest.java
@@ -10,7 +10,7 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
-package org.apache.juneau.urlencoding;
+package org.apache.juneau.uon;
import static org.junit.Assert.*;
@@ -19,7 +19,6 @@ import java.util.*;
import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.parser.*;
-import org.apache.juneau.uon.*;
import org.junit.*;
@SuppressWarnings({"rawtypes","serial","javadoc"})
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/Common_UonTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/Common_UonTest.java
similarity index 93%
rename from juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/Common_UonTest.java
rename to juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/Common_UonTest.java
index 1a228d9..f44778d 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/Common_UonTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/Common_UonTest.java
@@ -10,10 +10,11 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
-package org.apache.juneau.urlencoding;
+package org.apache.juneau.uon;
import static org.apache.juneau.TestUtils.*;
import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
import java.net.*;
import java.net.URI;
@@ -21,7 +22,6 @@ import java.util.*;
import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
-import org.apache.juneau.uon.*;
import org.apache.juneau.utils.*;
import org.junit.*;
@@ -277,10 +277,10 @@ public class Common_UonTest {
fail("Exception expected!");
} catch (Exception e) {
String msg = e.getLocalizedMessage();
- assertTrue(msg.contains("[0]root:org.apache.juneau.urlencoding.Common_UonTest$R1"));
- assertTrue(msg.contains("->[1]r2:org.apache.juneau.urlencoding.Common_UonTest$R2"));
- assertTrue(msg.contains("->[2]r3:org.apache.juneau.urlencoding.Common_UonTest$R3"));
- assertTrue(msg.contains("->[3]r1:org.apache.juneau.urlencoding.Common_UonTest$R1"));
+ assertTrue(msg.contains("[0]root:org.apache.juneau.uon.Common_UonTest$R1"));
+ assertTrue(msg.contains("->[1]r2:org.apache.juneau.uon.Common_UonTest$R2"));
+ assertTrue(msg.contains("->[2]r3:org.apache.juneau.uon.Common_UonTest$R3"));
+ assertTrue(msg.contains("->[3]r1:org.apache.juneau.uon.Common_UonTest$R1"));
}
s.ignoreRecursions();
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonParserReaderTest.java
similarity index 96%
rename from juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java
rename to juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonParserReaderTest.java
index 5e05128..6674a7a 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonParserReaderTest.java
@@ -10,7 +10,7 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
-package org.apache.juneau.urlencoding;
+package org.apache.juneau.uon;
import static org.junit.Assert.*;
@@ -18,7 +18,6 @@ import java.io.*;
import org.apache.juneau.*;
import org.apache.juneau.parser.*;
-import org.apache.juneau.uon.*;
import org.junit.*;
@SuppressWarnings({"javadoc","resource"})
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonParserTest.java
similarity index 87%
rename from juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java
rename to juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonParserTest.java
index 8d91ede..93ecf5a 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonParserTest.java
@@ -10,14 +10,16 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
-package org.apache.juneau.urlencoding;
+package org.apache.juneau.uon;
+import static org.apache.juneau.TestUtils.*;
import static org.junit.Assert.*;
+import java.io.*;
import java.util.*;
+import org.apache.juneau.*;
import org.apache.juneau.parser.*;
-import org.apache.juneau.uon.*;
import org.junit.*;
@SuppressWarnings({"rawtypes","javadoc"})
@@ -511,4 +513,52 @@ public class UonParserTest {
public String f1;
public int f2;
}
+
+ //====================================================================================================
+ // testStreamsAutoClose
+ // Validates PARSER_autoCloseStreams.
+ //====================================================================================================
+ @Test
+ public void testStreamsAutoClose() throws Exception {
+ ReaderParser p = UonParser.DEFAULT.builder().autoCloseStreams().build();
+ Object x;
+ Reader r;
+
+ r = reader("(foo=bar)(foo=bar)");
+ x = p.parse(r, ObjectMap.class);
+ assertObjectEquals("{foo:'bar'}", x);
+ try {
+ x = p.parse(r, ObjectMap.class);
+ fail("Exception expected");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Reader is closed"));
+ }
+ }
+
+ //====================================================================================================
+ // testMultipleObjectsInStream
+ // Validates that readers are not closed so that we can read streams of POJOs.
+ //====================================================================================================
+ @Test
+ public void testMultipleObjectsInStream() throws Exception {
+ ReaderParser p = UonParser.create().unbuffered().build();
+ Object x;
+ Reader r;
+
+ r = reader("(foo=bar)(baz=qux)");
+ x = p.parse(r, ObjectMap.class);
+ assertObjectEquals("{foo:'bar'}", x);
+ x = p.parse(r, ObjectMap.class);
+ assertObjectEquals("{baz:'qux'}", x);
+
+ r = reader("@(123)@(456)");
+ x = p.parse(r, ObjectList.class);
+ assertObjectEquals("[123]", x);
+ x = p.parse(r, ObjectList.class);
+ assertObjectEquals("[456]", x);
+ }
+
+ private Reader reader(String in) {
+ return new CloseableStringReader(in);
+ }
}
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonSerializerTest.java
similarity index 96%
rename from juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java
rename to juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonSerializerTest.java
index bf3bc75..593a27f 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/uon/UonSerializerTest.java
@@ -10,12 +10,11 @@
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
-package org.apache.juneau.urlencoding;
+package org.apache.juneau.uon;
import static org.junit.Assert.*;
import org.apache.juneau.*;
-import org.apache.juneau.uon.*;
import org.junit.*;
@SuppressWarnings("javadoc")
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserBuilder.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserBuilder.java
index 724c381..f3e7f05 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserBuilder.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserBuilder.java
@@ -338,6 +338,18 @@ public class RdfParserBuilder extends ParserBuilder {
}
@Override /* ParserBuilder */
+ public RdfParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public RdfParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public RdfParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -379,6 +391,18 @@ public class RdfParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public RdfParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public RdfParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public RdfParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvParserBuilder.java
index cfbd62c..3e2a396 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvParserBuilder.java
@@ -49,6 +49,18 @@ public class CsvParserBuilder extends ParserBuilder {
//--------------------------------------------------------------------------------
@Override /* ParserBuilder */
+ public CsvParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public CsvParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public CsvParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -90,6 +102,18 @@ public class CsvParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public CsvParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public CsvParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public CsvParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoParserBuilder.java
index 6f026ee..04ee3e6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoParserBuilder.java
@@ -50,6 +50,18 @@ public class JsoParserBuilder extends ParserBuilder {
//--------------------------------------------------------------------------------
@Override /* ParserBuilder */
+ public JsoParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public JsoParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public JsoParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -91,6 +103,18 @@ public class JsoParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public JsoParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public JsoParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public JsoParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java
index ab98319..ca02ea6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java
@@ -103,6 +103,54 @@ import org.apache.juneau.parser.*;
public class JsonParser extends ReaderParser {
//-------------------------------------------------------------------------------------------------------------------
+ // Configurable properties
+ //-------------------------------------------------------------------------------------------------------------------
+
+ private static final String PREFIX = "JsonParser.";
+
+ /**
+ * Configuration property: Validate end.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"JsonParser.validateEnd.b"</js>
+ * <li><b>Data type:</b> <code>Boolean</code>
+ * <li><b>Default:</b> <jk>false</jk>
+ * <li><b>Session-overridable:</b> <jk>true</jk>
+ * <li><b>Methods:</b>
+ * <ul>
+ * <li class='jm'>{@link JsonParserBuilder#validateEnd(boolean)}
+ * <li class='jm'>{@link JsonParserBuilder#validateEnd()}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * If <jk>true</jk>, after parsing a POJO from the input, verifies that the remaining input in
+ * the stream consists of only comments or whitespace.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <jc>// Create a parser that validates that there's no garbage at the end of the input.</jc>
+ * ReaderParser p = JsonParser.
+ * .<jsm>create</jsm>()
+ * .validateEnd()
+ * .build();
+ *
+ * <jc>// Same, but use property.</jc>
+ * ReaderParser p = JsonParser.
+ * .<jsm>create</jsm>()
+ * .set(<jsf>JSON_validateEnd</jsf>, <jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Should fail because input has multiple POJOs.</jc>
+ * String in = <js>"{foo:'bar'}{baz:'qux'}"</js>;
+ * MyBean myBean = p.parse(in, MyBean.<jk>class</jk>);
+ * </p>
+ */
+ public static final String JSON_validateEnd = PREFIX + "validateEnd.b";
+
+ //-------------------------------------------------------------------------------------------------------------------
// Predefined instances
//-------------------------------------------------------------------------------------------------------------------
@@ -126,7 +174,7 @@ public class JsonParser extends ReaderParser {
* @param ps The property store containing all the settings for this object.
*/
public Strict(PropertyStore ps) {
- super(ps.builder().set(PARSER_strict, true).build());
+ super(ps.builder().set(PARSER_strict, true).set(JSON_validateEnd, true).build());
}
}
@@ -135,6 +183,8 @@ public class JsonParser extends ReaderParser {
// Instance
//-------------------------------------------------------------------------------------------------------------------
+ final boolean validateEnd;
+
/**
* Constructor.
*
@@ -152,6 +202,7 @@ public class JsonParser extends ReaderParser {
*/
public JsonParser(PropertyStore ps, String...consumes) {
super(ps, consumes);
+ validateEnd = getProperty(JSON_validateEnd, boolean.class, false);
}
@Override /* Context */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserBuilder.java
index 0c42db6..826b6ef 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserBuilder.java
@@ -12,6 +12,8 @@
// ***************************************************************************************************************************
package org.apache.juneau.json;
+import static org.apache.juneau.json.JsonParser.*;
+
import java.util.*;
import org.apache.juneau.*;
@@ -49,6 +51,56 @@ public class JsonParserBuilder extends ParserBuilder {
// Properties
//--------------------------------------------------------------------------------
+ /**
+ * Configuration property: Validate end.
+ *
+ * <p>
+ * If <jk>true</jk>, after parsing a POJO from the input, verifies that the remaining input in
+ * the stream consists of only comments or whitespace.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link JsonParser#JSON_validateEnd}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public JsonParserBuilder validateEnd(boolean value) {
+ return set(JSON_validateEnd, value);
+ }
+
+ /**
+ * Configuration property: Validate end.
+ *
+ * <p>
+ * Shortcut for calling <code>validateEnd(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link JsonParser#JSON_validateEnd}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public JsonParserBuilder validateEnd() {
+ return set(JSON_validateEnd, true);
+ }
+
+ @Override /* ParserBuilder */
+ public JsonParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public JsonParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
@Override /* ParserBuilder */
public JsonParserBuilder fileCharset(String value) {
super.fileCharset(value);
@@ -91,6 +143,18 @@ public class JsonParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public JsonParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public JsonParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public JsonParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
index 6cf0932..a42b712 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
@@ -13,6 +13,7 @@
package org.apache.juneau.json;
import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.json.JsonParser.*;
import java.io.*;
import java.lang.reflect.*;
@@ -34,6 +35,8 @@ import org.apache.juneau.transform.*;
public final class JsonParserSession extends ReaderParserSession {
private static final AsciiSet decChars = new AsciiSet("0123456789");
+
+ private final boolean validateEnd;
/**
* Create a new session using properties specified in the context.
@@ -46,6 +49,7 @@ public final class JsonParserSession extends ReaderParserSession {
*/
protected JsonParserSession(JsonParser ctx, ParserSessionArgs args) {
super(ctx, args);
+ validateEnd = getProperty(JSON_validateEnd, boolean.class, ctx.validateEnd);
}
/**
@@ -290,6 +294,7 @@ public final class JsonParserSession extends ReaderParserSession {
int S5=5; // Looking for , or }
int S6=6; // Found , looking for attr start.
+ skipCommentsAndSpace(r);
int state = S0;
String currAttr = null;
int c = 0;
@@ -298,6 +303,8 @@ public final class JsonParserSession extends ReaderParserSession {
if (state == S0) {
if (c == '{')
state = S1;
+ else
+ break;
} else if (state == S1) {
if (c == '}') {
return m;
@@ -738,6 +745,8 @@ public final class JsonParserSession extends ReaderParserSession {
* remainder in the input, that it consists only of whitespace and comments.
*/
private void validateEnd(ParserReader r) throws Exception {
+ if (! validateEnd)
+ return;
skipCommentsAndSpace(r);
int c = r.read();
if (c != -1 && c != ';') // var x = {...}; expressions can end with a semicolon.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserBuilder.java
index 1c0d0b6..894b569 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserBuilder.java
@@ -50,6 +50,18 @@ public class MsgPackParserBuilder extends ParserBuilder {
//--------------------------------------------------------------------------------
@Override /* ParserBuilder */
+ public MsgPackParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public MsgPackParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public MsgPackParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -91,6 +103,18 @@ public class MsgPackParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public MsgPackParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public MsgPackParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public MsgPackParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
index 9d944c1..aa36e1e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
@@ -18,11 +18,15 @@ import java.nio.charset.*;
import java.util.*;
import org.apache.juneau.*;
+import org.apache.juneau.html.*;
import org.apache.juneau.http.*;
import org.apache.juneau.json.*;
+import org.apache.juneau.msgpack.*;
import org.apache.juneau.transform.*;
import org.apache.juneau.transforms.*;
+import org.apache.juneau.uon.*;
import org.apache.juneau.utils.*;
+import org.apache.juneau.xml.*;
/**
* Parent class for all Juneau parsers.
@@ -122,6 +126,49 @@ public abstract class Parser extends BeanContext {
private static final String PREFIX = "Parser.";
/**
+ * Configuration property: Auto-close streams.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"Parser.autoCloseStreams.b"</js>
+ * <li><b>Data type:</b> <code>Boolean</code>
+ * <li><b>Default:</b> <jk>false</jk>
+ * <li><b>Session-overridable:</b> <jk>true</jk>
+ * <li><b>Methods:</b>
+ * <ul>
+ * <li class='jm'>{@link ParserBuilder#autoCloseStreams(boolean)}
+ * <li class='jm'>{@link ParserBuilder#autoCloseStreams()}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * If <jk>true</jk>, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
+ * after parsing is complete.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <jc>// Create a parser using strict mode.</jc>
+ * ReaderParser p = JsonParser.
+ * .<jsm>create</jsm>()
+ * .autoCloseStreams()
+ * .build();
+ *
+ * <jc>// Same, but use property.</jc>
+ * ReaderParser p = JsonParser.
+ * .<jsm>create</jsm>()
+ * .set(<jsf>PARSER_autoCloseStreams</jsf>, <jk>true</jk>)
+ * .build();
+ *
+ * Reader r = <jk>new</jk> FileReader(<js>"/tmp/myfile.json"</js>);
+ * MyBean myBean = p.parse(r, MyBean.<jk>class</jk>);
+ *
+ * <jsm>assertTrue</jsm>(r.isClosed());
+ * </p>
+ */
+ public static final String PARSER_autoCloseStreams = PREFIX + "autoCloseStreams.b";
+
+ /**
* Configuration property: File charset.
*
* <h5 class='section'>Property:</h5>
@@ -388,6 +435,70 @@ public abstract class Parser extends BeanContext {
* </p>
*/
public static final String PARSER_trimStrings = PREFIX + "trimStrings.b";
+
+ /**
+ * Configuration property: Unbuffered.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"Parser.unbuffered.b"</js>
+ * <li><b>Data type:</b> <code>Boolean</code>
+ * <li><b>Default:</b> <jk>false</jk>
+ * <li><b>Session-overridable:</b> <jk>true</jk>
+ * <li><b>Methods:</b>
+ * <ul>
+ * <li class='jm'>{@link ParserBuilder#unbuffered(boolean)}
+ * <li class='jm'>{@link ParserBuilder#unbuffered()}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * If <jk>true</jk>, don't use internal buffering during parsing.
+ *
+ * <p>
+ * This is useful in cases when you want to parse the same input stream or reader multiple times
+ * because it may contain multiple independent POJOs to parse.
+ * <br>Buffering would cause the parser to read past the current POJO in the stream.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <jc>// Create a parser using strict mode.</jc>
+ * ReaderParser p = JsonParser.
+ * .<jsm>create</jsm>()
+ * .unbuffered()
+ * .build();
+ *
+ * <jc>// Same, but use property.</jc>
+ * ReaderParser p = JsonParser.
+ * .<jsm>create</jsm>()
+ * .set(<jsf>PARSER_unbuffered</jsf>, <jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Read input with multiple POJOs</jc>
+ * Reader json = <jk>new</jk> StringReader(<js>"{foo:'bar'}{foo:'baz'}"</js>);
+ * MyBean myBean1 = p.parse(json, MyBean.<jk>class</jk>);
+ * MyBean myBean2 = p.parse(json, MyBean.<jk>class</jk>);
+ * </p>
+ *
+ * <h5 class='section'>Notes:</h5>
+ * <ul>
+ * <li>
+ * This only allows for multi-input streams for the following parsers:
+ * <ul>
+ * <li class='jc'>{@link JsonParser}
+ * <li class='jc'>{@link UonParser}
+ * <ul>
+ * It has no effect on the following parsers:
+ * <ul>
+ * <li class='jc'>{@link MsgPackParser} - It already doesn't use buffering.
+ * <li class='jc'>{@link XmlParser}, {@link HtmlParser} - These use StAX which doesn't allow for more than one root element anyway.
+ * <li>RDF parsers - These read everything into an internal model before any parsing begins.
+ * </ul>
+ *
+ * If <jk>true</jk>, don't use internal buffering during parsing.
+ */
+ public static final String PARSER_unbuffered = PREFIX + "unbuffered.b";
static Parser DEFAULT = new Parser(PropertyStore.create().build()) {
@Override
@@ -400,7 +511,7 @@ public abstract class Parser extends BeanContext {
// Instance
//-------------------------------------------------------------------------------------------------------------------
- final boolean trimStrings, strict;
+ final boolean trimStrings, strict, autoCloseStreams, unbuffered;
final String inputStreamCharset, fileCharset;
final Class<? extends ParserListener> listener;
@@ -413,6 +524,8 @@ public abstract class Parser extends BeanContext {
trimStrings = getProperty(PARSER_trimStrings, boolean.class, false);
strict = getProperty(PARSER_strict, boolean.class, false);
+ autoCloseStreams = getProperty(PARSER_autoCloseStreams, boolean.class, false);
+ unbuffered = getProperty(PARSER_unbuffered, boolean.class, false);
inputStreamCharset = getProperty(PARSER_inputStreamCharset, String.class, "UTF-8");
fileCharset = getProperty(PARSER_fileCharset, String.class, "DEFAULT");
listener = getClassProperty(PARSER_listener, ParserListener.class, null);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserBuilder.java
index dc7ce0e..56477a6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserBuilder.java
@@ -46,6 +46,44 @@ public class ParserBuilder extends BeanContextBuilder {
//--------------------------------------------------------------------------------
/**
+ * Configuration property: Auto-close streams.
+ *
+ * <p>
+ * If <jk>true</jk>, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
+ * after parsing is complete.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_autoCloseStreams}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public ParserBuilder autoCloseStreams(boolean value) {
+ return set(PARSER_autoCloseStreams, value);
+ }
+
+ /**
+ * Configuration property: Auto-close streams.
+ *
+ * <p>
+ * Shortcut for calling <code>autoCloseStreams(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_autoCloseStreams}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public ParserBuilder autoCloseStreams() {
+ return set(PARSER_autoCloseStreams, true);
+ }
+
+ /**
* Configuration property: File charset.
*
* <p>
@@ -218,6 +256,43 @@ public class ParserBuilder extends BeanContextBuilder {
return set(PARSER_trimStrings, true);
}
+ /**
+ * Configuration property: Unbuffered.
+ *
+ * <p>
+ * If <jk>true</jk>, don't use internal buffering during parsing.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_unbuffered}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public ParserBuilder unbuffered(boolean value) {
+ return set(PARSER_unbuffered, value);
+ }
+
+ /**
+ * Configuration property: Unbuffered.
+ *
+ * <p>
+ * Shortcut for calling <code>unbuffered(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_unbuffered}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public ParserBuilder unbuffered() {
+ return set(PARSER_unbuffered, true);
+ }
+
@Override /* BeanContextBuilder */
public ParserBuilder beanClassVisibility(Visibility value) {
super.beanClassVisibility(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
index 39f40dd..6136568 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
@@ -131,6 +131,43 @@ public class ParserGroupBuilder extends BeanContextBuilder {
//--------------------------------------------------------------------------------
/**
+ * Configuration property: Auto-close streams.
+ *
+ * <p>
+ * If <jk>true</jk>, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
+ * after parsing is complete.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_autoCloseStreams}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public ParserGroupBuilder autoCloseStreams(boolean value) {
+ return set(PARSER_autoCloseStreams, value);
+ }
+
+ /**
+ * Configuration property: Auto-close streams.
+ * <p>
+ * Shortcut for calling <code>autoCloseStreams(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_autoCloseStreams}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public ParserGroupBuilder autoCloseStreams() {
+ return set(PARSER_autoCloseStreams, true);
+ }
+
+ /**
* Configuration property: File charset.
*
* <p>
@@ -263,6 +300,43 @@ public class ParserGroupBuilder extends BeanContextBuilder {
return set(PARSER_trimStrings, true);
}
+ /**
+ * Configuration property: Unbuffered.
+ *
+ * <p>
+ * If <jk>true</jk>, don't use internal buffering during parsing.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_unbuffered}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public ParserGroupBuilder unbuffered(boolean value) {
+ return set(PARSER_unbuffered, value);
+ }
+
+ /**
+ * Configuration property: Unbuffered.
+ *
+ * <p>
+ * Shortcut for calling <code>unbuffered(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_unbuffered}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public ParserGroupBuilder unbuffered() {
+ return set(PARSER_unbuffered, true);
+ }
+
@Override /* BeanContextBuilder */
public ParserGroupBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserPipe.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserPipe.java
index 27a2c15..aa2bba9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserPipe.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserPipe.java
@@ -52,12 +52,14 @@ import org.apache.juneau.internal.*;
public final class ParserPipe implements Closeable {
private final Object input;
- private final boolean debug, strict;
+ final boolean debug, strict, autoCloseStreams, unbuffered;
private final String fileCharset, inputStreamCharset;
private String inputString;
private InputStream inputStream;
private Reader reader;
+ private ParserReader parserReader;
+ private boolean doClose;
/**
* Constructor.
@@ -71,6 +73,12 @@ public final class ParserPipe implements Closeable {
* If <jk>true</jk>, sets {@link CodingErrorAction#REPORT} on {@link CharsetDecoder#onMalformedInput(CodingErrorAction)}
* and {@link CharsetDecoder#onUnmappableCharacter(CodingErrorAction)}.
* Otherwise, sets them to {@link CodingErrorAction#REPLACE}.
+ * @param autoCloseStreams
+ * Automatically close {@link InputStream InputStreams} and {@link Reader Readers} when passed in as input.
+ * @param unbuffered
+ * If <jk>true</jk>, we read one character at a time from underlying readers when the readers are expected to be parsed
+ * multiple times.
+ * <br>Otherwise, we read character data into a reusable buffer.
* @param fileCharset
* The charset to expect when reading from {@link File Files}.
* Use <js>"default"</js> to specify {@link Charset#defaultCharset()}.
@@ -78,10 +86,12 @@ public final class ParserPipe implements Closeable {
* The charset to expect when reading from {@link InputStream InputStreams}.
* Use <js>"default"</js> to specify {@link Charset#defaultCharset()}.
*/
- public ParserPipe(Object input, boolean debug, boolean strict, String fileCharset, String inputStreamCharset) {
+ public ParserPipe(Object input, boolean debug, boolean strict, boolean autoCloseStreams, boolean unbuffered, String fileCharset, String inputStreamCharset) {
this.input = input;
this.debug = debug;
this.strict = strict;
+ this.autoCloseStreams = autoCloseStreams;
+ this.unbuffered = unbuffered;
this.fileCharset = fileCharset;
this.inputStreamCharset = inputStreamCharset;
if (input instanceof CharSequence)
@@ -97,7 +107,7 @@ public final class ParserPipe implements Closeable {
* @param input The input object.
*/
public ParserPipe(Object input) {
- this(input, false, false, null, null);
+ this(input, false, false, false, false, null, null);
}
/**
@@ -120,14 +130,17 @@ public final class ParserPipe implements Closeable {
inputStream = new ByteArrayInputStream(b);
} else {
inputStream = (InputStream)input;
+ doClose = autoCloseStreams;
}
} else if (input instanceof byte[]) {
if (debug)
inputString = toHex((byte[])input);
inputStream = new ByteArrayInputStream((byte[])input);
+ doClose = false;
} else if (input instanceof String) {
inputString = (String)input;
inputStream = new ByteArrayInputStream(fromHex((String)input));
+ doClose = false;
} else if (input instanceof File) {
if (debug) {
byte[] b = readBytes((File)input);
@@ -135,6 +148,7 @@ public final class ParserPipe implements Closeable {
inputStream = new ByteArrayInputStream(b);
} else {
inputStream = new FileInputStream((File)input);
+ doClose = true;
}
} else {
throw new IOException("Cannot convert object of type "+input.getClass().getName()+" to an InputStream.");
@@ -163,11 +177,14 @@ public final class ParserPipe implements Closeable {
reader = new StringReader(inputString);
} else {
reader = (Reader)input;
+ doClose = autoCloseStreams;
}
} else if (input instanceof CharSequence) {
inputString = input.toString();
reader = new ParserReader(this);
+ doClose = false;
} else if (input instanceof InputStream || input instanceof byte[]) {
+ doClose = input instanceof InputStream && autoCloseStreams;
InputStream is = (
input instanceof InputStream
? (InputStream)input
@@ -208,6 +225,7 @@ public final class ParserPipe implements Closeable {
inputString = read(reader);
reader = new StringReader(inputString);
}
+ doClose = true;
} else {
throw new IOException("Cannot convert object of type "+input.getClass().getName()+" to a Reader.");
}
@@ -250,10 +268,10 @@ public final class ParserPipe implements Closeable {
if (input == null)
return null;
if (input instanceof ParserReader)
- reader = (ParserReader)input;
+ parserReader = (ParserReader)input;
else
- reader = new ParserReader(this);
- return (ParserReader)reader;
+ parserReader = new ParserReader(this);
+ return parserReader;
}
/**
@@ -268,7 +286,8 @@ public final class ParserPipe implements Closeable {
@Override /* Closeable */
public void close() {
try {
- IOUtils.close(reader, inputStream);
+ if (doClose)
+ IOUtils.close(reader, inputStream);
} catch (IOException e) {
throw new BeanRuntimeException(e);
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserReader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserReader.java
index 16c4e84..e536076 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserReader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserReader.java
@@ -43,6 +43,7 @@ public class ParserReader extends Reader {
private int iMark = -1; // Mark position in buffer
private int iEnd = 0; // The last good character position in the buffer
private boolean endReached, holesExist;
+ private final boolean unbuffered;
/**
* Constructor.
@@ -52,6 +53,7 @@ public class ParserReader extends Reader {
*/
public ParserReader(ParserPipe pipe) throws IOException {
this.pipe = pipe;
+ this.unbuffered = pipe.unbuffered;
if (pipe.isString()) {
String in = pipe.getInputAsString();
this.r = new CharSequenceReader(in);
@@ -284,14 +286,16 @@ public class ParserReader extends Reader {
}
/**
- * Close this reader and the underlying reader.
+ * No-op.
+ *
+ * <p>
+ * Input readers are closed in the {@link ParserPipe} class.
*
* @throws IOException If a problem occurred trying to read from the reader.
*/
@Override /* Reader */
public void close() throws IOException {
- if (r != null)
- r.close();
+ // No-op
}
/**
@@ -413,7 +417,7 @@ public class ParserReader extends Reader {
*/
@Override /* Reader */
public int read(char[] cbuf, int off, int len) throws IOException {
- return r.read(cbuf, off, len);
+ return unbuffered ? r.read(cbuf, off, 1) : r.read(cbuf, off, len);
}
/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
index 485e709..405e628 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
@@ -33,7 +33,7 @@ import org.apache.juneau.utils.*;
*/
public abstract class ParserSession extends BeanSession {
- private final boolean trimStrings, strict;
+ private final boolean trimStrings, strict, autoCloseStreams, unbuffered;
private final String inputStreamCharset, fileCharset;
private final Method javaMethod;
private final Object outer;
@@ -56,6 +56,8 @@ public abstract class ParserSession extends BeanSession {
super(ctx, args);
trimStrings = getProperty(PARSER_trimStrings, boolean.class, ctx.trimStrings);
strict = getProperty(PARSER_strict, boolean.class, ctx.strict);
+ autoCloseStreams = getProperty(PARSER_autoCloseStreams, boolean.class, ctx.autoCloseStreams);
+ unbuffered = getProperty(PARSER_unbuffered, boolean.class, ctx.unbuffered);
inputStreamCharset = getProperty(PARSER_inputStreamCharset, String.class, ctx.inputStreamCharset);
fileCharset = getProperty(PARSER_fileCharset, String.class, ctx.fileCharset);
javaMethod = args.javaMethod;
@@ -147,7 +149,7 @@ public abstract class ParserSession extends BeanSession {
* A new {@link ParserPipe} wrapper around the specified input object.
*/
public final ParserPipe createPipe(Object input) {
- return new ParserPipe(input, isDebug(), strict, fileCharset, inputStreamCharset);
+ return new ParserPipe(input, isDebug(), strict, autoCloseStreams, unbuffered, fileCharset, inputStreamCharset);
}
/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextParserBuilder.java
index d8b80ed..ae63bd0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextParserBuilder.java
@@ -50,6 +50,18 @@ public class PlainTextParserBuilder extends ParserBuilder {
//--------------------------------------------------------------------------------
@Override /* ParserBuilder */
+ public PlainTextParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public PlainTextParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public PlainTextParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -91,6 +103,18 @@ public class PlainTextParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public PlainTextParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public PlainTextParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public PlainTextParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParser.java
index b378faf..ed08dd9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParser.java
@@ -78,6 +78,47 @@ public class UonParser extends ReaderParser {
*/
public static final String UON_decoding = PREFIX + "decoding.b";
+ /**
+ * Configuration property: Validate end.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"UonParser.validateEnd.b"</js>
+ * <li><b>Data type:</b> <code>Boolean</code>
+ * <li><b>Default:</b> <jk>false</jk>
+ * <li><b>Session-overridable:</b> <jk>true</jk>
+ * <li><b>Methods:</b>
+ * <ul>
+ * <li class='jm'>{@link UonParserBuilder#validateEnd(boolean)}
+ * <li class='jm'>{@link UonParserBuilder#validateEnd()}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * If <jk>true</jk>, after parsing a POJO from the input, verifies that the remaining input in
+ * the stream consists of only comments or whitespace.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ * <jc>// Create a parser using strict mode.</jc>
+ * ReaderParser p = UonParser.
+ * .<jsm>create</jsm>()
+ * .validateEnd()
+ * .build();
+ *
+ * <jc>// Same, but use property.</jc>
+ * ReaderParser p = UonParser.
+ * .<jsm>create</jsm>()
+ * .set(<jsf>UON_validateEnd</jsf>, <jk>true</jk>)
+ * .build();
+ *
+ * <jc>// Should fail because input has multiple POJOs.</jc>
+ * String in = <js>"(foo=bar)(baz=qux)"</js>;
+ * MyBean myBean = p.parse(in, MyBean.<jk>class</jk>);
+ * </p>
+ */
+ public static final String UON_validateEnd = PREFIX + "validateEnd.b";
//-------------------------------------------------------------------------------------------------------------------
// Predefined instances
@@ -113,7 +154,7 @@ public class UonParser extends ReaderParser {
//-------------------------------------------------------------------------------------------------------------------
final boolean
- decodeChars;
+ decodeChars, validateEnd;
/**
* Constructor.
@@ -136,6 +177,7 @@ public class UonParser extends ReaderParser {
public UonParser(PropertyStore ps, String...consumes) {
super(ps, consumes);
this.decodeChars = getProperty(UON_decoding, boolean.class, false);
+ this.validateEnd = getProperty(UON_validateEnd, boolean.class, false);
}
@Override /* Context */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserBuilder.java
index 9dd292a..2f41431 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserBuilder.java
@@ -90,6 +90,56 @@ public class UonParserBuilder extends ParserBuilder {
return decoding(true);
}
+ /**
+ * Configuration property: Validate end.
+ *
+ * <p>
+ * If <jk>true</jk>, after parsing a POJO from the input, verifies that the remaining input in
+ * the stream consists of only whitespace.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link UonParser#UON_validateEnd}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public UonParserBuilder validateEnd(boolean value) {
+ return set(UON_validateEnd, value);
+ }
+
+ /**
+ * Configuration property: Validate end.
+ *
+ * <p>
+ * Shortcut for calling <code>validateEnd(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link UonParser#UON_validateEnd}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public UonParserBuilder validateEnd() {
+ return set(UON_validateEnd, true);
+ }
+
+ @Override /* ParserBuilder */
+ public UonParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public UonParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
@Override /* ParserBuilder */
public UonParserBuilder fileCharset(String value) {
super.fileCharset(value);
@@ -132,6 +182,18 @@ public class UonParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public UonParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public UonParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public UonParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
index 95ebad8..ad7906a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
@@ -40,7 +40,7 @@ public class UonParserSession extends ReaderParserSession {
private static final char AMP='\u0001', EQ='\u0002'; // Flags set in reader to denote & and = characters.
- private final boolean decodeChars;
+ private final boolean decodeChars, validateEnd;
/**
* Create a new session using properties specified in the context.
@@ -54,6 +54,7 @@ public class UonParserSession extends ReaderParserSession {
protected UonParserSession(UonParser ctx, ParserSessionArgs args) {
super(ctx, args);
decodeChars = getProperty(UON_decoding, boolean.class, ctx.decodeChars);
+ validateEnd = getProperty(UON_validateEnd, boolean.class, ctx.validateEnd);
}
@Override /* Session */
@@ -82,6 +83,7 @@ public class UonParserSession extends ReaderParserSession {
protected UonParserSession(UonParser ctx, ParserSessionArgs args, boolean decodeChars) {
super(ctx, args);
this.decodeChars = decodeChars;
+ this.validateEnd = true;
}
@Override /* ParserSession */
@@ -728,6 +730,8 @@ public class UonParserSession extends ReaderParserSession {
* remainder in the input, that it consists only of whitespace and comments.
*/
private void validateEnd(UonReader r) throws Exception {
+ if (! validateEnd)
+ return;
while (true) {
int c = r.read();
if (c == -1)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserBuilder.java
index fc819fc..a3d1a19 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserBuilder.java
@@ -184,6 +184,18 @@ public class XmlParserBuilder extends ParserBuilder {
}
@Override /* ParserBuilder */
+ public XmlParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public XmlParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public XmlParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -225,6 +237,18 @@ public class XmlParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public XmlParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public XmlParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public XmlParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserBuilder.java
index 19e27f0..c9c8ee0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlParserBuilder.java
@@ -50,6 +50,18 @@ public class YamlParserBuilder extends ParserBuilder {
//--------------------------------------------------------------------------------
@Override /* ParserBuilder */
+ public YamlParserBuilder autoCloseStreams(boolean value) {
+ super.autoCloseStreams(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public YamlParserBuilder autoCloseStreams() {
+ super.autoCloseStreams();
+ return this;
+ }
+
+ @Override /* ParserBuilder */
public YamlParserBuilder fileCharset(String value) {
super.fileCharset(value);
return this;
@@ -91,6 +103,18 @@ public class YamlParserBuilder extends ParserBuilder {
return this;
}
+ @Override /* ParserBuilder */
+ public YamlParserBuilder unbuffered(boolean value) {
+ super.unbuffered(value);
+ return this;
+ }
+
+ @Override /* ParserBuilder */
+ public YamlParserBuilder unbuffered() {
+ super.unbuffered();
+ return this;
+ }
+
@Override /* BeanContextBuilder */
public YamlParserBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index c3b1442..de1b32f 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -116,6 +116,7 @@
<li><p><a class='doclink' href='#juneau-marshall.BeanSubTypes'>Bean Subtypes</a></p>
</ol>
<li><p><a class='doclink' href='#juneau-marshall.VirtualBeans'>Virtual Beans</a></p>
+ <li><p><a class='doclink' href='#juneau-marshall.ReadingContinuousStreams'>Reading Continuous Streams</a></p>
<li><p><a class='doclink' href='#juneau-marshall.JacksonComparison'>Comparison with Jackson</a></p>
<li><p><a class='doclink' href='#juneau-marshall.PojoCategories'>POJO Categories</a></p>
<li><p><a class='doclink' href='#juneau-marshall.BestPractices'>Best Practices</a></p>
@@ -3033,8 +3034,59 @@
</div>
<!-- ======================================================================================================= -->
+ <a id="juneau-marshall.ReadingContinuousStreams"></a>
+ <h4 class='topic' onclick='toggle(this)'>2.1.10 - Reading Continuous Streams</h4>
+ <div class='topic'>
+ <p>
+ The following parsers can be configured to read continous streams of objects from the same input stream:
+ </p>
+ <ul>
+ <li class='jc'>{@link org.apache.juneau.json.JsonParser}
+ <li class='jc'>{@link org.apache.juneau.uon.UonParser}
+ <li class='jc'>{@link org.apache.juneau.msgpack.MsgPackParser}
+ </ul>
+ <p>
+ The {@link org.apache.juneau.json.JsonParser} and {@link org.apache.juneau.uon.UonParser}
+ classes can read continous streams by using the {@link org.apache.juneau.parser.Parser#PARSER_unbuffered}
+ setting.
+ <br>This prevents the parsers from using an internal buffer that would read past the end of the currently
+ parsed POJO.
+ </p>
+ <h6 class='figure'>Examples:</h6>
+ <p class='bcode'>
+ ReaderParser p = JsonParser.<jsm>create</jsm>().unbuffered().build();
+ Object x;
+ Reader r;
+
+ r = new StringReader(<js>"{foo:'bar'}{baz:'qux'}"</js>);
+ x = p.parse(r, ObjectMap.<jk>class</jk>); <jc>// {foo:'bar'}</jc>
+ x = p.parse(r, ObjectMap.<jk>class</jk>); <jc>// {baz:'qux'}</jc>
+
+ r = reader(<js>"[123][456]"</js>);
+ x = p.parse(r, <jk>int</jk>[].<jk>class</jk>); <jc>// [123]</jc>
+ x = p.parse(r, <jk>int</jk>[].<jk>class</jk>); <jc>// [456]</jc>
+ </p>
+ <p>
+ Note that this isn't perfect in all cases since you can't combine two JSON numbers into a single
+ reader (e.g. <code>"123" + "456" = "123456"</code>).
+ </p>
+ <p>
+ For obvious reasons, do not use the following properties when reading continuous streams:
+ </p>
+ <ul>
+ <li class='jf'>{@link org.apache.juneau.json.JsonParser#JSON_validateEnd}
+ <li class='jf'>{@link org.apache.juneau.uon.UonParser#UON_validateEnd}
+ <li class='jf'>{@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams}
+ </ul>
+ <p>
+ The {@link org.apache.juneau.msgpack.MsgPackParser} class doesn't use any internal buffering to begin with, so it can be used with
+ continuous streams without any special properties.
+ </p>
+ </div>
+
+ <!-- ======================================================================================================= -->
<a id="juneau-marshall.JacksonComparison"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.10 - Comparison with Jackson</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.11 - Comparison with Jackson</h4>
<div class='topic'>
<p>
Juneau was developed independently from Jackson, but shares many of the same features and capabilities.
@@ -3147,7 +3199,7 @@
<!-- ======================================================================================================= -->
<a id="juneau-marshall.PojoCategories"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.11 - POJO Categories</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.12 - POJO Categories</h4>
<div class='topic'>
<p>
The following chart shows POJOs categorized into groups and whether they can be serialized or parsed:
@@ -3413,7 +3465,7 @@
<!-- ======================================================================================================= -->
<a id="juneau-marshall.BestPractices"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.12 - Best Practices</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.13 - Best Practices</h4>
<div class='topic'>
<ol class='spaced-list'>
<li>
@@ -3442,7 +3494,7 @@
<!-- ======================================================================================================= -->
<a id="juneau-marshall.AdditionalInfo"></a>
- <h4 class='topic' onclick='toggle(this)'>2.1.13 - Additional Information</h4>
+ <h4 class='topic' onclick='toggle(this)'>2.1.14 - Additional Information</h4>
<div class='topic'>
<p>
Extensive javadocs exist for individual language support.
@@ -12329,7 +12381,7 @@
<h5 class='toc'>What's new in each release</h5>
<ul class='toc'>
- <li><p><a class='doclink' href='#7.0.2'>7.0.2 (TBD)</a></p>
+ <li><p><a class='doclink' href='#7.1.0'>7.1.0 (TBD)</a></p>
<li><p><a class='doclink' href='#7.0.1'>7.0.1 (Dec 24, 2017)</a></p>
<li><p><a class='doclink' href='#7.0.0'>7.0.0 (Oct 25, 2017)</a></p>
<li><p><a class='doclink' href='#6.4.0'>6.4.0 (Oct 5, 2017)</a></p>
@@ -12402,8 +12454,8 @@
</ul>
<!-- =========================================================================================================== -->
- <a id="7.0.2"></a>
- <h3 class='topic' onclick='toggle(this)'>7.0.2 (TBD)</h3>
+ <a id="7.1.0"></a>
+ <h3 class='topic' onclick='toggle(this)'>7.1.0 (TBD)</h3>
<div class='topic'>
<p>
</p>
@@ -12534,6 +12586,15 @@
<li>{@link org.apache.juneau.parser.ParserSession#getListener() getListener()}
<li>{@link org.apache.juneau.parser.ParserSession#getListener(Class) getListener(Class)}
</ul>
+ <li>
+ New {@link org.apache.juneau.parser.Parser#PARSER_unbuffered} setting allows you to disable internal
+ buffering on the JSON and UON parsers so that they can be used to read continous streams of objects.
+ <li>
+ New {@link org.apache.juneau.json.JsonParser#JSON_validateEnd} and {@link org.apache.juneau.uon.UonParser#UON_validateEnd}
+ settings allow you to control whether we validate that there is no garbage at the end of the parsed input.
+ <li>
+ New {@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams} setting allows input streams and
+ readers passed into parsers to be automatically closed after parsing.
</ul>
<h6 class='topic'>juneau-marshall</h6>
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 36c4df7..b57427b 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -1542,6 +1542,43 @@ public class RestClientBuilder extends BeanContextBuilder {
}
/**
+ * Configuration property: Auto-close streams.
+ *
+ * If <jk>true</jk>, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
+ * after parsing is complete.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_autoCloseStreams}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public RestClientBuilder autoCloseStreams(boolean value) {
+ return set(PARSER_autoCloseStreams, value);
+ }
+
+ /**
+ * Configuration property: Auto-close streams.
+ *
+ * <p>
+ * Shortcut for calling <code>autoCloseStreams(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_autoCloseStreams}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public RestClientBuilder autoCloseStreams() {
+ return set(PARSER_autoCloseStreams, true);
+ }
+
+ /**
* Configuration property: File charset.
*
* <p>
@@ -1675,6 +1712,42 @@ public class RestClientBuilder extends BeanContextBuilder {
}
/**
+ * Configuration property: Unbuffered.
+ *
+ * If <jk>true</jk>, don't use internal buffering during parsing.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_unbuffered}
+ * </ul>
+ *
+ * @param value
+ * The new value for this property.
+ * <br>The default value is <jk>false</jk>.
+ * @return This object (for method chaining).
+ */
+ public RestClientBuilder unbuffered(boolean value) {
+ return set(PARSER_unbuffered, value);
+ }
+
+ /**
+ * Configuration property: Unbuffered.
+ *
+ * <p>
+ * Shortcut for calling <code>unbuffered(<jk>true</jk>)</code>.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link Parser#PARSER_unbuffered}
+ * </ul>
+ *
+ * @return This object (for method chaining).
+ */
+ public RestClientBuilder unbuffered() {
+ return set(PARSER_unbuffered, true);
+ }
+
+ /**
* TODO
*
* <h5 class='section'>See Also:</h5>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
index cfc2351..f3ac617 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestUtils.java
@@ -270,7 +270,7 @@ public final class RestUtils {
if (qs == null || ((qs instanceof CharSequence) && isEmpty(qs)))
return m;
- try (ParserPipe p = new ParserPipe(qs, false, false, null, null)) {
+ try (ParserPipe p = new ParserPipe(qs, false, false, false, false, null, null)) {
final int S1=1; // Looking for attrName start.
final int S2=2; // Found attrName start, looking for = or & or end.
--
To stop receiving notification emails like this one, please contact
jamesbognar@apache.org.