You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/01/26 01:32:58 UTC

[juneau] branch master updated: Add support for parsing continuous streams.

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 1687de4  Add support for parsing continuous streams.
1687de4 is described below

commit 1687de48602c3fde1c8fdcd8aa8f77b0c26a670e
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Jan 25 20:32:56 2018 -0500

    Add support for parsing continuous streams.
---
 .../juneau/CloseableByteArrayInputStream.java      |  38 ++++++
 .../org/apache/juneau/CloseableStringReader.java   |  45 +++++++
 .../java/org/apache/juneau/ParserReaderTest.java   |   2 +-
 .../src/test/java/org/apache/juneau/TestUtils.java |   7 --
 .../org/apache/juneau/json/JsonParserTest.java     |  51 ++++++++
 .../apache/juneau/msgpack/MsgPackParserTest.java   | 137 +++++++++++++++++++++
 ...ialzierTest.java => MsgPackSerializerTest.java} |   5 +-
 .../{urlencoding => uon}/CommonParser_UonTest.java |   3 +-
 .../{urlencoding => uon}/Common_UonTest.java       |  12 +-
 .../{urlencoding => uon}/UonParserReaderTest.java  |   3 +-
 .../juneau/{urlencoding => uon}/UonParserTest.java |  54 +++++++-
 .../{urlencoding => uon}/UonSerializerTest.java    |   3 +-
 .../org/apache/juneau/jena/RdfParserBuilder.java   |  24 ++++
 .../org/apache/juneau/csv/CsvParserBuilder.java    |  24 ++++
 .../org/apache/juneau/jso/JsoParserBuilder.java    |  24 ++++
 .../java/org/apache/juneau/json/JsonParser.java    |  53 +++++++-
 .../org/apache/juneau/json/JsonParserBuilder.java  |  64 ++++++++++
 .../org/apache/juneau/json/JsonParserSession.java  |   9 ++
 .../juneau/msgpack/MsgPackParserBuilder.java       |  24 ++++
 .../main/java/org/apache/juneau/parser/Parser.java | 115 ++++++++++++++++-
 .../org/apache/juneau/parser/ParserBuilder.java    |  75 +++++++++++
 .../apache/juneau/parser/ParserGroupBuilder.java   |  74 +++++++++++
 .../java/org/apache/juneau/parser/ParserPipe.java  |  33 +++--
 .../org/apache/juneau/parser/ParserReader.java     |  12 +-
 .../org/apache/juneau/parser/ParserSession.java    |   6 +-
 .../juneau/plaintext/PlainTextParserBuilder.java   |  24 ++++
 .../main/java/org/apache/juneau/uon/UonParser.java |  44 ++++++-
 .../org/apache/juneau/uon/UonParserBuilder.java    |  62 ++++++++++
 .../org/apache/juneau/uon/UonParserSession.java    |   6 +-
 .../org/apache/juneau/xml/XmlParserBuilder.java    |  24 ++++
 .../juneau/yaml/proto/YamlParserBuilder.java       |  24 ++++
 juneau-doc/src/main/javadoc/overview.html          |  75 +++++++++--
 .../juneau/rest/client/RestClientBuilder.java      |  73 +++++++++++
 .../java/org/apache/juneau/rest/RestUtils.java     |   2 +-
 34 files changed, 1182 insertions(+), 49 deletions(-)

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

-- 
To stop receiving notification emails like this one, please contact
jamesbognar@apache.org.