http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
index f632c84..4a8177d 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
@@ -14,20 +14,20 @@ package org.apache.juneau.msgpack;
 
 import static org.apache.juneau.msgpack.MsgPackSerializerContext.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link 
MsgPackSerializer}.
  *
  * <p>
- * This class is NOT thread safe.  It is meant to be discarded after one-time 
use.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused 
within the same thread.
  */
-public final class MsgPackSerializerSession extends SerializerSession {
+public final class MsgPackSerializerSession extends 
OutputStreamSerializerSession {
 
        private final boolean
                addBeanTypeProperties;
@@ -38,28 +38,20 @@ public final class MsgPackSerializerSession extends 
SerializerSession {
         * @param ctx
         *      The context creating this session object.
         *      The context contains all the configuration settings for this 
object.
-        * @param op
-        *      The override properties.
-        *      These override any context properties defined in the context.
-        * @param javaMethod The java method that called this serializer, 
usually the method in a REST servlet.
-        * @param locale
-        *      The session locale.
-        *      If <jk>null</jk>, then the locale defined on the context is 
used.
-        * @param timeZone
-        *      The session timezone.
-        *      If <jk>null</jk>, then the timezone defined on the context is 
used.
-        * @param mediaType The session media type (e.g. 
<js>"application/json"</js>).
-        * @param uriContext
-        *      The URI context.
-        *      Identifies the current request URI used for resolution of URIs 
to absolute or root-relative form.
+        * @param args
+        *      Runtime arguments.
+        *      These specify session-level information such as locale and URI 
context.
+        *      It also include session-level properties that override the 
properties defined on the bean and
+        *      serializer contexts.
+        *      <br>If <jk>null</jk>, defaults to {@link 
SerializerSessionArgs#DEFAULT}.
         */
-       protected MsgPackSerializerSession(MsgPackSerializerContext ctx, 
ObjectMap op, Method javaMethod,
-                       Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
-               super(ctx, op, javaMethod, locale, timeZone, mediaType, 
uriContext);
-               if (op == null || op.isEmpty()) {
+       protected MsgPackSerializerSession(MsgPackSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+               ObjectMap p = getProperties();
+               if (p.isEmpty()) {
                        addBeanTypeProperties = ctx.addBeanTypeProperties;
                } else {
-                       addBeanTypeProperties = 
op.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
+                       addBeanTypeProperties = 
p.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
                }
        }
 
@@ -69,22 +61,167 @@ public final class MsgPackSerializerSession extends 
SerializerSession {
         * @return The {@link 
MsgPackSerializerContext#MSGPACK_addBeanTypeProperties} setting value for this 
session.
         */
        @Override /* SerializerSession */
-       public final boolean isAddBeanTypeProperties() {
+       protected final boolean isAddBeanTypeProperties() {
                return addBeanTypeProperties;
        }
 
-       /**
+       @Override /* SerializerSession */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               serializeAnything(getMsgPackOutputStream(out), o, 
getExpectedRootType(o), "root", null);
+       }
+
+       /*
         * Converts the specified output target object to an {@link 
MsgPackOutputStream}.
-        *
-        * @param out The output target object.
-        * @return The output target object wrapped in an {@link 
MsgPackOutputStream}.
-        * @throws Exception
         */
-       @SuppressWarnings("static-method")
-       public MsgPackOutputStream getMsgPackOutputStream(SerializerOutput out) 
throws Exception {
+       private static final MsgPackOutputStream 
getMsgPackOutputStream(SerializerPipe out) throws Exception {
                Object output = out.getRawOutput();
                if (output instanceof MsgPackOutputStream)
                        return (MsgPackOutputStream)output;
-               return new MsgPackOutputStream(out.getOutputStream());
+               MsgPackOutputStream os = new 
MsgPackOutputStream(out.getOutputStream());
+               out.setOutputStream(os);
+               return os;
+       }
+
+       /*
+        * Workhorse method.
+        * Determines the type of object, and then calls the appropriate 
type-specific serialization method.
+        */
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private MsgPackOutputStream serializeAnything(MsgPackOutputStream out, 
Object o, ClassMeta<?> eType, String attrName, BeanPropertyMeta pMeta) throws 
Exception {
+
+               if (o == null)
+                       return out.appendNull();
+
+               if (eType == null)
+                       eType = object();
+
+               ClassMeta<?> aType;                     // The actual type
+               ClassMeta<?> sType;                     // The serialized type
+
+               aType = push(attrName, o, eType);
+               boolean isRecursion = aType == null;
+
+               // Handle recursion
+               if (aType == null) {
+                       o = null;
+                       aType = object();
+               }
+
+               sType = aType.getSerializedClassMeta();
+               String typeName = getBeanTypeName(eType, aType, pMeta);
+
+               // Swap if necessary
+               PojoSwap swap = aType.getPojoSwap();
+               if (swap != null) {
+                       o = swap.swap(this, o);
+
+                       // If the getSwapClass() method returns Object, we need 
to figure out
+                       // the actual type now.
+                       if (sType.isObject())
+                               sType = getClassMetaForObject(o);
+               }
+
+               // '\0' characters are considered null.
+               if (o == null || (sType.isChar() && ((Character)o).charValue() 
== 0))
+                       out.appendNull();
+               else if (sType.isBoolean())
+                       out.appendBoolean((Boolean)o);
+               else if (sType.isNumber())
+                       out.appendNumber((Number)o);
+               else if (sType.isBean())
+                       serializeBeanMap(out, toBeanMap(o), typeName);
+               else if (sType.isUri() || (pMeta != null && pMeta.isUri()))
+                       out.appendString(resolveUri(o.toString()));
+               else if (sType.isMap()) {
+                       if (o instanceof BeanMap)
+                               serializeBeanMap(out, (BeanMap)o, typeName);
+                       else
+                               serializeMap(out, (Map)o, eType);
+               }
+               else if (sType.isCollection()) {
+                       serializeCollection(out, (Collection) o, eType);
+               }
+               else if (sType.isArray()) {
+                       serializeCollection(out, toList(sType.getInnerClass(), 
o), eType);
+               } else
+                       out.appendString(toString(o));
+
+               if (! isRecursion)
+                       pop();
+               return out;
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private void serializeMap(MsgPackOutputStream out, Map m, ClassMeta<?> 
type) throws Exception {
+
+               ClassMeta<?> keyType = type.getKeyType(), valueType = 
type.getValueType();
+
+               m = sort(m);
+
+               // The map size may change as we're iterating over it, so
+               // grab a snapshot of the entries in a separate list.
+               List<SimpleMapEntry> entries = new 
ArrayList<SimpleMapEntry>(m.size());
+               for (Map.Entry e : (Set<Map.Entry>)m.entrySet())
+                       entries.add(new SimpleMapEntry(e.getKey(), 
e.getValue()));
+
+               out.startMap(entries.size());
+
+               for (SimpleMapEntry e : entries) {
+                       Object value = e.value;
+                       Object key = generalize(e.key, keyType);
+
+                       serializeAnything(out, key, keyType, null, null);
+                       serializeAnything(out, value, valueType, null, null);
+               }
+       }
+
+       private void serializeBeanMap(MsgPackOutputStream out, final BeanMap<?> 
m, String typeName) throws Exception {
+
+               List<BeanPropertyValue> values = m.getValues(isTrimNulls(), 
typeName != null ? createBeanTypeNameProperty(m, typeName) : null);
+
+               int size = values.size();
+               for (BeanPropertyValue p : values)
+                       if (p.getThrown() != null)
+                               size--;
+               out.startMap(size);
+
+               for (BeanPropertyValue p : values) {
+                       BeanPropertyMeta pMeta = p.getMeta();
+                       ClassMeta<?> cMeta = p.getClassMeta();
+                       String key = p.getName();
+                       Object value = p.getValue();
+                       Throwable t = p.getThrown();
+                       if (t != null)
+                               onBeanGetterException(pMeta, t);
+                       else {
+                               serializeAnything(out, key, null, null, null);
+                               serializeAnything(out, value, cMeta, key, 
pMeta);
+                       }
+               }
+       }
+
+       private static class SimpleMapEntry {
+               final Object key;
+               final Object value;
+
+               private SimpleMapEntry(Object key, Object value) {
+                       this.key = key;
+                       this.value = value;
+               }
+       }
+
+       @SuppressWarnings({"rawtypes", "unchecked"})
+       private void serializeCollection(MsgPackOutputStream out, Collection c, 
ClassMeta<?> type) throws Exception {
+
+               ClassMeta<?> elementType = type.getElementType();
+               List<Object> l = new ArrayList<Object>(c.size());
+
+               c = sort(c);
+               l.addAll(c);
+
+               out.startArray(l.size());
+
+               for (Object o : l)
+                       serializeAnything(out, o, elementType, "<iterator>", 
null);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
index 46b1678..9fb15d6 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
@@ -45,7 +45,7 @@ public abstract class InputStreamParser extends Parser {
        }
 
        @Override /* Parser */
-       public boolean isReaderParser() {
+       public final boolean isReaderParser() {
                return false;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
new file mode 100644
index 0000000..3d061a5
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
@@ -0,0 +1,50 @@
+// 
***************************************************************************************************************************
+// * 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.parser;
+
+/**
+ * Subclass of parser session objects for byte-based parsers.
+ *
+ * <p>
+ * This class is NOT thread safe.  It is typically discarded after one-time 
use.
+ */
+public abstract class InputStreamParserSession extends ParserSession {
+
+       /**
+        * Create a new session using properties specified in the context.
+        *
+        * @param ctx
+        *      The context creating this session object.
+        *      The context contains all the configuration settings for this 
object.
+        * @param args
+        *      Runtime session arguments.
+        */
+       protected InputStreamParserSession(ParserContext ctx, ParserSessionArgs 
args) {
+               super(ctx, args);
+       }
+
+       /**
+        * Constructor for sessions that don't require context.
+        *
+        * @param args
+        *      Runtime session arguments.
+        */
+       protected InputStreamParserSession(ParserSessionArgs args) {
+               this(null, args);
+       }
+
+       @Override /* ParserSession */
+       public final boolean isReaderParser() {
+               return false;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
index f675377..f90d497 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
@@ -15,10 +15,8 @@ package org.apache.juneau.parser;
 import static org.apache.juneau.internal.StringUtils.*;
 
 import java.text.*;
-import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.json.*;
 
 /**
  * Exception that indicates invalid syntax encountered during parsing.
@@ -30,12 +28,12 @@ public class ParseException extends FormattedException {
        /**
         * Constructor.
         *
-        * @param session The parser session to extract information from.
+        * @param location The location of the parse exception.
         * @param message The exception message containing {@link 
MessageFormat}-style arguments.
         * @param args Optional {@link MessageFormat}-style arguments.
         */
-       public ParseException(ParserSession session, String message, 
Object...args) {
-               super(getMessage(session, message, args));
+       public ParseException(ObjectMap location, String message, 
Object...args) {
+               super(getMessage(location, message, args));
        }
 
        /**
@@ -51,11 +49,11 @@ public class ParseException extends FormattedException {
        /**
         * Constructor.
         *
-        * @param session The parser session to extract information from.
+        * @param location The location of the parse exception.
         * @param causedBy The inner exception.
         */
-       public ParseException(ParserSession session, Exception causedBy) {
-               super(causedBy, getMessage(session, causedBy.getMessage()));
+       public ParseException(ObjectMap location, Exception causedBy) {
+               super(causedBy, getMessage(location, causedBy.getMessage()));
        }
 
        /**
@@ -67,13 +65,11 @@ public class ParseException extends FormattedException {
                super(causedBy, getMessage(null, causedBy.getMessage()));
        }
 
-       private static String getMessage(ParserSession session, String msg, 
Object... args) {
+       private static String getMessage(ObjectMap location, String msg, 
Object... args) {
                if (args.length != 0)
                        msg = format(msg, args);
-               if (session != null) {
-                       Map<String,Object> m = session.getLastLocation();
-                       if (m != null && ! m.isEmpty())
-                               msg = "Parse exception occurred at " + 
JsonSerializer.DEFAULT_LAX.toString(m) + ".  " + msg;
+               if (location != null && ! location.isEmpty()) {
+                       msg = "Parse exception occurred at " + 
location.toString() + ".  " + msg;
                }
                return msg;
        }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
index c28dbf9..b077654 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
@@ -145,12 +145,10 @@ public abstract class Parser extends CoreObject {
 
        /** General parser properties currently set on this parser. */
        private final MediaType[] mediaTypes;
-       private final ParserContext ctx;
 
        // Hidden constructor to force subclass from InputStreamParser or 
ReaderParser.
        Parser(PropertyStore propertyStore) {
                super(propertyStore);
-               this.ctx = createContext(ParserContext.class);
 
                Consumes c = getAnnotation(Consumes.class, getClass());
                if (c == null)
@@ -168,74 +166,35 @@ public abstract class Parser extends CoreObject {
                return new ParserBuilder(propertyStore);
        }
 
+
        
//--------------------------------------------------------------------------------
        // Abstract methods
        
//--------------------------------------------------------------------------------
 
        /**
-        * Workhorse method.  Subclasses are expected to implement this method.
-        *
-        * @param session
-        *      The runtime session object returned by {@link 
#createSession(Object, ObjectMap, Method, Object,
-        *      Locale, TimeZone, MediaType)}.
-        *      If <jk>null</jk>, one will be created using {@link 
#createSession(Object)}.
-        * @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 Exception If thrown from underlying stream, or if the input 
contains a syntax error or is malformed.
-        */
-       protected abstract <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception;
-
-       /**
         * 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
-       
//--------------------------------------------------------------------------------
-
        /**
-        * Entry point for all parsing calls.
+        * Create the session object that will be passed in to the parse method.
         *
         * <p>
-        * Calls the {@link #doParse(ParserSession, ClassMeta)} implementation 
class and catches/re-wraps any exceptions
-        * thrown.
+        * It's up to implementers to decide what the session object looks 
like, although typically it's going to be a
+        * subclass of {@link ParserSession}.
         *
-        * @param session
-        *      The runtime session returned by {@link #createSession(Object, 
ObjectMap, Method, Object, Locale,
-        *      TimeZone, MediaType)}.
-        * @param type The class type of the object to create.
-        * @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.
+        * @param args
+        *      Runtime arguments.
+        * @return The new session.
         */
-       public final <T> T parseSession(ParserSession session, ClassMeta<T> 
type) throws ParseException {
-               try {
-                       if (type.isVoid())
-                               return null;
-                       return doParse(session, type);
-               } catch (ParseException e) {
-                       throw e;
-               } catch (StackOverflowError e) {
-                       throw new ParseException(session, "Depth too deep.  
Stack overflow occurred.");
-               } catch (IOException e) {
-                       throw new ParseException(session, "I/O exception 
occurred.  exception={0}, message={1}.",
-                               e.getClass().getSimpleName(), 
e.getLocalizedMessage()).initCause(e);
-               } catch (Exception e) {
-                       throw new ParseException(session, "Exception occurred.  
exception={0}, message={1}.",
-                               e.getClass().getSimpleName(), 
e.getLocalizedMessage()).initCause(e);
-               } finally {
-                       session.close();
-               }
-       }
+       public abstract ParserSession createSession(ParserSessionArgs args);
+
+
+       
//--------------------------------------------------------------------------------
+       // Other methods
+       
//--------------------------------------------------------------------------------
 
        /**
         * Parses input into the specified object type.
@@ -313,10 +272,13 @@ public abstract class Parser extends CoreObject {
         *      If the input contains a syntax error or is malformed, or is not 
valid for the specified type.
         * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for 
maps and collections.
         */
-       @SuppressWarnings("unchecked")
        public final <T> T parse(Object input, Type type, Type...args) throws 
ParseException {
-               ParserSession session = createSession(input);
-               return (T)parseSession(session, session.getClassMeta(type, 
args));
+               ParserSession session = createSession();
+               try {
+                       return session.parse(input, type, args);
+               } finally {
+                       session.close();
+               }
        }
 
        /**
@@ -355,8 +317,12 @@ public abstract class Parser extends CoreObject {
         *      If the input contains a syntax error or is malformed, or is not 
valid for the specified type.
         */
        public final <T> T parse(Object input, Class<T> type) throws 
ParseException {
-               ParserSession session = createSession(input);
-               return parseSession(session, session.getClassMeta(type));
+               ParserSession session = createSession();
+               try {
+                       return session.parse(input, type);
+               } finally {
+                       session.close();
+               }
        }
 
        /**
@@ -376,37 +342,12 @@ public abstract class Parser extends CoreObject {
         *      If the input contains a syntax error or is malformed, or is not 
valid for the specified type.
         */
        public final <T> T parse(Object input, ClassMeta<T> type) throws 
ParseException {
-               return parseSession(createSession(input), type);
-       }
-
-       /**
-        * Create the session object that will be passed in to the parse method.
-        *
-        * <p>
-        * It's up to implementers to decide what the session object looks 
like, although typically it's going to be a
-        * subclass of {@link ParserSession}.
-        *
-        * @param input
-        *      The input.
-        *      See {@link #parse(Object, ClassMeta)} for supported input types.
-        * @param op Optional additional properties.
-        * @param javaMethod
-        *      Java method that invoked this parser.
-        *      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.
-        * @param locale
-        *      The session locale.
-        *      If <jk>null</jk>, then the locale defined on the context is 
used.
-        * @param timeZone
-        *      The session timezone.
-        *      If <jk>null</jk>, then the timezone defined on the context is 
used.
-        * @param mediaType The session media type (e.g. 
<js>"application/json"</js>).
-        * @return The new session.
-        */
-       public ParserSession createSession(Object input, ObjectMap op, Method 
javaMethod, Object outer, Locale locale,
-                       TimeZone timeZone, MediaType mediaType) {
-               return new ParserSession(ctx, op, input, javaMethod, outer, 
locale, timeZone, mediaType);
+               ParserSession session = createSession();
+               try {
+                       return session.parse(input, type);
+               } finally {
+                       session.close();
+               }
        }
 
        /**
@@ -415,11 +356,10 @@ public abstract class Parser extends CoreObject {
         * <p>
         * Equivalent to calling <code>createSession(<jk>null</jk>, 
<jk>null</jk>)</code>.
         *
-        * @param input The input.  See {@link #parse(Object, ClassMeta)} for 
supported input types.
         * @return The new context.
         */
-       protected final ParserSession createSession(Object input) {
-               return createSession(input, null, null, null, null, null, 
getPrimaryMediaType());
+       public final ParserSession createSession() {
+               return createSession(null);
        }
 
 
@@ -452,39 +392,15 @@ public abstract class Parser extends CoreObject {
         * @throws UnsupportedOperationException If not implemented.
         */
        public final <K,V> Map<K,V> parseIntoMap(Object input, Map<K,V> m, Type 
keyType, Type valueType) throws ParseException {
-               ParserSession session = createSession(input);
+               ParserSession session = createSession();
                try {
-                       return doParseIntoMap(session, m, keyType, valueType);
-               } catch (ParseException e) {
-                       throw e;
-               } catch (Exception e) {
-                       throw new ParseException(session, e);
+                       return session.parseIntoMap(input, m, keyType, 
valueType);
                } finally {
                        session.close();
                }
        }
 
        /**
-        * Implementation method.
-        *
-        * <p>
-        * Default implementation throws an {@link 
UnsupportedOperationException}.
-        *
-        * @param session
-        *      The runtime session object returned by
-        *      {@link #createSession(Object, ObjectMap, Method, Object, 
Locale, TimeZone, MediaType)}.
-        *      If <jk>null</jk>, one will be created using {@link 
#createSession(Object)}.
-        * @param m The map being loaded.
-        * @param keyType The class type of the keys, or <jk>null</jk> to 
default to <code>String.<jk>class</jk></code>.
-        * @param valueType The class type of the values, or <jk>null</jk> to 
default to whatever is being parsed.
-        * @return The same map that was passed in to allow this method to be 
chained.
-        * @throws Exception If thrown from underlying stream, or if the input 
contains a syntax error or is malformed.
-        */
-       protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> 
m, Type keyType, Type valueType) throws Exception {
-               throw new UnsupportedOperationException("Parser 
'"+getClass().getName()+"' does not support this method.");
-       }
-
-       /**
         * Parses the contents of the specified reader and loads the results 
into the specified collection.
         *
         * <p>
@@ -504,40 +420,16 @@ public abstract class Parser extends CoreObject {
         *      If the input contains a syntax error or is malformed, or is not 
valid for the specified type.
         * @throws UnsupportedOperationException If not implemented.
         */
-       public final <E> Collection<E> parseIntoCollection(Object input, 
Collection<E> c, Type elementType)
-                       throws ParseException {
-               ParserSession session = createSession(input);
+       public final <E> Collection<E> parseIntoCollection(Object input, 
Collection<E> c, Type elementType) throws ParseException {
+               ParserSession session = createSession();
                try {
-                       return doParseIntoCollection(session, c, elementType);
-               } catch (ParseException e) {
-                       throw e;
-               } catch (Exception e) {
-                       throw new ParseException(session, e);
+                       return session.parseIntoCollection(input, c, 
elementType);
                } finally {
                        session.close();
                }
        }
 
        /**
-        * Implementation method.
-        *
-        * <p>
-        * Default implementation throws an {@link 
UnsupportedOperationException}.
-        *
-        * @param session
-        *      The runtime session object returned by {@link 
#createSession(Object, ObjectMap, Method, Object,
-        *      Locale, TimeZone, MediaType)}.
-        *      If <jk>null</jk>, one will be created using {@link 
#createSession(Object)}.
-        * @param c The collection being loaded.
-        * @param elementType The class type of the elements, or <jk>null</jk> 
to default to whatever is being parsed.
-        * @return The same collection that was passed in to allow this method 
to be chained.
-        * @throws Exception If thrown from underlying stream, or if the input 
contains a syntax error or is malformed.
-        */
-       protected <E> Collection<E> doParseIntoCollection(ParserSession 
session, Collection<E> c, Type elementType) throws Exception {
-               throw new UnsupportedOperationException("Parser 
'"+getClass().getName()+"' does not support this method.");
-       }
-
-       /**
         * Parses the specified array input with each entry in the object 
defined by the {@code argTypes}
         * argument.
         *
@@ -561,13 +453,9 @@ public abstract class Parser extends CoreObject {
        public final Object[] parseArgs(Object input, Type[] argTypes) throws 
ParseException {
                if (argTypes == null || argTypes.length == 0)
                        return new Object[0];
-               ParserSession session = createSession(input);
+               ParserSession session = createSession();
                try {
-                       return doParse(session, 
session.getArgsClassMeta(argTypes));
-               } catch (ParseException e) {
-                       throw e;
-               } catch (Exception e) {
-                       throw new ParseException(session, e);
+                       return session.parseArgs(input, argTypes);
                } finally {
                        session.close();
                }
@@ -579,83 +467,6 @@ public abstract class Parser extends CoreObject {
        
//--------------------------------------------------------------------------------
 
        /**
-        * Converts the specified string to the specified type.
-        *
-        * @param session The session object.
-        * @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 Exception 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(ParserSession session, Object outer, 
String s, ClassMeta<T> type) throws Exception {
-               if (s == null)
-                       return null;
-
-               if (type == null)
-                       type = (ClassMeta<T>)object();
-               PojoSwap transform = type.getPojoSwap();
-               ClassMeta<?> sType = type.getSerializedClassMeta();
-
-               Object o = s;
-               if (sType.isChar())
-                       o = s.charAt(0);
-               else if (sType.isNumber())
-                       if (type.canCreateNewInstanceFromNumber(outer))
-                               o = type.newInstanceFromNumber(session, outer, 
parseNumber(s, type.getNewInstanceFromNumberClass()));
-                       else
-                               o = parseNumber(s, (Class<? extends 
Number>)sType.getInnerClass());
-               else if (sType.isBoolean())
-                       o = Boolean.parseBoolean(s);
-               else if (! (sType.isCharSequence() || sType.isObject())) {
-                       if (sType.canCreateNewInstanceFromString(outer))
-                               o = sType.newInstanceFromString(outer, s);
-                       else
-                               throw new ParseException(session, "Invalid 
conversion from string to class ''{0}''", type);
-               }
-
-               if (transform != null)
-                       o = transform.unswap(session, 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 Exception
-        */
-       protected void setParent(ClassMeta<?> cm, Object o, Object parent) 
throws Exception {
-               Setter m = cm.getParentProperty();
-               if (m != null)
-                       m.set(o, parent);
-       }
-
-       /**
-        * 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 Exception
-        */
-       protected void setName(ClassMeta<?> cm, Object o, Object name) throws 
Exception {
-               if (cm != null) {
-                       Setter m = cm.getNameProperty();
-                       if (m != null)
-                               m.set(o, name);
-               }
-       }
-
-       /**
         * Returns the media types handled based on the value of the {@link 
Consumes} annotation on the parser class.
         *
         * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
index e8fd4b7..583649f 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
@@ -21,6 +21,12 @@ import org.apache.juneau.json.*;
 public class ParserContext extends BeanContext {
 
        /**
+        * Default context with all default values.
+        */
+       @SuppressWarnings("hiding")
+       protected static final ParserContext DEFAULT = new 
ParserContext(PropertyStore.create());
+
+       /**
         * <b>Configuration property:</b>  Trim parsed strings.
         *
         * <ul>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
index 846ebcb..d9ee830 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
@@ -92,7 +92,7 @@ public final class ParserGroup {
         *      tried to match against media types.
         */
        public ParserGroup(PropertyStore propertyStore, Parser[] parsers) {
-               this.propertyStore = PropertyStore.create(propertyStore);
+               this.propertyStore = propertyStore.copy();
                this.parsers = Collections.unmodifiableList(new 
ArrayList<Parser>(Arrays.asList(parsers)));
 
                List<MediaType> lmt = new ArrayList<MediaType>();
@@ -187,7 +187,7 @@ public final class ParserGroup {
         * @return A new copy of the property store passed in to the 
constructor.
         */
        public PropertyStore createPropertyStore() {
-               return PropertyStore.create(propertyStore);
+               return propertyStore.copy();
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java
deleted file mode 100644
index 773606e..0000000
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java
+++ /dev/null
@@ -1,230 +0,0 @@
-// 
***************************************************************************************************************************
-// * 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.parser;
-
-import static org.apache.juneau.internal.IOUtils.*;
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.io.*;
-import java.nio.charset.*;
-
-import org.apache.juneau.*;
-
-/**
- * A wrapper around an object that a parser reads its input from.
- *
- * <p>
- * For character-based parsers, the input object can be any of the following:
- * <ul>
- *     <li>{@link Reader}
- *     <li>{@link CharSequence}
- *     <li>{@link InputStream}
- *     <li><code><jk>byte</jk>[]</code>
- *     <li>{@link File}
- *     <li><code><jk>null</jk></code>
- * </ul>
- *
- * <p>
- * For stream-based parsers, the input object can be any of the following:
- * <ul>
- *     <li>{@link InputStream}
- *     <li><code><jk>byte</jk>[]</code>
- *     <li>{@link File}
- *     <li>{@link String} - Hex-encoded bytes.  (not BASE-64!)
- *     <li><code><jk>null</jk></code>
- * </ul>
- */
-public class ParserInput {
-
-       private Object input;
-       private String inputString;
-       private InputStream inputStream;
-       private Reader reader, noCloseReader;
-       private boolean debug, strict;
-       private String fileCharset, inputStreamCharset;
-
-       /**
-        * Constructor.
-        *
-        * @param input
-        * @param debug
-        * @param strict
-        * @param fileCharset
-        * @param inputStreamCharset
-        */
-       public ParserInput(Object input, boolean debug, boolean strict, String 
fileCharset, String inputStreamCharset) {
-               this.input = input;
-               this.debug = debug;
-               this.strict = strict;
-               this.fileCharset = fileCharset;
-               this.inputStreamCharset = inputStreamCharset;
-       }
-
-       /**
-        * Wraps the specified input object inside an input stream.
-        *
-        * <p>
-        * Subclasses can override this method to implement their own input 
streams.
-        *
-        * @return The input object wrapped in an input stream, or 
<jk>null</jk> if the object is null.
-        * @throws ParseException If object could not be converted to an input 
stream.
-        */
-       public InputStream getInputStream() throws ParseException {
-               try {
-                       if (input == null)
-                               return null;
-                       if (input instanceof InputStream) {
-                               if (debug) {
-                                       byte[] b = 
readBytes((InputStream)input, 1024);
-                                       inputString = toHex(b);
-                                       return new ByteArrayInputStream(b);
-                               }
-                               return (InputStream)input;
-                       }
-                       if (input instanceof byte[]) {
-                               if (debug)
-                                       inputString = toHex((byte[])input);
-                               return new ByteArrayInputStream((byte[])input);
-                       }
-                       if (input instanceof String) {
-                               inputString = (String)input;
-                               return new 
ByteArrayInputStream(fromHex((String)input));
-                       }
-                       if (input instanceof File) {
-                               if (debug) {
-                                       byte[] b = readBytes((File)input);
-                                       inputString = toHex(b);
-                                       return new ByteArrayInputStream(b);
-                               }
-                               inputStream = new FileInputStream((File)input);
-                               return inputStream;
-                       }
-               } catch (IOException e) {
-                       throw new ParseException(e);
-               }
-               throw new ParseException("Cannot convert object of type {0} to 
an InputStream.", input.getClass().getName());
-       }
-
-
-       /**
-        * Wraps the specified input object inside a reader.
-        *
-        * <p>
-        * Subclasses can override this method to implement their own readers.
-        *
-        * @return The input object wrapped in a Reader, or <jk>null</jk> if 
the object is null.
-        * @throws Exception If object could not be converted to a reader.
-        */
-       public Reader getReader() throws Exception {
-               if (input == null)
-                       return null;
-               if (input instanceof Reader) {
-                       if (debug) {
-                               inputString = read((Reader)input);
-                               return new StringReader(inputString);
-                       }
-                       return (Reader)input;
-               }
-               if (input instanceof CharSequence) {
-                       inputString = input.toString();
-                       if (reader == null)
-                               reader = new ParserReader((CharSequence)input);
-                       return reader;
-               }
-               if (input instanceof InputStream || input instanceof byte[]) {
-                       InputStream is = (
-                               input instanceof InputStream
-                               ? (InputStream)input
-                               : new ByteArrayInputStream((byte[])input)
-                       );
-                       if (noCloseReader == null) {
-                               CharsetDecoder cd = (
-                                       
"default".equalsIgnoreCase(inputStreamCharset)
-                                       ? Charset.defaultCharset()
-                                       : Charset.forName(inputStreamCharset)
-                               ).newDecoder();
-                               if (strict) {
-                                       
cd.onMalformedInput(CodingErrorAction.REPORT);
-                                       
cd.onUnmappableCharacter(CodingErrorAction.REPORT);
-                               } else {
-                                       
cd.onMalformedInput(CodingErrorAction.REPLACE);
-                                       
cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
-                               }
-                               noCloseReader = new InputStreamReader(is, cd);
-                       }
-                       if (debug) {
-                               inputString = read(noCloseReader);
-                               return new StringReader(inputString);
-                       }
-                       return noCloseReader;
-               }
-               if (input instanceof File) {
-                       if (reader == null) {
-                               CharsetDecoder cd = (
-                                       "default".equalsIgnoreCase(fileCharset)
-                                       ? Charset.defaultCharset()
-                                       : Charset.forName(fileCharset)
-                               ).newDecoder();
-                               if (strict) {
-                                       
cd.onMalformedInput(CodingErrorAction.REPORT);
-                                       
cd.onUnmappableCharacter(CodingErrorAction.REPORT);
-                               } else {
-                                       
cd.onMalformedInput(CodingErrorAction.REPLACE);
-                                       
cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
-                               }
-                               reader = new InputStreamReader(new 
FileInputStream((File)input), cd);
-                       }
-                       if (debug) {
-                               inputString = read(reader);
-                               return new StringReader(inputString);
-                       }
-                       return reader;
-               }
-               throw new ParseException("Cannot convert object of type {0} to 
a Reader.", input.getClass().getName());
-       }
-
-       /**
-        * Returns the raw input object passed into this session.
-        *
-        * @return The raw input object passed into this session.
-        */
-       protected Object getRawInput() {
-               return input;
-       }
-
-       /**
-        * Returns the input to this parser as a plain string.
-        *
-        * <p>
-        * This method only returns a value if {@link BeanContext#BEAN_debug} 
is enabled.
-        *
-        * @return The input as a string, or <jk>null</jk> if debug mode not 
enabled.
-        */
-       public String getInputAsString() {
-               return inputString;
-       }
-
-       /**
-        * Perform cleanup on this context object if necessary.
-        */
-       public void close() {
-               try {
-                       if (inputStream != null)
-                               inputStream.close();
-                       if (reader != null)
-                               reader.close();
-               } catch (IOException e) {
-                       throw new BeanRuntimeException(e);
-               }
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
index 75d39bb..83ac9a7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
@@ -29,10 +29,11 @@ public class ParserListener {
         * Otherwise, the parser will throw a {@link ParseException}.
         *
         * @param <T> The class type of the bean.
-        * @param session
-        *      The parser session.
+        * @param session The parser session.
+        * @param pipe
+        *      The parser input.
         *      Note that if {@link BeanContext#BEAN_debug} is enabled on the 
parser, you can get the input as a string through
-        *      {@link ParserSession#getInputAsString()}.
+        *      {@link ParserPipe#getInputAsString()}.
         * @param propertyName The property name encountered in the document.
         * @param beanClass The bean class.
         * @param bean The bean.
@@ -41,8 +42,8 @@ public class ParserListener {
         * @param col
         *      The column number where the unknown property was found (-1 if 
parser doesn't support line/column indicators).
         */
-       public <T> void onUnknownBeanProperty(ParserSession session, String 
propertyName, Class<T> beanClass, T bean, int line, int col) {
-               onError(session, null,
+       public <T> void onUnknownBeanProperty(ParserSession session, ParserPipe 
pipe, String propertyName, Class<T> beanClass, T bean, int line, int col) {
+               onError(session, pipe, null,
                        format("Unknown property ''{0}'' encountered while 
trying to parse into class ''{1}'' at line {2} column {3}",
                                propertyName, beanClass, line, col)
                );
@@ -51,13 +52,15 @@ public class ParserListener {
        /**
         * Called when an error occurs during parsing but is ignored.
         *
-        * @param session The parsers session.
+        * @param session The parser session.
+        * @param pipe
+        *      The parser input.
         *      Note that if {@link BeanContext#BEAN_debug} is enabled on the 
parser, you can get the input as a string through
-        *      {@link ParserSession#getInputAsString()}.
+        *      {@link ParserPipe#getInputAsString()}.
         * @param t The throwable that was thrown by the getter method.
         * @param msg The error message.
         */
-       public void onError(ParserSession session, Throwable t, String msg) {
+       public void onError(ParserSession session, ParserPipe pipe, Throwable 
t, String msg) {
                // Do something with this information.
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java
new file mode 100644
index 0000000..4faf988
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java
@@ -0,0 +1,278 @@
+// 
***************************************************************************************************************************
+// * 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.parser;
+
+import static org.apache.juneau.internal.IOUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.io.*;
+import java.nio.charset.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * A wrapper around an object that a parser reads its input from.
+ *
+ * <p>
+ * For character-based parsers, the input object can be any of the following:
+ * <ul>
+ *     <li>{@link Reader}
+ *     <li>{@link CharSequence}
+ *     <li>{@link InputStream}
+ *     <li><code><jk>byte</jk>[]</code>
+ *     <li>{@link File}
+ *     <li><code><jk>null</jk></code>
+ * </ul>
+ *
+ * <p>
+ * For stream-based parsers, the input object can be any of the following:
+ * <ul>
+ *     <li>{@link InputStream}
+ *     <li><code><jk>byte</jk>[]</code>
+ *     <li>{@link File}
+ *     <li>{@link String} - Hex-encoded bytes.  (not BASE-64!)
+ *     <li><code><jk>null</jk></code>
+ * </ul>
+ *
+ * <p>
+ * Note that Readers and InputStreams will NOT be automatically closed when 
{@link #close()} is called, but
+ * streams and readers created from other types (e.g. Files) WILL be 
automatically closed.
+ */
+public final class ParserPipe {
+
+       private final Object input;
+       private final boolean debug, strict;
+       private final String fileCharset, inputStreamCharset;
+
+       private String inputString;
+       private InputStream inputStream;
+       private Reader reader;
+
+       /**
+        * Constructor.
+        *
+        * @param input The parser input object.
+        * @param debug
+        *      If <jk>true</jk>, the input contents will be copied locally and 
accessible via the {@link #getInputAsString()}
+        *      method.
+        *      This allows the contents of the pipe to be accessed when a 
problem occurs.
+        * @param strict
+        *      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 fileCharset
+        *      The charset to expect when reading from {@link File Files}.
+        *      Use <js>"default"</js> to specify {@link 
Charset#defaultCharset()}.
+        * @param inputStreamCharset
+        *      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) {
+               this.input = input;
+               this.debug = debug;
+               this.strict = strict;
+               this.fileCharset = fileCharset;
+               this.inputStreamCharset = inputStreamCharset;
+               if (input instanceof CharSequence)
+                       this.inputString = input.toString();
+       }
+
+       /**
+        * Shortcut constructor, typically for straight string input.
+        *
+        * <p>
+        * Equivalent to calling <code><jk>new</jk> ParserPipe(input, 
<jk>false</jk>, <jk>false</jk>, <jk>null</jk>, <jk>null</jk>);</code>
+        *
+        * @param input The input object.
+        */
+       public ParserPipe(Object input) {
+               this(input, false, false, null, null);
+       }
+
+       /**
+        * Wraps the specified input object inside an input stream.
+        *
+        * <p>
+        * Subclasses can override this method to implement their own input 
streams.
+        *
+        * @return The input object wrapped in an input stream, or 
<jk>null</jk> if the object is null.
+        * @throws IOException If object could not be converted to an input 
stream.
+        */
+       public InputStream getInputStream() throws IOException {
+               if (input == null)
+                       return null;
+
+               if (input instanceof InputStream) {
+                       if (debug) {
+                               byte[] b = readBytes((InputStream)input, 1024);
+                               inputString = toHex(b);
+                               inputStream = new ByteArrayInputStream(b);
+                       } else {
+                               inputStream = (InputStream)input;
+                       }
+               } else if (input instanceof byte[]) {
+                       if (debug)
+                               inputString = toHex((byte[])input);
+                       inputStream = new ByteArrayInputStream((byte[])input);
+               } else if (input instanceof String) {
+                       inputString = (String)input;
+                       inputStream = new 
ByteArrayInputStream(fromHex((String)input));
+               } else if (input instanceof File) {
+                       if (debug) {
+                               byte[] b = readBytes((File)input);
+                               inputString = toHex(b);
+                               inputStream = new ByteArrayInputStream(b);
+                       } else {
+                               inputStream = new FileInputStream((File)input);
+                       }
+               } else {
+                       throw new IOException("Cannot convert object of type 
"+input.getClass().getName()+" to an InputStream.");
+               }
+
+               return inputStream;
+       }
+
+
+       /**
+        * Wraps the specified input object inside a reader.
+        *
+        * <p>
+        * Subclasses can override this method to implement their own readers.
+        *
+        * @return The input object wrapped in a Reader, or <jk>null</jk> if 
the object is null.
+        * @throws IOException If object could not be converted to a reader.
+        */
+       public Reader getReader() throws IOException {
+               if (input == null)
+                       return null;
+
+               if (input instanceof Reader) {
+                       if (debug) {
+                               inputString = read((Reader)input);
+                               reader = new StringReader(inputString);
+                       } else {
+                               reader = (Reader)input;
+                       }
+               } else if (input instanceof CharSequence) {
+                       inputString = input.toString();
+                       reader = new ParserReader(this);
+               } else if (input instanceof InputStream || input instanceof 
byte[]) {
+                       InputStream is = (
+                               input instanceof InputStream
+                               ? (InputStream)input
+                               : new ByteArrayInputStream((byte[])input)
+                       );
+                       CharsetDecoder cd = (
+                               "default".equalsIgnoreCase(inputStreamCharset)
+                               ? Charset.defaultCharset()
+                               : Charset.forName(inputStreamCharset)
+                       ).newDecoder();
+                       if (strict) {
+                               cd.onMalformedInput(CodingErrorAction.REPORT);
+                               
cd.onUnmappableCharacter(CodingErrorAction.REPORT);
+                       } else {
+                               cd.onMalformedInput(CodingErrorAction.REPLACE);
+                               
cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+                       }
+                       reader = new InputStreamReader(is, cd);
+                       if (debug) {
+                               inputString = read(reader);
+                               reader = new StringReader(inputString);
+                       }
+               } else if (input instanceof File) {
+                       CharsetDecoder cd = (
+                               "default".equalsIgnoreCase(fileCharset)
+                               ? Charset.defaultCharset()
+                               : Charset.forName(fileCharset)
+                       ).newDecoder();
+                       if (strict) {
+                               cd.onMalformedInput(CodingErrorAction.REPORT);
+                               
cd.onUnmappableCharacter(CodingErrorAction.REPORT);
+                       } else {
+                               cd.onMalformedInput(CodingErrorAction.REPLACE);
+                               
cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+                       }
+                       reader = new InputStreamReader(new 
FileInputStream((File)input), cd);
+                       if (debug) {
+                               inputString = read(reader);
+                               reader = new StringReader(inputString);
+                       }
+               } else {
+                       throw new IOException("Cannot convert object of type 
"+input.getClass().getName()+" to a Reader.");
+               }
+
+               return reader;
+       }
+
+       /**
+        * Returns the contents of this pipe as a buffered reader.
+        *
+        * <p>
+        * If the reader passed into this pipe is already a buffered reader, 
that reader will be returned.
+        *
+        * @return The contents of this pipe as a buffered reader.
+        * @throws Exception
+        */
+       public Reader getBufferedReader() throws Exception {
+               return IOUtils.getBufferedReader(getReader());
+       }
+
+       /**
+        * Returns the input to this parser as a plain string.
+        *
+        * <p>
+        * This method only returns a value if {@link BeanContext#BEAN_debug} 
is enabled.
+        *
+        * @return The input as a string, or <jk>null</jk> if debug mode not 
enabled.
+        */
+       public String getInputAsString() {
+               return inputString;
+       }
+
+       /**
+        * Converts this pipe into a {@link ParserReader}.
+        *
+        * @return The converted pipe.
+        * @throws Exception
+        */
+       public ParserReader getParserReader() throws Exception {
+               if (input == null)
+                       return null;
+               if (input instanceof ParserReader)
+                       reader = (ParserReader)input;
+               else
+                       reader = new ParserReader(this);
+               return (ParserReader)reader;
+       }
+
+       /**
+        * Returns <jk>true</jk> if the contents passed into this pipe was a 
{@link CharSequence}.
+        *
+        * @return <jk>true</jk> if the contents passed into this pipe was a 
{@link CharSequence}.
+        */
+       public boolean isString() {
+               return inputString != null;
+       }
+
+       /**
+        * Perform cleanup on this context object if necessary.
+        */
+       public void close() {
+               try {
+                       IOUtils.close(reader, inputStream);
+               } catch (IOException e) {
+                       throw new BeanRuntimeException(e);
+               }
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java 
b/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
index daa1593..3c75e36 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
@@ -14,6 +14,7 @@ package org.apache.juneau.parser;
 
 import java.io.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 
 /**
@@ -32,7 +33,8 @@ import org.apache.juneau.internal.*;
 public class ParserReader extends Reader {
 
        /** Wrapped reader */
-       protected Reader r;
+       protected final Reader r;
+       private final ParserPipe pipe;
 
        private char[] buff;       // Internal character buffer
        private int line = 1;      // Current line number
@@ -42,33 +44,28 @@ public class ParserReader extends Reader {
        private int iEnd = 0;      // The last good character position in the 
buffer
        private boolean endReached, holesExist;
 
-       ParserReader() {}
-
        /**
-        * Constructor for input from a {@link CharSequence}.
+        * Constructor.
         *
-        * @param in The character sequence being read from.
+        * @param pipe The parser input.
+        * @throws IOException
         */
-       public ParserReader(CharSequence in) {
-               this.r = new CharSequenceReader(in);
-               if (in == null)
-                       this.buff = new char[0];
-               else
+       public ParserReader(ParserPipe pipe) throws IOException {
+               this.pipe = pipe;
+               if (pipe.isString()) {
+                       String in = pipe.getInputAsString();
+                       this.r = new CharSequenceReader(in);
                        this.buff = new char[in.length() < 1024 ? in.length() : 
1024];
+               } else {
+                       Reader _r = pipe.getReader();
+                       if (_r instanceof ParserReader)
+                               this.r = ((ParserReader)_r).r;
+                       else
+                               this.r = _r;
+                       this.buff = new char[1024];
+               }
        }
 
-       /**
-        * Constructor for input from a {@link Reader}).
-        *
-        * @param r The Reader being wrapped.
-        */
-       public ParserReader(Reader r) {
-               if (r instanceof ParserReader)
-                       this.r = ((ParserReader)r).r;
-               else
-                       this.r = r;
-               this.buff = new char[1024];
-       }
 
        /**
         * Returns the current line number position in this reader.
@@ -278,7 +275,7 @@ public class ParserReader extends Reader {
         * @return This object (for method chaining).
         * @throws IOException If a problem occurred trying to read from the 
reader.
         */
-       public final ParserReader unread() throws IOException {
+       public ParserReader unread() throws IOException {
                if (iCurrent <= 0)
                        throw new IOException("Buffer underflow.");
                iCurrent--;
@@ -293,7 +290,8 @@ public class ParserReader extends Reader {
         */
        @Override /* Reader */
        public void close() throws IOException {
-               r.close();
+               if (r != null)
+                       r.close();
        }
 
        /**
@@ -417,4 +415,23 @@ public class ParserReader extends Reader {
        public int read(char[] cbuf, int off, int len) throws IOException {
                return r.read(cbuf, off, len);
        }
+
+       /**
+        * Returns the combined location information on both this reader and 
the session.
+        *
+        * @param session The session object to read the last location on.
+        * @return A new map describing the current parse location.
+        */
+       public ObjectMap getLocation(ParserSession session) {
+               return session.getLastLocation().append("line", 
getLine()).append("column", getColumn());
+       }
+
+       /**
+        * Returns the pipe that was passed into the constructor.
+        *
+        * @return The pipe that was passed into the constructor.
+        */
+       public final ParserPipe getPipe() {
+               return pipe;
+       }
 }

Reply via email to