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 <[email protected]>
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
[email protected].

Reply via email to