juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [13/51] [partial] incubator-juneau git commit: Initial Juno contents from IBM JazzHub repo
Date Mon, 01 Aug 2016 00:08:02 GMT
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/package.html
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/package.html b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/package.html
new file mode 100755
index 0000000..98cb75a
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/package.html
@@ -0,0 +1,210 @@
+<!DOCTYPE HTML>
+<!--
+    Licensed Materials - Property of IBM
+    (c) Copyright IBM Corporation 2014. All Rights Reserved.
+   
+    Note to U.S. Government Users Restricted Rights:  
+    Use, duplication or disclosure restricted by GSA ADP Schedule 
+    Contract with IBM Corp. 
+ -->
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<style type="text/css">
+		/* For viewing in Page Designer */
+		@IMPORT url("../../../../../javadoc.css");
+
+		/* For viewing in REST interface */
+		@IMPORT url("../htdocs/javadoc.css");
+		body { 
+			margin: 20px; 
+		}	
+	</style>
+	<script>
+		/* Replace all @code and @link tags. */	
+		window.onload = function() {
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>');
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>');
+		}
+	</script>
+</head>
+<body>
+<p>Base toolkit for serializers, parsers, and bean contexts</p>
+
+<script>
+	function toggle(x) {
+		var div = x.nextSibling;
+		while (div != null && div.nodeType != 1)
+			div = div.nextSibling;
+		if (div != null) {
+			var d = div.style.display;
+			if (d == 'block' || d == '') {
+				div.style.display = 'none';
+				x.className += " closed";
+			} else {
+				div.style.display = 'block';
+				x.className = x.className.replace(/(?:^|\s)closed(?!\S)/g , '' );
+			}
+		}
+	}
+</script>
+
+<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
+<ol class='toc'>
+	<li><p><a class='doclink' href='#BeanContext_Api'>Bean Context API</a></p> 
+	<ol>
+		<li><p><a class='doclink' href='#BeanMap'>The BeanMap class</a></p> 
+		<li><p><a class='doclink' href='#BeanContext'>The BeanContext class</a></p>
+		<li><p><a class='doclink' href='#Bean'>Bean annotations</a></p>
+	</ol>
+	<li><p><a class='doclink' href='#ObjectMap_ObjectList'>ObjectMap and ObjectList APIs</a></p>
+	<li><p><a class='doclink' href='#PojoCategories'>POJO Categories</a></p>
+</ol>
+
+<!-- ======================================================================================================== -->
+<a id="BeanContext_Api"></a>
+<h2 class='topic' onclick='toggle(this)'>1 - Bean Context API</h2>
+<div class='topic'>
+	<p>
+		The {@link com.ibm.juno.core.BeanContext} class is the core class in the Juno architecture.  It serves multiple functions...
+	</p>
+	<ul class='normal'>
+		<li>It provides the ability to create instances of {@link com.ibm.juno.core.BeanMap BeanMaps}.
+		<li>It serves as a repository for {@link com.ibm.juno.core.filter.Filter Filters}, which are used to tailor how beans and non-beans are handled. 
+		<li>It's used by all built-in {@link com.ibm.juno.core.serializer.Serializer Serializers} and {@link com.ibm.juno.core.parser.Parser Parsers} for working with POJOs in a consistent way.
+	</ul>
+	
+	<!-- ======================================================================================================== -->
+	<a id="BeanMap"></a>
+	<h3 class='topic' onclick='toggle(this)'>1.1 - The BeanMap class</h3>
+	<div class='topic'>
+		<p>
+			The {@link com.ibm.juno.core.BeanMap} class allows you to access the properties of a bean through the familiar {@code Map} interface. 
+			So, for example, you can use the {@code Map.get(key)} method to retrieve a property value in leu of it's getter method, and the {@code Map.put(key, value)} method to set a property value in leu of it's setter method.
+		</p>
+		<p>
+			The serialization and parsing of beans in Juno is accomplished by wrapping Java beans inside instances of the class {@code BeanMap}. 
+		</p>
+		<p>
+			<b>Note:</b> Instances of {@link com.ibm.juno.core.BeanMap} objects are always retrieved through the {@link com.ibm.juno.core.BeanContext} class. You cannot instantiate {@code BeanMaps} directly since the rules for defining what constitutes a bean depend on various settings in the bean context.
+		</p>
+		<p>
+			In general, the performance on using the {@link com.ibm.juno.core.BeanMap} class to access properties is equivalent to using reflection directly.
+		</p>
+		<p>
+			See the {@link com.ibm.juno.core.BeanMap} javadoc for more information.
+		</p>
+	</div>
+	
+	<!-- ======================================================================================================== -->
+	<a id="BeanContext"></a>
+	<h3 class='topic' onclick='toggle(this)'>1.2 - The BeanContext class</h3>
+	<div class='topic'>
+		<p>
+			The {@link com.ibm.juno.core.BeanContext} class is the workhorse class used to wrap Java beans inside {@link com.ibm.juno.core.BeanMap BeanMaps}. 
+			There are several options provided on the {@link com.ibm.juno.core.BeanContext} class to tailor the definition of a bean.
+		</p>
+		<p>
+			The following is a very simple example of how to wrap a bean inside a {@link com.ibm.juno.core.BeanMap} wrapper and use the wrapper interface to get and set property values on the bean. 
+			In this case, we're using the DEFAULT bean context.
+		</p>
+		<p class='bcode'>
+	<jc>// A sample pseudo bean class.</jc>
+	<jk>public class</jk> Person {
+		<jk>public</jk> String getName();
+		<jk>public void</jk> setName(String name);
+		<jk>public int</jk> getAge();
+		<jk>public void</jk> setAge(<jk>int</jk> age);
+	}
+	
+	<jc>// Get an instance of a bean context.
+	// In this case, just use the default bean context.</jc>
+	BeanContext beanContext = BeanContext.<jsf>DEFAULT</jsf>;
+	
+	<jc>// Create an instance of our bean and wrap it in a bean map.</jc>
+	Person p = <jk>new</jk> Person();
+	BeanMap&lt;Person&gt; m = beanContext.forBean(p);
+	
+	<jc>// Set some properties on the bean.</jc>
+	m.put(<js>"name"</js>, <js>"John Smith"</js>);
+	m.put(<js>"age"</js>, 21);
+	
+	<jc>// Print out bean properties.</jc>
+	System.out.println(m.get(<js>"name"</js>));	<jc>// Prints "John Smith"</jc>
+	System.out.println(p.getName());	  <jc>// Prints "John Smith"</jc>
+	System.out.println(m.get(<js>"age"</js>));	 <jc>// Prints 21</jc>
+	System.out.println(p.getAge());		<jc>// Prints 21</jc>
+	
+	<jc>// The bean context class can also create instances of bean maps.</jc>
+	m = beanContext.newBeanMap(Person.<jk>class</jk>);
+	p = m.getBean();	<jc>// Get the new wrapped bean.</jc>
+	
+	<jc>// The bean context class can also create instances of beans.</jc>
+	p = beanContext.newBean(Person.<jk>class</jk>);
+		</p>
+		<p>
+			There are 3 ways to get an instance of a {@link com.ibm.juno.core.BeanContext}:
+		</p>
+		<p class='bcode'>
+	<jc>// Use one of the default bean contexts.</jc>
+	BeanContext beanContext = BeanContext.<jsf>DEFAULT</jsf>;
+	
+	<jc>// Create a context from scratch with your own settings.</jc>
+	beanContext = <jk>new</jk> BeanContext().addFilters(DateFilter.ISO8601DT.<jk>class</jk>);
+	
+	<jc>// Clone and modify an existing context.</jc>
+	beanContext = BeanContext.<jsf>DEFAULT</jsf>.clone().addFilters(DateFilter.ISO8601DT.<jk>class</jk>);
+		</p>
+		<p>
+			The {@link com.ibm.juno.core.BeanContext} class is a highly-customizable class.  
+			See the {@link com.ibm.juno.core.BeanContext} javadoc for more information.
+		</p>
+	</div>
+	
+	<!-- ======================================================================================================== -->
+	<a id="Bean"></a>
+	<h3 class='topic' onclick='toggle(this)'>1.3 - Bean annotations</h3>
+	<div class='topic'>
+		<p>
+			Juno provides the following annotations that can be used to fine-tune what properties are associated with beans:
+		</p>
+		<ul class='normal'>
+			<li>{@link com.ibm.juno.core.annotation.Bean} - Fine-tune properties associated with beans.
+			<li>{@link com.ibm.juno.core.annotation.BeanProperty} - Fine-tune bean properties (fields / getters / setters).
+			<li>{@link com.ibm.juno.core.annotation.BeanConstructor} - Define read-only bean properties that can only be set through constructor arguments.
+			<li>{@link com.ibm.juno.core.annotation.BeanIgnore} - Prevent bean classes/methods/fields from being interpreted as bean constructs.
+		</ul>
+		<p>
+			These annotations always override the settings defined in the {@link com.ibm.juno.core.BeanContext} class.
+		</p>
+		<p>
+			For example, the following bean class will only have one property associated with it, <js>"name"</js>, since it's the only one listed in the list of properties.
+		</p>
+		<p class='bcode'>
+	<jc>// Bean with only one 'name' property</jc>
+	<ja>@Bean</ja>(properties={<js>"name"</js>})
+	<jk>public class</jk> Person {
+		<jk>public</jk> String getName();
+		<jk>public void</jk> setName(String name);
+		<jk>public int</jk> getAge();
+		<jk>public void</jk> setAge(<jk>int</jk> age);
+	}
+		</p>
+		<p>
+			When this bean is serialized using one of the {@link com.ibm.juno.core.serializer.Serializer Serializers}, the age property will be ignored.
+		</p>
+		<p>
+			Using the <ja>@Bean</ja> and <ja>@BeanProperty</ja> annotations, it's also possible to include non-standard properties (for example, getters or setters with non-standard names), or override the names of properties (for example, {@code "Name"} or {@code "fullName"} instead of {@code "name"}).
+		</p>
+		<p>
+			It should be noted that the {@link com.ibm.juno.core.filter.BeanFilter} class can also be used to exclude properties from beans.  
+			However, only the annotations can be used to include non-standard properties or override property names.
+		</p>
+		<p>
+			See the {@link com.ibm.juno.core.annotation.Bean}, {@link com.ibm.juno.core.annotation.BeanProperty}, {@link com.ibm.juno.core.annotation.BeanConstructor}, and {@link com.ibm.juno.core.annotation.BeanIgnore} javadocs for more information.
+		</p>
+	</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.class
new file mode 100755
index 0000000..ec2f7c0
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.java
new file mode 100755
index 0000000..e4b8518
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/InputStreamParser.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * © Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import java.io.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.annotation.*;
+
+/**
+ * Subclass of {@link Parser} for byte-based parsers.
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ * 	This class is typically the parent class of all byte-based parsers.
+ * 	It has 1 abstract method to implement...
+ * <ul>
+ * 	<li><code>parse(InputStream, ClassMeta, ParserContext)</code>
+ * </ul>
+ *
+ *
+ * <h6 class='topic'>@Consumes annotation</h6>
+ * <p>
+ * 	The media types that this parser can handle is specified through the {@link Consumes @Consumes} annotation.
+ * <p>
+ * 	However, the media types can also be specified programmatically by overriding the {@link #getMediaTypes()} method.
+ *
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public abstract class InputStreamParser extends Parser<InputStream> {
+
+	@Override /* Parser */
+	public boolean isReaderParser() {
+		return false;
+	}
+
+	//--------------------------------------------------------------------------------
+	// Abstract methods
+	//--------------------------------------------------------------------------------
+
+	@Override /* Parser */
+	protected abstract <T> T doParse(InputStream in, int estimatedSize, ClassMeta<T> type, ParserContext ctx) throws ParseException, IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.class
new file mode 100755
index 0000000..858b57f
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.java
new file mode 100755
index 0000000..f013dfb
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParseException.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import java.text.*;
+
+/**
+ * Exception that indicates invalid syntax encountered during parsing.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class ParseException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param msg The error message.
+	 * @param args Optional printf arguments to replace in the error message.
+	 */
+	public ParseException(String msg, Object...args) {
+		super(args.length == 0 ? msg : MessageFormat.format(msg, args));
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param lineNumber The line number where the parse error was detected.
+	 * @param colNumber The column number where the parse error was detected.
+	 * @param msg The error message.
+	 * @param args Optional printf arguments to replace in the error message.
+	 */
+	public ParseException(int lineNumber, int colNumber, String msg, Object... args) {
+		super(
+			(lineNumber != -1 ? MessageFormat.format("Parse exception occurred at line=''{0}'', column=''{1}''.  ", lineNumber, colNumber) : "")
+			+ (args.length == 0 ? msg : MessageFormat.format(msg, args))
+		);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param cause The cause of the parse exception.
+	 */
+	public ParseException(Exception cause) {
+		super(cause == null ? null : cause.getLocalizedMessage());
+		initCause(cause);
+	}
+
+	/**
+	 * Returns the highest-level <code>ParseException</code> in the stack trace.
+	 * Useful for JUnit testing of error conditions.
+	 *
+	 * @return The root parse exception, or this exception if there isn't one.
+	 */
+	public ParseException getRootCause() {
+		ParseException t = this;
+		while (! (t.getCause() == null || ! (t.getCause() instanceof ParseException)))
+			t = (ParseException)t.getCause();
+		return t;
+	}
+
+	/**
+	 * Sets the inner cause for this exception.
+	 *
+	 * @param cause The inner cause.
+	 * @return This object (for method chaining).
+	 */
+	@Override /* Throwable */
+	public synchronized ParseException initCause(Throwable cause) {
+		super.initCause(cause);
+		return this;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.class
new file mode 100755
index 0000000..222d41a
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.java
new file mode 100755
index 0000000..0394bc6
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/Parser.java
@@ -0,0 +1,573 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import static com.ibm.juno.core.utils.StringUtils.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.text.*;
+import java.util.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.filter.*;
+import com.ibm.juno.core.filters.*;
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Parent class for all Juno parsers.
+ *
+ *
+ * <h6 class='topic'>@Consumes annotation</h6>
+ * <p>
+ * 	The media types that this parser can handle is specified through the {@link Consumes @Consumes} annotation.
+ * <p>
+ * 	However, the media types can also be specified programmatically by overriding the {@link #getMediaTypes()} method.
+ *
+ *
+ * <a id='ValidDataConversions'></a><h6 class='topic'>Valid data conversions</h6>
+ * 	Parsers can parse any parsable POJO types, as specified in the <a class='doclink' href='../package-summary.html#PojoCategories'>POJO Categories</a>.
+ * <p>
+ * 	Some examples of conversions are shown below...
+ * </p>
+ * 	<table class='styled'>
+ * 		<tr>
+ * 			<th>Data type</th>
+ * 			<th>Class type</th>
+ * 			<th>JSON example</th>
+ * 			<th>XML example</th>
+ * 			<th>Class examples</th>
+ * 		</tr>
+ * 		<tr>
+ * 			<td>object</td>
+ * 			<td>Maps, Java beans</td>
+ * 			<td class='code'>{name:<js>'John Smith'</js>,age:21}</td>
+ * 			<td class='code'><xt>&lt;object&gt;
+ * 	&lt;name</xt> <xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt>John Smith<xt>&lt;/name&gt;
+ * 	&lt;age</xt> <xa>type</xa>=<xs>'number'</xs><xt>&gt;</xt>21<xt>&lt;/age&gt;
+ * &lt;/object&gt;</xt></td>
+ * 			<td class='code'>HashMap, TreeMap&lt;String,Integer&gt;</td>
+ * 		</tr>
+ * 		<tr>
+ * 			<td>array</td>
+ * 			<td>Collections, Java arrays</td>
+ * 			<td class='code'>[1,2,3]</td>
+ * 			<td class='code'><xt>&lt;array&gt;
+ * 	&lt;number&gt;</xt>1<xt>&lt;/number&gt;
+ * 	&lt;number&gt;</xt>2<xt>&lt;/number&gt;
+ * 	&lt;number&gt;</xt>3<xt>&lt;/number&gt;
+ * &lt;/array&gt;</xt></td>
+ * 			<td class='code'>List&lt;Integer&gt;, <jk>int</jk>[], Float[], Set&lt;Person&gt;</td>
+ * 		</tr>
+ * 		<tr>
+ * 			<td>number</td>
+ * 			<td>Numbers</td>
+ * 			<td class='code'>123</td>
+ * 			<td class='code'><xt>&lt;number&gt;</xt>123<xt>&lt;/number&gt;</xt></td>
+ * 			<td class='code'>Integer, Long, Float, <jk>int</jk></td>
+ * 		</tr>
+ * 		<tr>
+ * 			<td>boolean</td>
+ * 			<td>Booleans</td>
+ * 			<td class='code'><jk>true</jk></td>
+ * 			<td class='code'><xt>&lt;boolean&gt;</xt>true<xt>&lt;/boolean&gt;</xt></td>
+ * 			<td class='code'>Boolean</td>
+ * 		</tr>
+ * 		<tr>
+ * 			<td>string</td>
+ * 			<td>CharSequences</td>
+ * 			<td class='code'><js>'foobar'</js></td>
+ * 			<td class='code'><xt>&lt;string&gt;</xt>foobar<xt>&lt;/string&gt;</xt></td>
+ * 			<td class='code'>String, StringBuilder</td>
+ * 		</tr>
+ * 	</table>
+ * <p>
+ * 	In addition, any class types with {@link PojoFilter PojoFilters} associated with them on the registered
+ * 		{@link #getBeanContext() beanContext} can also be passed in.
+ * <p>
+ * 	For example, if the {@link CalendarFilter} filter is used to generalize {@code Calendar} objects to {@code String} objects.  When registered
+ * 	with this parser, you can construct {@code Calendar} objects from {@code Strings} using the following syntax...
+ * <p class='bcode'>
+ * 	Calendar c = parser.parse(<js>"'Sun Mar 03 04:05:06 EST 2001'"</js>, GregorianCalendar.<jk>class</jk>);
+ * <p>
+ * 	If <code>Object.<jk>class</jk></code> is specified as the target type, then the parser
+ * 	automatically determines the data types and generates the following object types...
+ * </p>
+ * <table class='styled'>
+ * 	<tr><th>JSON type</th><th>Class type</th></tr>
+ * 	<tr><td>object</td><td>{@link ObjectMap}</td></tr>
+ * 	<tr><td>array</td><td>{@link ObjectList}</td></tr>
+ * 	<tr><td>number</td><td>{@link Number} <br>(depending on length and format, could be {@link Integer}, {@link Double}, {@link Float}, etc...)</td></tr>
+ * 	<tr><td>boolean</td><td>{@link Boolean}</td></tr>
+ * 	<tr><td>string</td><td>{@link String}</td></tr>
+ * </table>
+ *
+ *
+ * <a id='SupportedTypes'></a><h6 class='topic'>Supported types</h6>
+ * <p>
+ * 	Several of the methods below take {@link Type} parameters to identify the type of
+ * 		object to create.  Any of the following types can be passed in to these methods...
+ * </p>
+ * <ul>
+ * 	<li>{@link ClassMeta}
+ * 	<li>{@link Class}
+ * 	<li>{@link ParameterizedType}
+ * 	<li>{@link GenericArrayType}
+ * </ul>
+ * <p>
+ * 	However, {@code ParameterizedTypes} and {@code GenericArrayTypes} should not contain
+ * 		{@link WildcardType WildcardTypes} or {@link TypeVariable TypeVariables}.
+ * <p>
+ * 	Passing in <jk>null</jk> or <code>Object.<jk>class</jk></code> typically signifies that it's up to the parser
+ * 	to determine what object type is being parsed parsed based on the rules above.
+
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ * @param <R> The input type (e.g. Reader or InputStream)
+ */
+public abstract class Parser<R> extends CoreApi {
+
+	/** General serializer properties currently set on this serializer. */
+	protected transient ParserProperties pp = new ParserProperties();
+	private transient List<ParserListener> listeners = new LinkedList<ParserListener>();
+	private String[] mediaTypes;
+
+	// Hidden constructor to force subclass from InputStreamParser or ReaderParser.
+	Parser() {}
+
+	//--------------------------------------------------------------------------------
+	// Abstract methods
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Workhorse method.  Subclasses are expected to implement this method.
+	 *
+	 * @param in The input stream or reader containing the input.
+	 * @param estimatedSize The estimated size of the input, or <code>-1</code> if unknown.
+	 * @param type The class type of the object to create.
+	 * 	If <jk>null</jk> or <code>Object.<jk>class</jk></code>, object type is based on what's being parsed.
+	 * 	For example, when parsing JSON text, it may return a <code>String</code>, <code>Number</code>, <code>ObjectMap</code>, etc...
+	 * @param ctx The runtime context object returned by {@link #createContext(ObjectMap, Method, Object)}.
+	 * 	If <jk>null</jk>, one will be created using {@link #createContext()}.
+	 * @param <T> The class type of the object to create.
+	 * @return The parsed object.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	protected abstract <T> T doParse(R in, int estimatedSize, ClassMeta<T> type, ParserContext ctx) throws ParseException, IOException;
+
+	/**
+	 * Returns <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
+	 *
+	 * @return <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
+	 */
+	public abstract boolean isReaderParser();
+
+	//--------------------------------------------------------------------------------
+	// Other methods
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Parses the content of the reader and creates an object of the specified type.
+	 *
+	 * @param in The input stream or reader containing the input.
+	 * @param estimatedSize The estimated size of the input, or <code>-1</code> if unknown.
+	 * @param type The class type of the object to create.
+	 * 	If <jk>null</jk> or <code>Object.<jk>class</jk></code>, object type is based on what's being parsed.
+	 * 	For example, when parsing JSON text, it may return a <code>String</code>, <code>Number</code>, <code>ObjectMap</code>, etc...
+	 * @param ctx The runtime context object returned by {@link #createContext(ObjectMap, Method, Object)}.
+	 * @param <T> The class type of the object to create.
+	 * @return The parsed object.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final <T> T parse(R in, int estimatedSize, ClassMeta<T> type, ParserContext ctx) throws ParseException, IOException {
+		try {
+			if (in == null)
+				throw new IOException("Null input stream or reader passed to parser.");
+			return doParse(in, estimatedSize, type, ctx);
+		} catch (RuntimeException e) {
+			throw new ParseException(e);
+		} finally {
+			ctx.close();
+		}
+	}
+
+	/**
+	 * Parses the content of the reader and creates an object of the specified type.
+	 * <p>
+	 * Equivalent to calling <code>parser.parse(in, type, <jk>null</jk>);</code>
+	 *
+	 * @param in The input stream or reader containing the input.
+	 * @param estimatedSize The estimated size of the input, or <code>-1</code> if unknown.
+	 * @param type The class type of the object to create.
+	 * 	If <jk>null</jk> or <code>Object.<jk>class</jk></code>, object type is based on what's being parsed.
+	 * 	For example, when parsing JSON text, it may return a <code>String</code>, <code>Number</code>, <code>ObjectMap</code>, etc...
+	 * @param <T> The class type of the object to create.
+	 * @return The parsed object.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final <T> T parse(R in, int estimatedSize, ClassMeta<T> type) throws ParseException, IOException {
+		ParserContext ctx = createContext();
+		return parse(in, estimatedSize, type, ctx);
+	}
+
+	/**
+	 * Parses input into the specified object type.
+	 *
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	MyBean b = p.parse(json, MyBean.<jk>class</jk>);
+	 * </p>
+	 * <p>
+	 * This method equivalent to the following code:
+	 * <p class='bcode'>
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	ClassMeta&lt;MyBean&gt; cm = p.getBeanContext().getClassMeta(MyBean.<jk>class</jk>);
+	 * 	MyBean b = p.parse(json, cm, <jk>null</jk>);
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param <T> The class type of the object to create.
+	 * @param in The input stream or reader containing the input.
+	 * @param estimatedSize The estimated size of the input, or <code>-1</code> if unknown.
+	 * @param type The class type of the object to create.
+	 * @return The parsed object.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final <T> T parse(R in, int estimatedSize, Class<T> type) throws ParseException, IOException {
+		ClassMeta<T> cm = getBeanContext().getClassMeta(type);
+		return parse(in, estimatedSize, cm);
+	}
+
+	/**
+	 * Parses input into a map with specified key and value types.
+	 *
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	Map&lt;String,MyBean&gt; m = p.parseMap(json, LinkedHashMap.<jk>class</jk>, String.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * </p>
+	 * 		<p>
+	 * 			A simpler approach is often to just extend the map class you want and just use the normal {@link #parse(Object, int, Class)} method:
+	 * </p>
+	 * <p class='bcode'>
+	 * 	<jk>public static class</jk> MyMap <jk>extends</jk> LinkedHashMap&lt;String,MyBean&gt; {}
+	 *
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	Map&lt;String,MyBean&gt; m = p.parse(json, MyMap.<jk>class</jk>);
+	 * </p>
+	 * <p>
+	 * This method equivalent to the following code:
+	 * 		</p>
+	 * <p class='bcode'>
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	ClassMeta&lt;Map&lt;String,MyBean&gt;&gt; cm = p.getBeanContext().getMapClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * 	Map&ltString,MyBean&gt; m = p.parse(json, cm, <jk>null</jk>);
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param <T> The class type of the object to create.
+	 * @param in The input stream or reader containing the input.
+	 * @param estimatedSize The estimated size of the input, or <code>-1</code> if unknown.
+	 * @param mapClass The map class type.
+	 * @param keyClass The key class type.
+	 * @param valueClass The value class type.
+	 * @return The parsed object.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final <K,V,T extends Map<K,V>> T parseMap(R in, int estimatedSize, Class<T> mapClass, Class<K> keyClass, Class<V> valueClass) throws ParseException, IOException {
+		ClassMeta<T> cm = getBeanContext().getMapClassMeta(mapClass, keyClass, valueClass);
+		return parse(in, estimatedSize, cm);
+	}
+
+	/**
+	 * Parses input into a collection with a specified element type.
+	 *
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	List&lt;MyBean&gt; l = p.parseCollection(json, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * </p>
+	 * 		<p>
+	 * A simpler approach is often to just extend the collection class you want and just use the normal {@link #parse(Object, int, Class)} method:
+	 * 		</p>
+	 * <p class='bcode'>
+	 * 	<jk>public static class</jk> MyBeanCollection <jk>extends</jk> LinkedList&lt;MyBean&gt; {}
+	 *
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	List&lt;MyBean&gt; l = p.parse(json, MyBeanCollection.<jk>class</jk>);
+	 * </p>
+	 * <p>
+	 * This method equivalent to the following code:
+	 * 		</p>
+	 * <p class='bcode'>
+	 * 	ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
+	 * 	ClassMeta&lt;List&lt;MyBean&gt;&gt; cm = p.getBeanContext().getCollectionClassMeta(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * 	List&lt;MyBean&gt; l = p.parse(json, cm, <jk>null</jk>);
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param <T> The class type of the object to create.
+	 * @param in The input stream or reader containing the input.
+	 * @param estimatedSize The estimated size of the input, or <code>-1</code> if unknown.
+	 * @param collectionClass The collection class type.
+	 * @param entryClass The class type of entries in the collection.
+	 * @return The parsed object.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final <E,T extends Collection<E>> T parseCollection(R in, int estimatedSize, Class<T> collectionClass, Class<E> entryClass) throws ParseException, IOException {
+		ClassMeta<T> cm = getBeanContext().getCollectionClassMeta(collectionClass, entryClass);
+		return parse(in, estimatedSize, cm);
+	}
+
+	/**
+	 * Create the context object that will be passed in to the parse method.
+	 * <p>
+	 * 	It's up to implementers to decide what the context object looks like, although typically
+	 * 	it's going to be a subclass of {@link ParserContext}.
+	 *
+	 * @param properties Optional additional properties.
+	 * @param javaMethod Java method that invoked this serializer.
+	 * 	When using the REST API, this is the Java method invoked by the REST call.
+	 * 	Can be used to access annotations defined on the method or class.
+	 * @param outer The outer object for instantiating top-level non-static inner classes.
+	 * @return The new context.
+	 */
+	public ParserContext createContext(ObjectMap properties, Method javaMethod, Object outer) {
+		return new ParserContext(getBeanContext(), pp, properties, javaMethod, outer);
+	}
+
+	/**
+	 * Create a basic context object without overriding properties or specifying <code>javaMethod</code>.
+	 * <p>
+	 * Equivalent to calling <code>createContext(<jk>null</jk>, <jk>null</jk>)</code>.
+	 *
+	 * @return The new context.
+	 */
+	protected final ParserContext createContext() {
+		return createContext(null, null, null);
+	}
+
+	//--------------------------------------------------------------------------------
+	// Other methods
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Adds a {@link ParserListener} to this parser to listen for parse events.
+	 *
+	 * @param listener The listener to associate with this parser.
+	 * @throws LockedException If {@link #lock()} was called on this object.
+	 * @return This object (for method chaining).
+	 */
+	public Parser<R> addListener(ParserListener listener) throws LockedException {
+		checkLock();
+		this.listeners.add(listener);
+		return this;
+	}
+
+	/**
+	 * Returns the current parser listeners associated with this parser.
+	 *
+	 * @return The current list of parser listeners.
+	 */
+	public List<ParserListener> getListeners() {
+		return listeners;
+	}
+
+	/**
+	 * Converts the specified string to the specified type.
+	 *
+	 * @param outer The outer object if we're converting to an inner object that needs to be created within the context of an outer object.
+	 * @param s The string to convert.
+	 * @param type The class type to convert the string to.
+	 * @return The string converted as an object of the specified type.
+	 * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+	 * @param <T> The class type to convert the string to.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	protected <T> T convertAttrToType(Object outer, String s, ClassMeta<T> type) throws ParseException {
+		if (s == null)
+			return null;
+
+		if (type == null)
+			type = (ClassMeta<T>)object();
+		PojoFilter filter = type.getPojoFilter();
+		ClassMeta<?> gType = type.getFilteredClassMeta();
+
+		Object o = s;
+		if (gType.isChar())
+			o = s.charAt(0);
+		else if (gType.isNumber())
+			o = parseNumber(s, (Class<? extends Number>)gType.getInnerClass());
+		else if (gType.isBoolean())
+			o = Boolean.parseBoolean(s);
+		else if (! (gType.isCharSequence() || gType.isObject())) {
+			if (gType.canCreateNewInstanceFromString(outer)) {
+				try {
+					o = gType.newInstanceFromString(outer, s);
+				} catch (Exception e) {
+					throw new ParseException("Unable to construct new object of type ''{0}'' from input string ''{1}''", type, s).initCause(e);
+				}
+			} else {
+				throw new ParseException("Invalid conversion from string to class ''{0}''", type);
+			}
+		}
+
+		if (filter != null)
+			o = filter.unfilter(o, type);
+
+
+		return (T)o;
+	}
+
+	/**
+	 * Convenience method for calling the {@link ParentProperty @ParentProperty} method on
+	 * the specified object if it exists.
+	 *
+	 * @param cm The class type of the object.
+	 * @param o The object.
+	 * @param parent The parent to set.
+	 * @throws ParseException
+	 */
+	protected void setParent(ClassMeta<?> cm, Object o, Object parent) throws ParseException {
+		Method m = cm.getParentProperty();
+		if (m != null) {
+			try {
+				m.invoke(o, parent);
+			} catch (Exception e) {
+				throw new ParseException(e);
+			}
+		}
+	}
+
+	/**
+	 * Convenience method for calling the {@link NameProperty @NameProperty} method on
+	 * the specified object if it exists.
+	 *
+	 * @param cm The class type of the object.
+	 * @param o The object.
+	 * @param name The name to set.
+	 * @throws ParseException
+	 */
+	protected void setName(ClassMeta<?> cm, Object o, Object name) throws ParseException {
+		Method m = cm.getNameProperty();
+		if (m != null) {
+			try {
+				m.invoke(o, name);
+			} catch (Exception e) {
+				throw new ParseException(e);
+			}
+		}
+	}
+
+
+	/**
+	 * Method that gets called when an unknown bean property name is encountered.
+	 *
+	 * @param ctx The parser context.
+	 * @param propertyName The unknown bean property name.
+	 * @param beanMap The bean that doesn't have the expected property.
+	 * @param line The line number where the property was found.  <code>-1</code> if line numbers are not available.
+	 * @param col The column number where the property was found.  <code>-1</code> if column numbers are not available.
+	 * @throws ParseException Automatically thrown if {@link BeanContextProperties#BEAN_ignoreUnknownBeanProperties} setting
+	 * 	on this parser is <jk>false</jk>
+	 * @param <T> The class type of the bean map that doesn't have the expected property.
+	 */
+	protected <T> void onUnknownProperty(ParserContext ctx, String propertyName, BeanMap<T> beanMap, int line, int col) throws ParseException {
+		if (propertyName.equals("uri") || propertyName.equals("type") || propertyName.equals("_class"))
+			return;
+		if (! ctx.getBeanContext().isIgnoreUnknownBeanProperties())
+			throw new ParseException(line, col, "Unknown property ''{0}'' encountered while trying to parse into class ''{1}''", propertyName, beanMap.getClassMeta());
+		if (listeners.size() > 0)
+			for (ParserListener listener : listeners)
+				listener.onUnknownProperty(propertyName, beanMap.getClassMeta().getInnerClass(), beanMap.getBean(), line, col);
+	}
+
+
+	/**
+	 * Returns the media types handled based on the value of the {@link Consumes} annotation on the parser class.
+	 * <p>
+	 * This method can be overridden by subclasses to determine the media types programatically.
+	 *
+	 * @return The list of media types.  Never <jk>null</jk>.
+	 */
+	public String[] getMediaTypes() {
+		if (mediaTypes == null) {
+			Consumes c = ReflectionUtils.getAnnotation(Consumes.class, getClass());
+			if (c == null)
+				throw new RuntimeException(MessageFormat.format("Class ''{0}'' is missing the @Consumes annotation", getClass().getName()));
+			mediaTypes = c.value();
+		}
+		return mediaTypes;
+	}
+
+
+	//--------------------------------------------------------------------------------
+	// Overridden methods
+	//--------------------------------------------------------------------------------
+
+
+	@Override /* CoreApi */
+	public Parser<R> setProperty(String property, Object value) throws LockedException {
+		super.setProperty(property, value);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public Parser<R> addNotBeanClasses(Class<?>...classes) throws LockedException {
+		super.addNotBeanClasses(classes);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public Parser<R> addFilters(Class<?>...classes) throws LockedException {
+		super.addFilters(classes);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public <T> Parser<R> addImplClass(Class<T> interfaceClass, Class<? extends T> implClass) throws LockedException {
+		super.addImplClass(interfaceClass, implClass);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public Parser<R> setClassLoader(ClassLoader classLoader) throws LockedException {
+		super.setClassLoader(classLoader);
+		return this;
+	}
+
+	@Override /* Lockable */
+	public Parser<R> lock() {
+		super.lock();
+		return this;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override /* Lockable */
+	public Parser<R> clone() throws CloneNotSupportedException {
+		return (Parser<R>)super.clone();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.class
new file mode 100755
index 0000000..788eb28
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.java
new file mode 100755
index 0000000..30b2365
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserContext.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.logging.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.serializer.*;
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Context object that lives for the duration of a single parsing of {@link Parser} and its subclasses.
+ * <p>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public class ParserContext {
+
+	private static Logger logger = Logger.getLogger(ParserContext.class.getName());
+
+	private boolean debug, closed;
+	private final BeanContext beanContext;
+	private final List<String> warnings = new LinkedList<String>();
+
+	private ObjectMap properties;
+	private Method javaMethod;
+	private Object outer;
+
+	/**
+	 * Create a new parser context with the specified options.
+	 *
+	 * @param beanContext The bean context being used.
+	 * @param pp The default parser properties.
+	 * @param properties The override properties.
+	 * @param javaMethod The java method that called this parser, usually the method in a REST servlet.
+	 * @param outer The outer object for instantiating top-level non-static inner classes.
+	 */
+	public ParserContext(BeanContext beanContext, ParserProperties pp, ObjectMap properties, Method javaMethod, Object outer) {
+		this.debug = pp.debug;
+		this.beanContext = beanContext;
+		this.properties = properties;
+		this.javaMethod = javaMethod;
+		this.outer = outer;
+	}
+
+	/**
+	 * Returns the bean context associated with this context.
+	 *
+	 * @return The bean context associated with this context.
+	 */
+	public final BeanContext getBeanContext() {
+		return beanContext;
+	}
+
+	/**
+	 * Returns the Java method that invoked this parser.
+	 * <p>
+	 * When using the REST API, this is the Java method invoked by the REST call.
+	 * Can be used to access annotations defined on the method or class.
+	 *
+	 * @return The Java method that invoked this parser.
+	*/
+	public final Method getJavaMethod() {
+		return javaMethod;
+	}
+
+	/**
+	 * Returns the outer object used for instantiating top-level non-static member classes.
+	 * When using the REST API, this is the servlet object.
+	 *
+	 * @return The outer object.
+	*/
+	public final Object getOuter() {
+		return outer;
+	}
+
+	/**
+	 * Returns the {@link SerializerProperties#SERIALIZER_debug} setting value in this context.
+	 *
+	 * @return The {@link SerializerProperties#SERIALIZER_debug} setting value in this context.
+	 */
+	public final boolean isDebug() {
+		return debug;
+	}
+
+	/**
+	 * Returns the runtime properties associated with this context.
+	 *
+	 * @return The runtime properties associated with this context.
+	 */
+	public final ObjectMap getProperties() {
+		return properties;
+	}
+
+	/**
+	 * Logs a warning message.
+	 *
+	 * @param msg The warning message.
+	 * @param args Optional printf arguments to replace in the error message.
+	 */
+	public void addWarning(String msg, Object... args) {
+		msg = args.length == 0 ? msg : String.format(msg, args);
+		logger.warning(msg);
+		warnings.add(warnings.size() + 1 + ": " + msg);
+	}
+
+	/**
+	 * Perform cleanup on this context object if necessary.
+	 *
+	 * @throws ParseException
+	 */
+	public void close() throws ParseException {
+		if (closed)
+			throw new ParseException("Attempt to close ParserContext more than once.");
+		if (debug && warnings.size() > 0)
+			throw new ParseException("Warnings occurred during parsing: \n" + StringUtils.join(warnings, "\n"));
+	}
+
+	@Override /* Object */
+	protected void finalize() throws Throwable {
+		if (! closed)
+			throw new RuntimeException("ParserContext was not closed.");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup$ParserEntry.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup$ParserEntry.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup$ParserEntry.class
new file mode 100755
index 0000000..01c92d0
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup$ParserEntry.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.class
new file mode 100755
index 0000000..85a3152
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.java
new file mode 100755
index 0000000..225eb77
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserGroup.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import static com.ibm.juno.core.utils.ArrayUtils.*;
+
+import java.util.*;
+
+import com.ibm.juno.core.*;
+
+/**
+ * Represents a group of {@link Parser Parsers} that can be looked up by media type.
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ * 	Provides the following features:
+ * <ul>
+ * 	<li>Finds parsers based on HTTP <code>Content-Type</code> header values.
+ * 	<li>Sets common properties on all parsers in a single method call.
+ * 	<li>Locks all parsers in a single method call.
+ * 	<li>Clones existing groups and all parsers within the group in a single method call.
+ * </ul>
+ *
+ *
+ * <h6 class='topic'>Match ordering</h6>
+ * <p>
+ * 	Parsers are matched against <code>Content-Type</code> strings in the order they exist in this group.
+ * <p>
+ * 	Adding new entries will cause the entries to be prepended to the group.
+ *  	This allows for previous parsers to be overridden through subsequent calls.
+ * <p>
+ * 	For example, calling <code>g.append(P1.<jk>class</jk>,P2.<jk>class</jk>).append(P3.<jk>class</jk>,P4.<jk>class</jk>)</code>
+ * 	will result in the order <code>P3, P4, P1, P2</code>.
+ *
+ *
+ * <h6 class='topic'>Examples</h6>
+ * <p class='bcode'>
+ * 	<jc>// Construct a new parser group</jc>
+ * 	ParserGroup g = <jk>new</jk> ParserGroup();
+ *
+ * 	<jc>// Add some parsers to it</jc>
+ * 	g.append(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
+ *
+ * 	<jc>// Change settings on parsers simultaneously</jc>
+ * 	g.setProperty(BeanContextProperties.<jsf>BEAN_beansRequireSerializable</jsf>, <jk>true</jk>)
+ * 		.addFilters(CalendarFilter.ISO8601DT.<jk>class</jk>)
+ * 		.lock();
+ *
+ * 	<jc>// Find the appropriate parser by Content-Type</jc>
+ * 	ReaderParser p = (ReaderParser)g.getParser(<js>"text/json"</js>);
+ *
+ * 	<jc>// Parse a bean from JSON</jc>
+ * 	String json = <js>"{...}"</js>;
+ * 	AddressBook addressBook = p.parse(json, AddressBook.<jk>class</jk>);
+ * </p>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class ParserGroup extends Lockable {
+
+	private transient Map<String,ParserEntry> entryMap = new HashMap<String,ParserEntry>();
+	private transient LinkedList<ParserEntry> tempEntries = new LinkedList<ParserEntry>();
+	private transient ParserEntry[] entries;
+
+
+	/**
+	 * Registers the specified REST parsers with this parser group.
+	 *
+	 * @param p The parsers to append to this group.
+	 * @return This object (for method chaining).
+	 */
+	public ParserGroup append(Parser<?>...p) {
+		checkLock();
+		entries = null;
+		for (Parser<?> pp : reverse(p))  {
+			ParserEntry e = new ParserEntry(pp);
+			tempEntries.addFirst(e);
+			for (String mediaType : e.mediaTypes)
+				entryMap.put(mediaType, e);
+		}
+		return this;
+	}
+
+	/**
+	 * Same as {@link #append(Parser[])}, except specify classes instead of class instances
+	 * 	 of {@link Parser}.
+	 * <p>
+	 * Note that this can only be used on {@link Parser Parsers} with no-arg constructors.
+	 *
+	 * @param p The parsers to append to this group.
+	 * @return This object (for method chaining).
+	 * @throws Exception Thrown if {@link Parser} could not be constructed.
+	 */
+	public ParserGroup append(Class<? extends Parser<?>>...p) throws Exception {
+		checkLock();
+		for (Class<? extends Parser<?>> c : reverse(p)) {
+			try {
+			append(c.newInstance());
+			} catch (NoClassDefFoundError e) {
+				// Ignore if dependent library not found (e.g. Jena).
+				System.err.println(e);
+			}
+		}
+		return this;
+	}
+
+	/**
+	 * Same as {@link #append(Class[])}, except specify a single class to avoid unchecked compile warnings.
+	 *
+	 * @param p The parser to append to this group.
+	 * @return This object (for method chaining).
+	 * @throws Exception Thrown if {@link Parser} could not be constructed.
+	 */
+	public ParserGroup append(Class<? extends Parser<?>> p) throws Exception {
+		checkLock();
+		try {
+		append(p.newInstance());
+		} catch (NoClassDefFoundError e) {
+			// Ignore if dependent library not found (e.g. Jena).
+			System.err.println(e);
+		}
+		return this;
+	}
+
+	/**
+	 * Returns the parser registered to handle the specified media type.
+	 * <p>
+	 * The media-type string must not contain any parameters such as <js>";charset=X"</js>.
+	 *
+	 * @param mediaType The media-type string (e.g. <js>"text/json"</js>).
+	 * @return The REST parser that handles the specified request content type, or <jk>null</jk> if
+	 * 		no parser is registered to handle it.
+	 */
+	public Parser<?> getParser(String mediaType) {
+		ParserEntry e = entryMap.get(mediaType);
+		return (e == null ? null : e.parser);
+	}
+
+	/**
+	 * Searches the group for a parser that can handle the specified media type.
+	 *
+	 * @param mediaType The accept string.
+	 * @return The media type registered by one of the parsers that matches the <code>mediaType</code> string,
+	 * 	or <jk>null</jk> if no media types matched.
+	 */
+	public String findMatch(String mediaType) {
+		MediaRange[] mr = MediaRange.parse(mediaType);
+		if (mr.length == 0)
+			mr = MediaRange.parse("*/*");
+
+		for (MediaRange a : mr)
+			for (ParserEntry e : getEntries())
+				for (MediaRange a2 : e.mediaRanges)
+					if (a.matches(a2))
+						return a2.getMediaType();
+
+		return null;
+	}
+
+	/**
+	 * Returns the media types that all parsers in this group can handle
+	 * <p>
+	 * Entries are ordered in the same order as the parsers in the group.
+	 *
+	 * @return The list of media types.
+	 */
+	public List<String> getSupportedMediaTypes() {
+		List<String> l = new ArrayList<String>();
+		for (ParserEntry e : getEntries())
+			for (String mt : e.mediaTypes)
+				if (! l.contains(mt))
+					l.add(mt);
+		return l;
+	}
+
+	private ParserEntry[] getEntries() {
+		if (entries == null)
+			entries = tempEntries.toArray(new ParserEntry[tempEntries.size()]);
+		return entries;
+	}
+
+	static class ParserEntry {
+		Parser<?> parser;
+		MediaRange[] mediaRanges;
+		String[] mediaTypes;
+
+		ParserEntry(Parser<?> p) {
+			parser = p;
+
+			mediaTypes = new String[p.getMediaTypes().length];
+			int i = 0;
+			for (String mt : p.getMediaTypes())
+				mediaTypes[i++] = mt.toLowerCase(Locale.ENGLISH);
+
+			List<MediaRange> l = new LinkedList<MediaRange>();
+			for (i = 0; i < mediaTypes.length; i++)
+				l.addAll(Arrays.asList(MediaRange.parse(mediaTypes[i])));
+			mediaRanges = l.toArray(new MediaRange[l.size()]);
+		}
+	}
+
+
+	//--------------------------------------------------------------------------------
+	// Convenience methods for setting properties on all parsers.
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Shortcut for calling {@link Parser#setProperty(String, Object)} on all parsers in this group.
+	 *
+	 * @param property The property name.
+	 * @param value The property value.
+	 * @throws LockedException If {@link #lock()} was called on this object.
+	 * @return This object (for method chaining).
+	 */
+	public ParserGroup setProperty(String property, Object value) throws LockedException {
+		checkLock();
+		for (ParserEntry e : getEntries())
+			e.parser.setProperty(property, value);
+		return this;
+	}
+
+	/**
+	 * Shortcut for calling {@link Parser#setProperties(ObjectMap)} on all parsers in this group.
+	 *
+	 * @param properties The properties to set.  Ignored if <jk>null</jk>.
+	 * @throws LockedException If {@link #lock()} was called on this object.
+	 * @return This object (for method chaining).
+	 */
+	public ParserGroup setProperties(ObjectMap properties) {
+		checkLock();
+		if (properties != null)
+			for (Map.Entry<String,Object> e : properties.entrySet())
+				setProperty(e.getKey(), e.getValue());
+		return this;
+	}
+
+	/**
+	 * Shortcut for calling {@link Parser#addNotBeanClasses(Class[])} on all parsers in this group.
+	 *
+	 * @param classes The classes to specify as not-beans to the underlying bean context of all parsers in this group.
+	 * @throws LockedException If {@link #lock()} was called on this object.
+	 * @return This object (for method chaining).
+	 */
+	public ParserGroup addNotBeanClasses(Class<?>...classes) throws LockedException {
+		checkLock();
+		for (ParserEntry e : getEntries())
+			e.parser.addNotBeanClasses(classes);
+		return this;
+	}
+
+	/**
+	 * Shortcut for calling {@link Parser#addFilters(Class[])} on all parsers in this group.
+	 *
+	 * @param classes The classes to add bean filters for to the underlying bean context of all parsers in this group.
+	 * @throws LockedException If {@link #lock()} was called on this object.
+	 * @return This object (for method chaining).
+	 */
+	public ParserGroup addFilters(Class<?>...classes) throws LockedException {
+		checkLock();
+		for (ParserEntry e : getEntries())
+			e.parser.addFilters(classes);
+		return this;
+	}
+
+	/**
+	 * Shortcut for calling {@link Parser#addImplClass(Class, Class)} on all parsers in this group.
+	 *
+	 * @param <T> The interface or abstract class type.
+	 * @param interfaceClass The interface or abstract class.
+	 * @param implClass The implementation class.
+	 * @throws LockedException If {@link #lock()} was called on this object.
+	 * @return This object (for method chaining).
+	 */
+	public <T> ParserGroup addImplClass(Class<T> interfaceClass, Class<? extends T> implClass) throws LockedException {
+		checkLock();
+		for (ParserEntry e : getEntries())
+			e.parser.addImplClass(interfaceClass, implClass);
+		return this;
+	}
+
+	//--------------------------------------------------------------------------------
+	// Overridden methods
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Locks this group and all parsers in this group.
+	 */
+	@Override /* Lockable */
+	public ParserGroup lock() {
+		super.lock();
+		for (ParserEntry e : getEntries())
+			e.parser.lock();
+		return this;
+	}
+
+	/**
+	 * Clones this group and all parsers in this group.
+	 */
+	@Override /* Lockable */
+	public ParserGroup clone() throws CloneNotSupportedException {
+		ParserGroup c = (ParserGroup)super.clone();
+		c.entryMap = new HashMap<String,ParserEntry>();
+		c.tempEntries = new LinkedList<ParserEntry>();
+		c.entries = null;
+		ParserEntry[] e = getEntries();
+		for (int i = e.length-1; i >= 0; i--)
+			c.append(e[i].parser.clone());
+		return c;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.class
new file mode 100755
index 0000000..1e80272
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.java
new file mode 100755
index 0000000..8b24cc1
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import com.ibm.juno.core.*;
+
+/**
+ * Class for listening for certain parse events during a document parse.
+ * <p>
+ * 	Listeners can be registered with parsers through the {@link Parser#addListener(ParserListener)} method.
+ * </p>
+ * 	It should be noted that listeners are not automatically copied over to new parsers when a parser is cloned.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public class ParserListener {
+
+	/**
+	 * Gets called when an unknown bean property is detected in a document.
+	 * <p>
+	 * 	This method only gets called if {@link BeanContextProperties#BEAN_ignoreUnknownBeanProperties} setting is <jk>true</jk>.
+	 * 	Otherwise, the parser will throw a {@link ParseException}.
+	 *
+	 * @param <T> The class type of the bean.
+	 * @param propertyName The property name encountered in the document.
+	 * @param beanClass The bean class.
+	 * @param bean The bean.
+	 * @param line The line number where the unknown property was found (-1 if parser doesn't support line/column indicators).
+	 * @param col The column number where the unknown property was found (-1 if parser doesn't support line/column indicators).
+	 */
+	public <T> void onUnknownProperty(String propertyName, Class<T> beanClass, T bean, int line, int col) {
+		// Do something with information
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.class
new file mode 100755
index 0000000..d02c9bc
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.java
new file mode 100755
index 0000000..0392b51
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserProperties.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import com.ibm.juno.core.*;
+
+/**
+ * Configurable properties common to all {@link Parser} classes.
+ * <p>
+ * 	Use the {@link Parser#setProperty(String, Object)} method to set property values.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class ParserProperties implements Cloneable {
+
+	/**
+	 * Debug mode ({@link Boolean}, default=<jk>false</jk>).
+	 * <p>
+	 * Enables the following additional information during parsing:
+	 * <ul>
+	 * 	<li>When bean setters throws exceptions, the exception includes the object stack information
+	 * 		in order to determine how that method was invoked.
+	 * </ul>
+	 */
+	public static final String PARSER_debug = "Parser.debug";
+
+	boolean
+		debug = false;
+
+	/**
+	 * Sets the specified property value.
+	 *
+	 * @param property The property name.
+	 * @param value The property value.
+	 * @return <jk>true</jk> if property name was valid and property was set.
+	 */
+	public boolean setProperty(String property, Object value) {
+		BeanContext bc = BeanContext.DEFAULT;
+		if (property.equals(PARSER_debug))
+			debug = bc.convertToType(value, Boolean.class);
+		else
+			return false;
+		return true;
+	}
+
+
+	@Override /* Object */
+	public ParserProperties clone() throws CloneNotSupportedException {
+		return (ParserProperties)super.clone();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.class
new file mode 100755
index 0000000..9dd18f7
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.java
new file mode 100755
index 0000000..18b9478
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ParserReader.java
@@ -0,0 +1,379 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.parser;
+
+import java.io.*;
+
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Similar to a {@link java.io.PushbackReader} with a pushback buffer of 1 character.
+ * <p>
+ * 	Code is optimized to work with a 1 character buffer.
+ * <p>
+ * 	Additionally keeps track of current line and column number, and provides the ability to set
+ * 	mark points and capture characters from the previous mark point.
+ * <p>
+ * 	<b>Warning:</b>  Not thread safe.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public class ParserReader extends Reader {
+
+	/** Wrapped reader */
+	protected Reader r;
+
+	private char[] buff;       // Internal character buffer
+	private int line = 1;      // Current line number
+	private int column;        // Current column number
+	private int iCurrent = 0;  // Current pointer into character buffer
+	private int iMark = -1;    // Mark position in buffer
+	private int iEnd = 0;      // The last good character position in the buffer
+	private boolean endReached, holesExist;
+
+	ParserReader() {}
+
+	/**
+	 * Constructor for input from a {@link CharSequence}.
+	 *
+	 * @param in The character sequence being read from.
+	 */
+	public ParserReader(CharSequence in) {
+		this.r = new CharSequenceReader(in);
+		if (in == null)
+			this.buff = new char[0];
+		else
+			this.buff = new char[in.length() < 1024 ? in.length() : 1024];
+	}
+
+	/**
+	 * Constructor for input from a {@link Reader}).
+	 *
+	 * @param r The Reader being wrapped.
+	 * @param buffSize The buffer size to use for the buffered reader.
+	 */
+	public ParserReader(Reader r, int buffSize) {
+		if (r instanceof ParserReader)
+			this.r = ((ParserReader)r).r;
+		else
+			this.r = r;
+		this.buff = new char[buffSize <= 0 ? 1024 : Math.max(buffSize, 20)];
+	}
+
+	/**
+	 * Returns the current line number position in this reader.
+	 *
+	 * @return The current line number.
+	 */
+	public final int getLine() {
+		return line;
+	}
+
+	/**
+	 * Returns the current column number position in this reader.
+	 *
+	 * @return The current column number.
+	 */
+	public final int getColumn() {
+		return column;
+	}
+
+	/**
+	 * Reads a single character.
+	 * Note that this method does NOT process extended unicode characters (i.e. characters
+	 * 	above 0x10000), but rather returns them as two <jk>char</jk>s.
+	 * Use {@link #readCodePoint()} to ensure proper handling of extended unicode.
+	 *
+	 * @return The character read, or -1 if the end of the stream has been reached.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	@Override /* Reader */
+	public final int read() throws IOException {
+		int c = readFromBuff();
+		if (c == -1)
+			return -1;
+		if (c == '\n') {
+			line++;
+			column = 0;
+		} else {
+			column++;
+		}
+		return c;
+	}
+
+	/**
+	 * Same as {@link #read()} but detects and combines extended unicode characters (i.e. characters
+	 * 	above 0x10000).
+	 *
+	 * @return The character read, or -1 if the end of the stream has been reached.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final int readCodePoint() throws IOException {
+		int c = read();
+
+		// Characters that take up 2 chars.
+		if (c >= 0xd800 && c <= 0xdbff) {
+			int low = read();
+			if (low >= 0xdc00 && low <= 0xdfff)
+				c = 0x10000 + ((c - 0xd800) << 10) + (low - 0xdc00);
+		}
+
+		return c;
+	}
+
+	private final int readFromBuff() throws IOException {
+		while (iCurrent >= iEnd) {
+			if (endReached)
+				return -1;
+
+			// If there's still space at the end of this buffer, fill it.
+			// Make sure there's at least 2 character spaces free for extended unicode characters.
+			//if (false) {
+			if (iEnd+1 < buff.length) {
+				int x = read(buff, iCurrent, buff.length-iEnd);
+				if (x == -1) {
+					endReached = true;
+					return -1;
+				}
+				iEnd += x;
+
+			} else {
+				// If we're currently marking, then we want to copy from the current mark point
+				// to the beginning of the buffer and then fill in the remainder of buffer.
+				if (iMark >= 0) {
+
+					// If we're marking from the beginning of the array, we double the size of the
+					// buffer.  This isn't likely to occur often.
+					if (iMark == 0) {
+						char[] buff2 = new char[buff.length<<1];
+						System.arraycopy(buff, 0, buff2, 0, buff.length);
+						buff = buff2;
+
+					// Otherwise, we copy what's currently marked to the beginning of the buffer.
+					} else {
+						int copyBuff = iMark;
+						System.arraycopy(buff, copyBuff, buff, 0, buff.length - copyBuff);
+						iCurrent -= copyBuff;
+						iMark -= copyBuff;
+					}
+					int expected = buff.length - iCurrent;
+
+					int x = read(buff, iCurrent, expected);
+					if (x == -1) {
+						endReached = true;
+						iEnd = iCurrent;
+						return -1;
+					}
+					iEnd = iCurrent + x;
+				} else {
+					// Copy the last 10 chars in the buffer to the beginning of the buffer.
+					int copyBuff = Math.min(iCurrent, 10);
+					System.arraycopy(buff, iCurrent-copyBuff, buff, 0, copyBuff);
+
+					// Number of characters we expect to copy on the next read.
+					int expected = buff.length - copyBuff;
+					int x = read(buff, copyBuff, expected);
+					iCurrent = copyBuff;
+					if (x == -1) {
+						endReached = true;
+						iEnd = iCurrent;
+						return -1;
+					}
+					iEnd = iCurrent + x;
+				}
+			}
+		}
+		return buff[iCurrent++];
+	}
+
+	/**
+	 * Start buffering the calls to read() so that the text can be gathered from the mark
+	 * point on calling {@code getFromMarked()}.
+	 */
+	public final void mark() {
+		iMark = iCurrent;
+	}
+
+
+	/**
+	 * Peeks the next character in the stream.
+	 * <p>
+	 * 	This is equivalent to doing a {@code read()} followed by an {@code unread()}.
+	 *
+	 * @return The peeked character, or (char)-1 if the end of the stream has been reached.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final int peek() throws IOException {
+		int c = read();
+		if (c != -1)
+			unread();
+		return c;
+	}
+
+	/**
+	 * Read the specified number of characters off the stream.
+	 *
+	 * @param num The number of characters to read.
+	 * @return The characters packaged as a String.
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final String read(int num) throws IOException {
+		char[] c = new char[num];
+		for (int i = 0; i < num; i++) {
+			int c2 = read();
+			if (c2 == -1)
+				return new String(c, 0, i);
+			c[i] = (char)c2;
+		}
+		return new String(c);
+	}
+
+	/**
+	 * Pushes the last read character back into the stream.
+	 *
+	 * @return This object (for method chaining).
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	public final ParserReader unread() throws IOException {
+		if (iCurrent <= 0)
+			throw new IOException("Buffer underflow.");
+		iCurrent--;
+		column--;
+		return this;
+	}
+
+	/**
+	 * Close this reader and the underlying reader.
+	 *
+	 * @throws IOException If a problem occurred trying to read from the reader.
+	 */
+	@Override /* Reader */
+	public void close() throws IOException {
+		r.close();
+	}
+
+	/**
+	 * Returns the contents of the reusable character buffer as a string, and
+	 * resets the buffer for next usage.
+	 *
+	 * @return The contents of the reusable character buffer as a string.
+	 */
+	public final String getMarked() {
+		return getMarked(0, 0);
+	}
+
+	/**
+	 * Same as {@link #getMarked()} except allows you to specify offsets
+	 * 	into the buffer.
+	 * <p>
+	 * For example, to return the marked string, but trim the first and last characters,
+	 * 	call the following:
+	 * <p class='bcode'>
+	 * 	getFromMarked(1, -1);
+	 * </p>
+	 *
+	 * @param offsetStart The offset of the start position.
+	 * @param offsetEnd The offset of the end position.
+	 * @return The contents of the reusable character buffer as a string.
+	 */
+	public final String getMarked(int offsetStart, int offsetEnd) {
+		int offset = 0;
+
+		// Holes are \u00FF 'delete' characters that we need to get rid of now.
+		if (holesExist) {
+			for (int i = iMark; i < iCurrent; i++) {
+				char c = buff[i];
+				if (c == 127)
+					offset++;
+				else
+					buff[i-offset] = c;
+			}
+			holesExist = false;
+		}
+		int start = iMark + offsetStart, len = iCurrent - iMark + offsetEnd - offsetStart - offset;
+		String s = new String(buff, start, len);
+		iMark = -1;
+		return s;
+	}
+
+	/**
+	 * Trims off the last character in the marking buffer.
+	 * Useful for removing escape characters from sequences.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public final ParserReader delete() {
+		return delete(1);
+	}
+
+	/**
+	 * Trims off the specified number of last characters in the marking buffer.
+	 * Useful for removing escape characters from sequences.
+	 *
+	 * @param count The number of characters to delete.
+	 * @return This object (for method chaining).
+	 */
+	public final ParserReader delete(int count) {
+		for (int i = 0; i < count; i++)
+			buff[iCurrent-i-1] = 127;
+		holesExist = true;
+		return this;
+	}
+
+	/**
+	 * Replaces the last character in the marking buffer with the specified character.
+	 * <code>offset</code> must be at least <code>1</code> for normal characters, and
+	 * <code>2</code> for extended unicode characters in order for the replacement
+	 * to fit into the buffer.
+	 *
+	 * @param c The new character.
+	 * @param offset The offset.
+	 * @return This object (for method chaining).
+	 * @throws IOException
+	 */
+	public final ParserReader replace(int c, int offset) throws IOException {
+		if (c < 0x10000) {
+			if (offset < 1)
+				throw new IOException("Buffer underflow.");
+			buff[iCurrent-offset] = (char)c;
+		} else {
+			if (offset < 2)
+				throw new IOException("Buffer underflow.");
+			c -= 0x10000;
+			buff[iCurrent-offset] = (char)(0xd800 + (c >> 10));
+			buff[iCurrent-offset+1] = (char)(0xdc00 + (c & 0x3ff));
+			offset--;
+		}
+		// Fill in the gap with DEL characters.
+		for (int i = 1; i < offset; i++)
+			buff[iCurrent-i] = 127;
+		holesExist |= (offset > 1);
+		return this;
+	}
+
+	/**
+	 * Replace the last read character in the buffer with the specified character.
+	 *
+	 * @param c The new character.
+	 * @return This object (for method chaining).
+	 * @throws IOException
+	 */
+	public final ParserReader replace(char c) throws IOException {
+		return replace(c, 1);
+	}
+
+	/**
+	 * Subclasses can override this method to provide additional filtering (e.g. {#link UrlEncodingParserReader}).
+	 * Default implementation simply calls the same method on the underlying reader.
+	 */
+	@Override /* Reader */
+	public int read(char[] cbuf, int off, int len) throws IOException {
+		return r.read(cbuf, off, len);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ReaderParser.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ReaderParser.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ReaderParser.class
new file mode 100755
index 0000000..430fce6
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/parser/ReaderParser.class differ


Mime
View raw message