http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/json/JsonParserSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonParserSession.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonParserSession.java
index 17571c0..6cb332a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonParserSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonParserSession.java
@@ -12,23 +12,28 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.json;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
+import org.apache.juneau.transform.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link 
JsonParser}.
  *
  * <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 
against multiple inputs.
  */
-public final class JsonParserSession extends ParserSession {
+@SuppressWarnings({ "unchecked", "rawtypes" })
+public final class JsonParserSession extends ReaderParserSession {
 
-       private ParserReader reader;
+       private static final AsciiSet decChars = new AsciiSet("0123456789");
 
        /**
         * Create a new session using properties specified in the context.
@@ -36,46 +41,11 @@ public final class JsonParserSession extends ParserSession {
         * @param ctx
         *      The context creating this session object.
         *      The context contains all the configuration settings for this 
object.
-        * @param input
-        *      The input.
-        *      Can be any of the following types:
-        *      <ul>
-        *              <li><jk>null</jk>
-        *              <li>{@link Reader}
-        *              <li>{@link CharSequence}
-        *              <li>{@link InputStream} containing UTF-8 encoded text.
-        *              <li>{@link File} containing system encoded text.
-        *      </ul>
-        * @param op
-        *      The override properties.
-        *      These override any context properties defined in the context.
-        * @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.
-        * @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 args
+        *      Runtime session arguments.
         */
-       public JsonParserSession(JsonParserContext ctx, ObjectMap op, Object 
input, Method javaMethod, Object outer,
-                       Locale locale, TimeZone timeZone, MediaType mediaType) {
-               super(ctx, op, input, javaMethod, outer, locale, timeZone, 
mediaType);
-       }
-
-       @Override /* ParserSession */
-       public ParserReader getReader() throws Exception {
-               if (reader == null) {
-                       Object input = getInput();
-                       if (input == null)
-                               return null;
-                       if (input instanceof CharSequence)
-                               reader = new ParserReader((CharSequence)input);
-                       else
-                               reader = new ParserReader(super.getReader());
-               }
-               return reader;
+       protected JsonParserSession(JsonParserContext ctx, ParserSessionArgs 
args) {
+               super(ctx, args);
        }
 
        /**
@@ -89,7 +59,7 @@ public final class JsonParserSession extends ParserSession {
         * @param cp The codepoint.
         * @return <jk>true</jk> if the specified character is whitespace.
         */
-       public final boolean isWhitespace(int cp) {
+       protected final boolean isWhitespace(int cp) {
                if (isStrict())
                                return cp <= 0x20 && (cp == 0x09 || cp == 0x0A 
|| cp == 0x0D || cp == 0x20);
                return Character.isWhitespace(cp);
@@ -101,21 +71,677 @@ public final class JsonParserSession extends 
ParserSession {
         * @param cp The codepoint.
         * @return <jk>true</jk> if the specified character is whitespace or 
'/'.
         */
-       public final boolean isCommentOrWhitespace(int cp) {
+       protected final boolean isCommentOrWhitespace(int cp) {
                if (cp == '/')
                        return true;
                if (isStrict())
                        return cp <= 0x20 && (cp == 0x09 || cp == 0x0A || cp == 
0x0D || cp == 0x20);
-       return Character.isWhitespace(cp);
+               return Character.isWhitespace(cp);
        }
 
        @Override /* ParserSession */
-       public Map<String,Object> getLastLocation() {
-               Map<String,Object> m = super.getLastLocation();
-               if (reader != null) {
-                       m.put("line", reader.getLine());
-                       m.put("column", reader.getColumn());
-               }
+       protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws 
Exception {
+               ParserReader r = pipe.getParserReader();
+               if (r == null)
+                       return null;
+               T o = parseAnything(type, r, getOuter(), null);
+               validateEnd(r);
+               return o;
+       }
+
+       @Override /* ReaderParserSession */
+       protected <K,V> Map<K,V> doParseIntoMap(ParserPipe pipe, Map<K,V> m, 
Type keyType, Type valueType) throws Exception {
+               ParserReader r = pipe.getParserReader();
+               m = parseIntoMap2(r, m, (ClassMeta<K>)getClassMeta(keyType), 
(ClassMeta<V>)getClassMeta(valueType), null);
+               validateEnd(r);
                return m;
        }
+
+       @Override /* ReaderParserSession */
+       protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, 
Collection<E> c, Type elementType) throws Exception {
+               ParserReader r = pipe.getParserReader();
+               c = parseIntoCollection2(r, c, getClassMeta(elementType), null);
+               validateEnd(r);
+               return c;
+       }
+
+       private <T> T parseAnything(ClassMeta<T> eType, ParserReader r, Object 
outer, BeanPropertyMeta pMeta) throws Exception {
+
+               if (eType == null)
+                       eType = (ClassMeta<T>)object();
+               PojoSwap<T,Object> transform = 
(PojoSwap<T,Object>)eType.getPojoSwap();
+               ClassMeta<?> sType = eType.getSerializedClassMeta();
+               setCurrentClass(sType);
+               String wrapperAttr = 
sType.getExtendedMeta(JsonClassMeta.class).getWrapperAttr();
+
+               Object o = null;
+
+               skipCommentsAndSpace(r);
+               if (wrapperAttr != null)
+                       skipWrapperAttrStart(r, wrapperAttr);
+               int c = r.peek();
+               if (c == -1) {
+                       if (isStrict())
+                               throw new ParseException(r.getLocation(this), 
"Empty input.");
+                       // Let o be null.
+               } else if ((c == ',' || c == '}' || c == ']')) {
+                       if (isStrict())
+                               throw new ParseException(r.getLocation(this), 
"Missing value detected.");
+                       // Handle bug in Cognos 10.2.1 that can product 
non-existent values.
+                       // Let o be null;
+               } else if (c == 'n') {
+                       parseKeyword("null", r);
+               } else if (sType.isObject()) {
+                       if (c == '{') {
+                               ObjectMap m2 = new ObjectMap(this);
+                               parseIntoMap2(r, m2, string(), object(), pMeta);
+                               o = cast(m2, pMeta, eType);
+                       } else if (c == '[') {
+                               o = parseIntoCollection2(r, new 
ObjectList(this), object(), pMeta);
+                       } else if (c == '\'' || c == '"') {
+                               o = parseString(r);
+                               if (sType.isChar())
+                                       o = o.toString().charAt(0);
+                       } else if (c >= '0' && c <= '9' || c == '-' || c == 
'.') {
+                               o = parseNumber(r, null);
+                       } else if (c == 't') {
+                               parseKeyword("true", r);
+                               o = Boolean.TRUE;
+                       } else {
+                               parseKeyword("false", r);
+                               o = Boolean.FALSE;
+                       }
+               } else if (sType.isBoolean()) {
+                       o = parseBoolean(r);
+               } else if (sType.isCharSequence()) {
+                       o = parseString(r);
+               } else if (sType.isChar()) {
+                       o = parseString(r).charAt(0);
+               } else if (sType.isNumber()) {
+                       o = parseNumber(r, (Class<? extends 
Number>)sType.getInnerClass());
+               } else if (sType.isMap()) {
+                       Map m = (sType.canCreateNewInstance(outer) ? 
(Map)sType.newInstance(outer) : new ObjectMap(this));
+                       o = parseIntoMap2(r, m, sType.getKeyType(), 
sType.getValueType(), pMeta);
+               } else if (sType.isCollection()) {
+                       if (c == '{') {
+                               ObjectMap m = new ObjectMap(this);
+                               parseIntoMap2(r, m, string(), object(), pMeta);
+                               o = cast(m, pMeta, eType);
+                       } else {
+                               Collection l = 
(sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance() : new 
ObjectList(this));
+                               o = parseIntoCollection2(r, l, sType, pMeta);
+                       }
+               } else if (sType.canCreateNewBean(outer)) {
+                       BeanMap m = newBeanMap(outer, sType.getInnerClass());
+                       o = parseIntoBeanMap2(r, m).getBean();
+               } else if (sType.canCreateNewInstanceFromString(outer) && (c == 
'\'' || c == '"')) {
+                       o = sType.newInstanceFromString(outer, parseString(r));
+               } else if (sType.canCreateNewInstanceFromNumber(outer) && 
isFirstNumberChar((char)c)) {
+                       o = sType.newInstanceFromNumber(this, outer, 
parseNumber(r, sType.getNewInstanceFromNumberClass()));
+               } else if (sType.isArray() || sType.isArgs()) {
+                       if (c == '{') {
+                               ObjectMap m = new ObjectMap(this);
+                               parseIntoMap2(r, m, string(), object(), pMeta);
+                               o = cast(m, pMeta, eType);
+                       } else {
+                               ArrayList l = 
(ArrayList)parseIntoCollection2(r, new ArrayList(), sType, pMeta);
+                               o = toArray(sType, l);
+                       }
+               } else if (c == '{') {
+                       Map m = new ObjectMap(this);
+                       parseIntoMap2(r, m, sType.getKeyType(), 
sType.getValueType(), pMeta);
+                       if (m.containsKey(getBeanTypePropertyName(eType)))
+                               o = cast((ObjectMap)m, pMeta, eType);
+                       else
+                               throw new ParseException(r.getLocation(this), 
"Class ''{0}'' could not be instantiated.  Reason: ''{1}''",
+                                               
sType.getInnerClass().getName(), sType.getNotABeanReason());
+               } else if (sType.canCreateNewInstanceFromString(outer) && ! 
isStrict()) {
+                       o = sType.newInstanceFromString(outer, parseString(r));
+               } else {
+                       throw new ParseException(r.getLocation(this), 
"Unrecognized syntax for class type ''{0}'', starting character ''{1}''",
+                               sType, (char)c);
+               }
+
+               if (wrapperAttr != null)
+                       skipWrapperAttrEnd(r);
+
+               if (transform != null && o != null)
+                       o = transform.unswap(this, o, eType);
+
+               if (outer != null)
+                       setParent(eType, o, outer);
+
+               return (T)o;
+       }
+
+       private Number parseNumber(ParserReader r, Class<? extends Number> 
type) throws Exception {
+               int c = r.peek();
+               if (c == '\'' || c == '"')
+                       return parseNumber(r, parseString(r), type);
+               return parseNumber(r, parseNumberString(r), type);
+       }
+
+       private Number parseNumber(ParserReader r, String s, Class<? extends 
Number> type) throws Exception {
+
+               // JSON has slightly different number rules from Java.
+               // Strict mode enforces these different rules, lax does not.
+               if (isStrict()) {
+
+                       // Lax allows blank strings to represent 0.
+                       // Strict does not allow blank strings.
+                       if (s.length() == 0)
+                               throw new ParseException(r.getLocation(this), 
"Invalid JSON number: ''{0}''", s);
+
+                       // Need to weed out octal and hexadecimal formats:  
0123,-0123,0x123,-0x123.
+                       // Don't weed out 0 or -0.
+                       boolean isNegative = false;
+                       char c = s.charAt(0);
+                       if (c == '-') {
+                               isNegative = true;
+                               c = (s.length() == 1 ? 'x' : s.charAt(1));
+                       }
+
+                       // JSON doesn't allow '.123' and '-.123'.
+                       if (c == '.')
+                               throw new ParseException(loc(r), "Invalid JSON 
number: ''{0}''", s);
+
+                       // '01' is not a valid number, but '0.1', '0e1', '0e+1' 
are valid.
+                       if (c == '0' && s.length() > (isNegative ? 2 : 1)) {
+                               char c2 = s.charAt((isNegative ? 2 : 1));
+                               if (c2 != '.' && c2 != 'e' && c2 != 'E')
+                                       throw new ParseException(loc(r), 
"Invalid JSON number: ''{0}''", s);
+                       }
+
+                       // JSON doesn't allow '1.' or '0.e1'.
+                       int i = s.indexOf('.');
+                       if (i != -1 && (s.length() == (i+1) || ! 
decChars.contains(s.charAt(i+1))))
+                               throw new ParseException(loc(r), "Invalid JSON 
number: ''{0}''", s);
+
+               }
+               return StringUtils.parseNumber(s, type);
+       }
+
+       private Boolean parseBoolean(ParserReader r) throws Exception {
+               int c = r.peek();
+               if (c == '\'' || c == '"')
+                       return Boolean.valueOf(parseString(r));
+               if (c == 't') {
+                       parseKeyword("true", r);
+                       return Boolean.TRUE;
+               }
+               parseKeyword("false", r);
+               return Boolean.FALSE;
+       }
+
+
+       private <K,V> Map<K,V> parseIntoMap2(ParserReader r, Map<K,V> m, 
ClassMeta<K> keyType,
+                       ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws 
Exception {
+
+               if (keyType == null)
+                       keyType = (ClassMeta<K>)string();
+
+               int S0=0; // Looking for outer {
+               int S1=1; // Looking for attrName start.
+               int S3=3; // Found attrName end, looking for :.
+               int S4=4; // Found :, looking for valStart: { [ " ' LITERAL.
+               int S5=5; // Looking for , or }
+               int S6=6; // Found , looking for attr start.
+
+               int state = S0;
+               String currAttr = null;
+               int c = 0;
+               while (c != -1) {
+                       c = r.read();
+                       if (state == S0) {
+                               if (c == '{')
+                                       state = S1;
+                       } else if (state == S1) {
+                               if (c == '}') {
+                                       return m;
+                               } else if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       currAttr = parseFieldName(r.unread());
+                                       state = S3;
+                               }
+                       } else if (state == S3) {
+                               if (c == ':')
+                                       state = S4;
+                       } else if (state == S4) {
+                               if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       K key = convertAttrToType(m, currAttr, 
keyType);
+                                       V value = parseAnything(valueType, 
r.unread(), m, pMeta);
+                                       setName(valueType, value, key);
+                                       m.put(key, value);
+                                       state = S5;
+                               }
+                       } else if (state == S5) {
+                               if (c == ',')
+                                       state = S6;
+                               else if (isCommentOrWhitespace(c))
+                                       skipCommentsAndSpace(r.unread());
+                               else if (c == '}') {
+                                       return m;
+                               } else {
+                                       break;
+                               }
+                       } else if (state == S6) {
+                               if (c == '}') {
+                                       break;
+                               } else if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       currAttr = parseFieldName(r.unread());
+                                       state = S3;
+                               }
+                       }
+               }
+               if (state == S0)
+                       throw new ParseException(loc(r), "Expected '{' at 
beginning of JSON object.");
+               if (state == S1)
+                       throw new ParseException(loc(r), "Could not find 
attribute name on JSON object.");
+               if (state == S3)
+                       throw new ParseException(loc(r), "Could not find ':' 
following attribute name on JSON object.");
+               if (state == S4)
+                       throw new ParseException(loc(r), "Expected one of the 
following characters: {,[,',\",LITERAL.");
+               if (state == S5)
+                       throw new ParseException(loc(r), "Could not find '}' 
marking end of JSON object.");
+               if (state == S6)
+                       throw new ParseException(loc(r), "Unexpected '}' found 
in JSON object.");
+
+               return null; // Unreachable.
+       }
+
+       /*
+        * Parse a JSON attribute from the character array at the specified 
position, then
+        * set the position marker to the last character in the field name.
+        */
+       private String parseFieldName(ParserReader r) throws Exception {
+               int c = r.peek();
+               if (c == '\'' || c == '"')
+                       return parseString(r);
+               if (isStrict())
+                       throw new ParseException(loc(r), "Unquoted attribute 
detected.");
+               r.mark();
+               // Look for whitespace.
+               while (c != -1) {
+                       c = r.read();
+                       if (c == ':' || isWhitespace(c) || c == '/') {
+                               r.unread();
+                               String s = r.getMarked().intern();
+                               return s.equals("null") ? null : s;
+                       }
+               }
+               throw new ParseException(loc(r), "Could not find the end of the 
field name.");
+       }
+
+       private <E> Collection<E> parseIntoCollection2(ParserReader r, 
Collection<E> l,
+                       ClassMeta<?> type, BeanPropertyMeta pMeta) throws 
Exception {
+
+               int S0=0; // Looking for outermost [
+               int S1=1; // Looking for starting [ or { or " or ' or LITERAL 
or ]
+               int S2=2; // Looking for , or ]
+               int S3=3; // Looking for starting [ or { or " or ' or LITERAL
+
+               int argIndex = 0;
+
+               int state = S0;
+               int c = 0;
+               while (c != -1) {
+                       c = r.read();
+                       if (state == S0) {
+                               if (c == '[')
+                                       state = S1;
+                       } else if (state == S1) {
+                               if (c == ']') {
+                                       return l;
+                               } else if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else if (c != -1) {
+                                       l.add((E)parseAnything(type.isArgs() ? 
type.getArg(argIndex++) : type.getElementType(), r.unread(), l, pMeta));
+                                       state = S2;
+                               }
+                       } else if (state == S2) {
+                               if (c == ',') {
+                                       state = S3;
+                               } else if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else if (c == ']') {
+                                       return l;
+                               } else {
+                                       break;  // Invalid character found.
+                               }
+                       } else if (state == S3) {
+                               if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else if (c == ']') {
+                                       break;
+                               } else if (c != -1) {
+                                       l.add((E)parseAnything(type.isArgs() ? 
type.getArg(argIndex++) : type.getElementType(), r.unread(), l, pMeta));
+                                       state = S2;
+                               }
+                       }
+               }
+               if (state == S0)
+                       throw new ParseException(loc(r), "Expected '[' at 
beginning of JSON array.");
+               if (state == S1)
+                       throw new ParseException(loc(r), "Expected one of the 
following characters: {,[,',\",LITERAL.");
+               if (state == S2)
+                       throw new ParseException(loc(r), "Expected ',' or 
']'.");
+               if (state == S3)
+                       throw new ParseException(loc(r), "Unexpected trailing 
comma in array.");
+
+               return null;  // Unreachable.
+       }
+
+       private <T> BeanMap<T> parseIntoBeanMap2(ParserReader r, BeanMap<T> m) 
throws Exception {
+
+               int S0=0; // Looking for outer {
+               int S1=1; // Looking for attrName start.
+               int S3=3; // Found attrName end, looking for :.
+               int S4=4; // Found :, looking for valStart: { [ " ' LITERAL.
+               int S5=5; // Looking for , or }
+
+               int state = S0;
+               String currAttr = "";
+               int c = 0;
+               int currAttrLine = -1, currAttrCol = -1;
+               while (c != -1) {
+                       c = r.read();
+                       if (state == S0) {
+                               if (c == '{')
+                                       state = S1;
+                       } else if (state == S1) {
+                               if (c == '}') {
+                                       return m;
+                               } else if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       r.unread();
+                                       currAttrLine= r.getLine();
+                                       currAttrCol = r.getColumn();
+                                       currAttr = parseFieldName(r);
+                                       state = S3;
+                               }
+                       } else if (state == S3) {
+                               if (c == ':')
+                                       state = S4;
+                       } else if (state == S4) {
+                               if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       if (! 
currAttr.equals(getBeanTypePropertyName(m.getClassMeta()))) {
+                                               BeanPropertyMeta pMeta = 
m.getPropertyMeta(currAttr);
+                                               setCurrentProperty(pMeta);
+                                               if (pMeta == null) {
+                                                       
onUnknownProperty(r.getPipe(), currAttr, m, currAttrLine, currAttrCol);
+                                                       parseAnything(object(), 
r.unread(), m.getBean(false), null); // Read content anyway to ignore it
+                                               } else {
+                                                       ClassMeta<?> cm = 
pMeta.getClassMeta();
+                                                       Object value = 
parseAnything(cm, r.unread(), m.getBean(false), pMeta);
+                                                       setName(cm, value, 
currAttr);
+                                                       pMeta.set(m, currAttr, 
value);
+                                               }
+                                               setCurrentProperty(null);
+                                       }
+                                       state = S5;
+                               }
+                       } else if (state == S5) {
+                               if (c == ',')
+                                       state = S1;
+                               else if (isCommentOrWhitespace(c))
+                                       skipCommentsAndSpace(r.unread());
+                               else if (c == '}') {
+                                       return m;
+                               }
+                       }
+               }
+               if (state == S0)
+                       throw new ParseException(loc(r), "Expected '{' at 
beginning of JSON object.");
+               if (state == S1)
+                       throw new ParseException(loc(r), "Could not find 
attribute name on JSON object.");
+               if (state == S3)
+                       throw new ParseException(loc(r), "Could not find ':' 
following attribute name on JSON object.");
+               if (state == S4)
+                       throw new ParseException(loc(r), "Expected one of the 
following characters: {,[,',\",LITERAL.");
+               if (state == S5)
+                       throw new ParseException(loc(r), "Could not find '}' 
marking end of JSON object.");
+
+               return null; // Unreachable.
+       }
+
+       /*
+        * Starting from the specified position in the character array, returns 
the
+        * position of the character " or '.
+        * If the string consists of a concatenation of strings (e.g. 'AAA' + 
"BBB"), this method
+        * will automatically concatenate the strings and return the result.
+        */
+       private String parseString(ParserReader r) throws Exception  {
+               r.mark();
+               int qc = r.read();              // The quote character being 
used (" or ')
+               if (qc != '"' && isStrict()) {
+                       String msg = (
+                               qc == '\''
+                               ? "Invalid quote character \"{0}\" being used."
+                               : "Did not find quote character marking 
beginning of string.  Character=\"{0}\""
+                       );
+                       throw new ParseException(loc(r), msg, (char)qc);
+               }
+               final boolean isQuoted = (qc == '\'' || qc == '"');
+               String s = null;
+               boolean isInEscape = false;
+               int c = 0;
+               while (c != -1) {
+                       c = r.read();
+                       // Strict syntax requires that all control characters 
be escaped.
+                       if (isStrict() && c <= 0x1F)
+                               throw new ParseException("Unescaped control 
character encountered: ''0x{0}''", String.format("%04X", c));
+                       if (isInEscape) {
+                               switch (c) {
+                                       case 'n': r.replace('\n'); break;
+                                       case 'r': r.replace('\r'); break;
+                                       case 't': r.replace('\t'); break;
+                                       case 'f': r.replace('\f'); break;
+                                       case 'b': r.replace('\b'); break;
+                                       case '\\': r.replace('\\'); break;
+                                       case '/': r.replace('/'); break;
+                                       case '\'': r.replace('\''); break;
+                                       case '"': r.replace('"'); break;
+                                       case 'u': {
+                                               String n = r.read(4);
+                                               try {
+                                                       
r.replace(Integer.parseInt(n, 16), 6);
+                                               } catch (NumberFormatException 
e) {
+                                                       throw new 
ParseException(loc(r), "Invalid Unicode escape sequence in string.");
+                                               }
+                                               break;
+                                       }
+                                       default:
+                                               throw new 
ParseException(loc(r), "Invalid escape sequence in string.");
+                               }
+                               isInEscape = false;
+                       } else {
+                               if (c == '\\') {
+                                       isInEscape = true;
+                                       r.delete();
+                               } else if (isQuoted) {
+                                       if (c == qc) {
+                                               s = r.getMarked(1, -1);
+                                               break;
+                                       }
+                               } else {
+                                       if (c == ',' || c == '}' || c == ']' || 
isWhitespace(c)) {
+                                               s = r.getMarked(0, -1);
+                                               r.unread();
+                                               break;
+                                       } else if (c == -1) {
+                                               s = r.getMarked(0, 0);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               if (s == null)
+                       throw new ParseException(loc(r), "Could not find 
expected end character ''{0}''.", (char)qc);
+
+               // Look for concatenated string (i.e. whitespace followed by +).
+               skipCommentsAndSpace(r);
+               if (r.peek() == '+') {
+                       if (isStrict())
+                               throw new ParseException(loc(r), "String 
concatenation detected.");
+                       r.read();       // Skip past '+'
+                       skipCommentsAndSpace(r);
+                       s += parseString(r);
+               }
+               return trim(s); // End of input reached.
+       }
+
+       /*
+        * Looks for the keywords true, false, or null.
+        * Throws an exception if any of these keywords are not found at the 
specified position.
+        */
+       private void parseKeyword(String keyword, ParserReader r) throws 
Exception {
+               try {
+                       String s = r.read(keyword.length());
+                       if (s.equals(keyword))
+                               return;
+                       throw new ParseException(loc(r), "Unrecognized 
syntax.");
+               } catch (IndexOutOfBoundsException e) {
+                       throw new ParseException(loc(r), "Unrecognized 
syntax.");
+               }
+       }
+
+       /*
+        * Doesn't actually parse anything, but moves the position beyond any 
whitespace or comments.
+        * If positionOnNext is 'true', then the cursor will be set to the 
point immediately after
+        * the comments and whitespace.  Otherwise, the cursor will be set to 
the last position of
+        * the comments and whitespace.
+        */
+       private void skipCommentsAndSpace(ParserReader r) throws Exception {
+               int c = 0;
+               while ((c = r.read()) != -1) {
+                       if (! isWhitespace(c)) {
+                               if (c == '/') {
+                                       if (isStrict())
+                                               throw new 
ParseException(loc(r), "Javascript comment detected.");
+                                       skipComments(r);
+                               } else {
+                                       r.unread();
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Doesn't actually parse anything, but moves the position beyond the 
construct "{wrapperAttr:" when
+        * the @Json.wrapperAttr() annotation is used on a class.
+        */
+       private void skipWrapperAttrStart(ParserReader r, String wrapperAttr) 
throws Exception {
+
+               int S0=0; // Looking for outer {
+               int S1=1; // Looking for attrName start.
+               int S3=3; // Found attrName end, looking for :.
+               int S4=4; // Found :, looking for valStart: { [ " ' LITERAL.
+
+               int state = S0;
+               String currAttr = null;
+               int c = 0;
+               while (c != -1) {
+                       c = r.read();
+                       if (state == S0) {
+                               if (c == '{')
+                                       state = S1;
+                       } else if (state == S1) {
+                               if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       currAttr = parseFieldName(r.unread());
+                                       if (! currAttr.equals(wrapperAttr))
+                                               throw new ParseException(loc(r),
+                                                       "Expected to find 
wrapper attribute ''{0}'' but found attribute ''{1}''", wrapperAttr, currAttr);
+                                       state = S3;
+                               }
+                       } else if (state == S3) {
+                               if (c == ':')
+                                       state = S4;
+                       } else if (state == S4) {
+                               if (isCommentOrWhitespace(c)) {
+                                       skipCommentsAndSpace(r.unread());
+                               } else {
+                                       r.unread();
+                                       return;
+                               }
+                       }
+               }
+               if (state == S0)
+                       throw new ParseException(loc(r), "Expected '{' at 
beginning of JSON object.");
+               if (state == S1)
+                       throw new ParseException(loc(r), "Could not find 
attribute name on JSON object.");
+               if (state == S3)
+                       throw new ParseException(loc(r), "Could not find ':' 
following attribute name on JSON object.");
+               if (state == S4)
+                       throw new ParseException(loc(r), "Expected one of the 
following characters: {,[,',\",LITERAL.");
+       }
+
+       /*
+        * Doesn't actually parse anything, but moves the position beyond the 
construct "}" when
+        * the @Json.wrapperAttr() annotation is used on a class.
+        */
+       private void skipWrapperAttrEnd(ParserReader r) throws ParseException, 
IOException {
+               int c = 0;
+               while ((c = r.read()) != -1) {
+                       if (! isWhitespace(c)) {
+                               if (c == '/') {
+                                       if (isStrict())
+                                               throw new 
ParseException(loc(r), "Javascript comment detected.");
+                                       skipComments(r);
+                               } else if (c == '}') {
+                                       return;
+                               } else {
+                                       throw new ParseException(loc(r), "Could 
not find '}' at the end of JSON wrapper object.");
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Doesn't actually parse anything, but when positioned at the 
beginning of comment,
+        * it will move the pointer to the last character in the comment.
+        */
+       private void skipComments(ParserReader r) throws ParseException, 
IOException {
+               int c = r.read();
+               //  "/* */" style comments
+               if (c == '*') {
+                       while (c != -1)
+                               if ((c = r.read()) == '*')
+                                       if ((c = r.read()) == '/')
+                                               return;
+               //  "//" style comments
+               } else if (c == '/') {
+                       while (c != -1) {
+                               c = r.read();
+                               if (c == -1 || c == '\n')
+                                       return;
+                       }
+               }
+               throw new ParseException(loc(r), "Open ended comment.");
+       }
+
+       /*
+        * Call this method after you've finished a parsing a string to make 
sure that if there's any
+        * remainder in the input, that it consists only of whitespace and 
comments.
+        */
+       private void validateEnd(ParserReader r) throws Exception {
+               skipCommentsAndSpace(r);
+               int c = r.read();
+               if (c != -1 && c != ';')  // var x = {...}; expressions can end 
with a semicolon.
+                       throw new ParseException(loc(r), "Remainder after 
parse: ''{0}''.", (char)c);
+       }
+
+       private ObjectMap loc(ParserReader r) {
+               return getLastLocation().append("line", 
r.getLine()).append("column", r.getColumn());
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
index 9829016..66d6bae 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
@@ -12,17 +12,11 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.json;
 
-import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.serializer.SerializerContext.*;
 
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
 
 /**
  * Serializes POJO metadata to HTTP responses as JSON.
@@ -40,125 +34,21 @@ import org.apache.juneau.transform.*;
 
@Produces(value="application/json+schema,text/json+schema",contentType="application/json")
 public final class JsonSchemaSerializer extends JsonSerializer {
 
-       private final JsonSerializerContext ctx;
-
        /**
         * Constructor.
         *
         * @param propertyStore Initialize with the specified config property 
store.
         */
        public JsonSchemaSerializer(PropertyStore propertyStore) {
-               this(propertyStore, null);
-       }
-
-       /**
-        * Constructor.
-        *
-        * @param propertyStore Initialize with the specified config property 
store.
-        * @param overrideProperties
-        */
-       public JsonSchemaSerializer(PropertyStore propertyStore, 
Map<String,Object> overrideProperties) {
-               super(propertyStore);
-               this.ctx = 
this.propertyStore.create(overrideProperties).getContext(JsonSerializerContext.class);
-       }
-
-       @Override /* CoreObject */
-       protected ObjectMap getOverrideProperties() {
-               return 
super.getOverrideProperties().append(SERIALIZER_detectRecursions, true)
-                       .append(SERIALIZER_ignoreRecursions, true);
+               super(
+                       propertyStore.copy()
+                       .append(SERIALIZER_detectRecursions, true)
+                       .append(SERIALIZER_ignoreRecursions, true)
+               );
        }
 
-
-       
//--------------------------------------------------------------------------------
-       // Entry point methods
-       
//--------------------------------------------------------------------------------
-
        @Override /* Serializer */
-       public JsonSerializerSession createSession(ObjectMap op, Method 
javaMethod, Locale locale,
-                       TimeZone timeZone, MediaType mediaType, UriContext 
uriContext) {
-               return new JsonSerializerSession(ctx, op, javaMethod, locale, 
timeZone, mediaType, uriContext);
-       }
-
-       @Override /* JsonSerializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               JsonSerializerSession s = (JsonSerializerSession)session;
-               ObjectMap schema = getSchema(s, 
session.getClassMetaForObject(o), "root", null);
-               serializeAnything(s, s.getJsonWriter(out), schema, 
s.getExpectedRootType(o), "root", null);
-       }
-
-       /*
-        * Creates a schema representation of the specified class type.
-        *
-        * @param eType The class type to get the schema of.
-        * @param ctx Serialize context used to prevent infinite loops.
-        * @param attrName The name of the current attribute.
-        * @return A schema representation of the specified class.
-        * @throws SerializeException If a problem occurred trying to convert 
the output.
-        */
-       @SuppressWarnings({ "unchecked", "rawtypes" })
-       private ObjectMap getSchema(JsonSerializerSession session, ClassMeta<?> 
eType, String attrName, String[] pNames)
-                       throws Exception {
-               ObjectMap out = new ObjectMap();
-
-               if (eType == null)
-                       eType = object();
-
-               ClassMeta<?> aType;                     // The actual type 
(will be null if recursion occurs)
-               ClassMeta<?> sType;                     // The serialized type
-
-               aType = session.push(attrName, eType, null);
-
-               sType = eType.getSerializedClassMeta();
-               String type = null;
-
-               if (sType.isEnum() || sType.isCharSequence() || sType.isChar())
-                       type = "string";
-               else if (sType.isNumber())
-                       type = "number";
-               else if (sType.isBoolean())
-                       type = "boolean";
-               else if (sType.isMapOrBean())
-                       type = "object";
-               else if (sType.isCollectionOrArray())
-                       type = "array";
-               else
-                       type = "any";
-
-               out.put("type", type);
-               out.put("description", eType.toString());
-               PojoSwap f = eType.getPojoSwap();
-               if (f != null)
-                       out.put("transform", f);
-
-               if (aType != null) {
-                       if (sType.isEnum())
-                               out.put("enum", 
getEnumStrings((Class<Enum<?>>)sType.getInnerClass()));
-                       else if (sType.isCollectionOrArray()) {
-                               ClassMeta componentType = 
sType.getElementType();
-                               if (sType.isCollection() && 
isParentClass(Set.class, sType.getInnerClass()))
-                                       out.put("uniqueItems", true);
-                               out.put("items", getSchema(session, 
componentType, "items", pNames));
-                       } else if (sType.isBean()) {
-                               ObjectMap properties = new ObjectMap();
-                               BeanMeta bm = 
session.getBeanMeta(sType.getInnerClass());
-                               if (pNames != null)
-                                       bm = new BeanMetaFiltered(bm, pNames);
-                               for (Iterator<BeanPropertyMeta> i = 
bm.getPropertyMetas().iterator(); i.hasNext();) {
-                                       BeanPropertyMeta p = i.next();
-                                       properties.put(p.getName(), 
getSchema(session, p.getClassMeta(), p.getName(), p.getProperties()));
-                               }
-                               out.put("properties", properties);
-                       }
-               }
-               session.pop();
-               return out;
-       }
-
-       @SuppressWarnings({ "unchecked", "rawtypes" })
-       private static List<String> getEnumStrings(Class<? extends Enum> c) {
-               List<String> l = new LinkedList<String>();
-               for (Object e : EnumSet.allOf(c))
-                       l.add(e.toString());
-               return l;
+       public WriterSerializerSession createSession(SerializerSessionArgs 
args) {
+               return new JsonSchemaSerializerSession(ctx, args);
        }
-}
+}
\ 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/json/JsonSchemaSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java
new file mode 100644
index 0000000..f9e875d
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java
@@ -0,0 +1,129 @@
+// 
***************************************************************************************************************************
+// * 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.json;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link 
JsonSchemaSerializer}.
+ *
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused 
within the same thread.
+ */
+public class JsonSchemaSerializerSession extends JsonSerializerSession {
+
+       /**
+        * 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 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 JsonSchemaSerializerSession(JsonSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+       }
+
+       @Override /* SerializerSession */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               ObjectMap schema = getSchema(getClassMetaForObject(o), "root", 
null);
+               serializeAnything(getJsonWriter(out), schema, 
getExpectedRootType(o), "root", null);
+       }
+
+       /*
+        * Creates a schema representation of the specified class type.
+        *
+        * @param eType The class type to get the schema of.
+        * @param ctx Serialize context used to prevent infinite loops.
+        * @param attrName The name of the current attribute.
+        * @return A schema representation of the specified class.
+        * @throws SerializeException If a problem occurred trying to convert 
the output.
+        */
+       @SuppressWarnings({ "unchecked", "rawtypes" })
+       private ObjectMap getSchema(ClassMeta<?> eType, String attrName, 
String[] pNames) throws Exception {
+               ObjectMap out = new ObjectMap();
+
+               if (eType == null)
+                       eType = object();
+
+               ClassMeta<?> aType;                     // The actual type 
(will be null if recursion occurs)
+               ClassMeta<?> sType;                     // The serialized type
+
+               aType = push(attrName, eType, null);
+
+               sType = eType.getSerializedClassMeta();
+               String type = null;
+
+               if (sType.isEnum() || sType.isCharSequence() || sType.isChar())
+                       type = "string";
+               else if (sType.isNumber())
+                       type = "number";
+               else if (sType.isBoolean())
+                       type = "boolean";
+               else if (sType.isMapOrBean())
+                       type = "object";
+               else if (sType.isCollectionOrArray())
+                       type = "array";
+               else
+                       type = "any";
+
+               out.put("type", type);
+               out.put("description", eType.toString());
+               PojoSwap f = eType.getPojoSwap();
+               if (f != null)
+                       out.put("transform", f);
+
+               if (aType != null) {
+                       if (sType.isEnum())
+                               out.put("enum", 
getEnumStrings((Class<Enum<?>>)sType.getInnerClass()));
+                       else if (sType.isCollectionOrArray()) {
+                               ClassMeta componentType = 
sType.getElementType();
+                               if (sType.isCollection() && 
isParentClass(Set.class, sType.getInnerClass()))
+                                       out.put("uniqueItems", true);
+                               out.put("items", getSchema(componentType, 
"items", pNames));
+                       } else if (sType.isBean()) {
+                               ObjectMap properties = new ObjectMap();
+                               BeanMeta bm = 
getBeanMeta(sType.getInnerClass());
+                               if (pNames != null)
+                                       bm = new BeanMetaFiltered(bm, pNames);
+                               for (Iterator<BeanPropertyMeta> i = 
bm.getPropertyMetas().iterator(); i.hasNext();) {
+                                       BeanPropertyMeta p = i.next();
+                                       properties.put(p.getName(), 
getSchema(p.getClassMeta(), p.getName(), p.getProperties()));
+                               }
+                               out.put("properties", properties);
+                       }
+               }
+               pop();
+               return out;
+       }
+
+       @SuppressWarnings({ "unchecked", "rawtypes" })
+       private static List<String> getEnumStrings(Class<? extends Enum> c) {
+               List<String> l = new LinkedList<String>();
+               for (Object e : EnumSet.allOf(c))
+                       l.add(e.toString());
+               return l;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
index 82edd79..db0a78d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializer.java
@@ -14,14 +14,11 @@ package org.apache.juneau.json;
 
 import static org.apache.juneau.json.JsonSerializerContext.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
 
 /**
  * Serializes POJO models to JSON.
@@ -132,12 +129,10 @@ public class JsonSerializer extends WriterSerializer {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public Readable(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(SERIALIZER_useWhitespace, true);
+                       super(
+                               propertyStore.copy()
+                               .append(SERIALIZER_useWhitespace, true)
+                       );
                }
        }
 
@@ -151,12 +146,11 @@ public class JsonSerializer extends WriterSerializer {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public Simple(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(JSON_simpleMode, 
true).append(SERIALIZER_quoteChar, '\'');
+                       super(
+                               propertyStore.copy()
+                               .append(JSON_simpleMode, true)
+                               .append(SERIALIZER_quoteChar, '\'')
+                       );
                }
        }
 
@@ -169,13 +163,12 @@ public class JsonSerializer extends WriterSerializer {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public SimpleReadable(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(JSON_simpleMode, 
true).append(SERIALIZER_quoteChar, '\'')
-                               .append(SERIALIZER_useWhitespace, true);
+                       super(
+                               propertyStore.copy()
+                               .append(JSON_simpleMode, true)
+                               .append(SERIALIZER_quoteChar, '\'')
+                               .append(SERIALIZER_useWhitespace, true)
+                       );
                }
        }
 
@@ -191,18 +184,18 @@ public class JsonSerializer extends WriterSerializer {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public SimpleReadableSafe(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(JSON_simpleMode, 
true).append(SERIALIZER_quoteChar, '\'')
-                               .append(SERIALIZER_useWhitespace, 
true).append(SERIALIZER_detectRecursions, true);
+                       super(
+                               propertyStore.copy()
+                               .append(JSON_simpleMode, true)
+                               .append(SERIALIZER_quoteChar, '\'')
+                               .append(SERIALIZER_useWhitespace, true)
+                               .append(SERIALIZER_detectRecursions, true)
+                       );
                }
        }
 
 
-       private final JsonSerializerContext ctx;
+       final JsonSerializerContext ctx;
        private volatile JsonSchemaSerializer schemaSerializer;
 
        /**
@@ -221,186 +214,13 @@ public class JsonSerializer extends WriterSerializer {
        }
 
        /**
-        * Workhorse method.
-        *
-        * <p>
-        * Determines the type of object, and then calls the appropriate 
type-specific serialization method.
-        */
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       SerializerWriter serializeAnything(JsonSerializerSession session, 
JsonWriter out, Object o, ClassMeta<?> eType,
-                       String attrName, BeanPropertyMeta pMeta) throws 
Exception {
-
-               if (o == null) {
-                       out.append("null");
-                       return out;
-               }
-
-               if (eType == null)
-                       eType = object();
-
-               ClassMeta<?> aType;                     // The actual type
-               ClassMeta<?> sType;                     // The serialized type
-
-               aType = session.push(attrName, o, eType);
-               boolean isRecursion = aType == null;
-
-               // Handle recursion
-               if (aType == null) {
-                       o = null;
-                       aType = object();
-               }
-
-               sType = aType.getSerializedClassMeta();
-               String typeName = session.getBeanTypeName(eType, aType, pMeta);
-
-               // Swap if necessary
-               PojoSwap swap = aType.getPojoSwap();
-               if (swap != null) {
-                       o = swap.swap(session, o);
-
-                       // If the getSwapClass() method returns Object, we need 
to figure out
-                       // the actual type now.
-                       if (sType.isObject())
-                               sType = session.getClassMetaForObject(o);
-               }
-
-               String wrapperAttr = 
sType.getExtendedMeta(JsonClassMeta.class).getWrapperAttr();
-               if (wrapperAttr != null) {
-                       
out.append('{').cr(session.indent).attr(wrapperAttr).append(':').s(session.indent);
-                       session.indent++;
-               }
-
-               // '\0' characters are considered null.
-               if (o == null || (sType.isChar() && ((Character)o).charValue() 
== 0))
-                       out.append("null");
-               else if (sType.isNumber() || sType.isBoolean())
-                       out.append(o);
-               else if (sType.isBean())
-                       serializeBeanMap(session, out, session.toBeanMap(o), 
typeName);
-               else if (sType.isUri() || (pMeta != null && pMeta.isUri()))
-                       out.uriValue(o);
-               else if (sType.isMap()) {
-                       if (o instanceof BeanMap)
-                               serializeBeanMap(session, out, (BeanMap)o, 
typeName);
-                       else
-                               serializeMap(session, out, (Map)o, eType);
-               }
-               else if (sType.isCollection()) {
-                       serializeCollection(session, out, (Collection) o, 
eType);
-               }
-               else if (sType.isArray()) {
-                       serializeCollection(session, out, 
toList(sType.getInnerClass(), o), eType);
-               }
-               else
-                       out.stringValue(session.toString(o));
-
-               if (wrapperAttr != null) {
-                       session.indent--;
-                       out.cre(session.indent-1).append('}');
-               }
-
-               if (! isRecursion)
-                       session.pop();
-               return out;
-       }
-
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       private SerializerWriter serializeMap(JsonSerializerSession session, 
JsonWriter out, Map m, ClassMeta<?> type)
-                       throws Exception {
-
-               ClassMeta<?> keyType = type.getKeyType(), valueType = 
type.getValueType();
-
-               m = session.sort(m);
-
-               int i = session.getIndent();
-               out.append('{');
-
-               Iterator mapEntries = m.entrySet().iterator();
-
-               while (mapEntries.hasNext()) {
-                       Map.Entry e = (Map.Entry) mapEntries.next();
-                       Object value = e.getValue();
-
-                       Object key = session.generalize(e.getKey(), keyType);
-
-                       out.cr(i).attr(session.toString(key)).append(':').s(i);
-
-                       serializeAnything(session, out, value, valueType, (key 
== null ? null : session.toString(key)), null);
-
-                       if (mapEntries.hasNext())
-                               out.append(',').smi(i);
-               }
-
-               out.cre(i-1).append('}');
-
-               return out;
-       }
-
-       private SerializerWriter serializeBeanMap(JsonSerializerSession 
session, JsonWriter out, BeanMap<?> m,
-                       String typeName) throws Exception {
-               int i = session.getIndent();
-               out.append('{');
-
-               boolean addComma = false;
-               for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), 
typeName != null ? session.createBeanTypeNameProperty(m, typeName) : null)) {
-                       BeanPropertyMeta pMeta = p.getMeta();
-                       ClassMeta<?> cMeta = p.getClassMeta();
-                       String key = p.getName();
-                       Object value = p.getValue();
-                       Throwable t = p.getThrown();
-                       if (t != null)
-                               session.onBeanGetterException(pMeta, t);
-
-                       if (session.canIgnoreValue(cMeta, key, value))
-                               continue;
-
-                       if (addComma)
-                               out.append(',').smi(i);
-
-                       out.cr(i).attr(key).append(':').s(i);
-
-                       serializeAnything(session, out, value, cMeta, key, 
pMeta);
-
-                       addComma = true;
-               }
-               out.cre(i-1).append('}');
-               return out;
-       }
-
-       @SuppressWarnings({"rawtypes", "unchecked"})
-       private SerializerWriter serializeCollection(JsonSerializerSession 
session, JsonWriter out, Collection c,
-                       ClassMeta<?> type) throws Exception {
-
-               ClassMeta<?> elementType = type.getElementType();
-
-               c = session.sort(c);
-
-               out.append('[');
-               int depth = session.getIndent();
-
-               for (Iterator i = c.iterator(); i.hasNext();) {
-
-                       Object value = i.next();
-
-                       out.cr(depth);
-
-                       serializeAnything(session, out, value, elementType, 
"<iterator>", null);
-
-                       if (i.hasNext())
-                               out.append(',').smi(depth);
-               }
-               out.cre(depth-1).append(']');
-               return out;
-       }
-
-       /**
         * Returns the schema serializer based on the settings of this 
serializer.
         *
         * @return The schema serializer.
         */
        public JsonSchemaSerializer getSchemaSerializer() {
                if (schemaSerializer == null)
-                       schemaSerializer = new 
JsonSchemaSerializer(propertyStore, getOverrideProperties());
+                       schemaSerializer = new 
JsonSchemaSerializer(propertyStore);
                return schemaSerializer;
        }
 
@@ -409,14 +229,7 @@ public class JsonSerializer extends WriterSerializer {
        
//--------------------------------------------------------------------------------
 
        @Override /* Serializer */
-       public JsonSerializerSession createSession(ObjectMap op, Method 
javaMethod, Locale locale,
-                       TimeZone timeZone, MediaType mediaType, UriContext 
uriContext) {
-               return new JsonSerializerSession(ctx, op, javaMethod, locale, 
timeZone, mediaType, uriContext);
-       }
-
-       @Override /* Serializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               JsonSerializerSession s = (JsonSerializerSession)session;
-               serializeAnything(s, s.getJsonWriter(out), o, 
s.getExpectedRootType(o), "root", null);
+       public WriterSerializerSession createSession(SerializerSessionArgs 
args) {
+               return new JsonSerializerSession(ctx, args);
        }
-}
+}
\ 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/json/JsonSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
index 2808f59..12c9433 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
@@ -14,20 +14,20 @@ package org.apache.juneau.json;
 
 import static org.apache.juneau.json.JsonSerializerContext.*;
 
-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 
JsonSerializer}.
  *
  * <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 JsonSerializerSession extends SerializerSession {
+public class JsonSerializerSession extends WriterSerializerSession {
 
        private final boolean
                simpleMode,
@@ -40,60 +40,203 @@ public final class JsonSerializerSession 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 JsonSerializerSession(JsonSerializerContext 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 JsonSerializerSession(JsonSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+               ObjectMap p = getProperties();
+               if (p.isEmpty()) {
                        simpleMode = ctx.simpleMode;
                        escapeSolidus = ctx.escapeSolidus;
                        addBeanTypeProperties = ctx.addBeanTypeProperties;
                } else {
-                       simpleMode = op.getBoolean(JSON_simpleMode, 
ctx.simpleMode);
-                       escapeSolidus = op.getBoolean(JSON_escapeSolidus, 
ctx.escapeSolidus);
-                       addBeanTypeProperties = 
op.getBoolean(JSON_addBeanTypeProperties, ctx.addBeanTypeProperties);
+                       simpleMode = p.getBoolean(JSON_simpleMode, 
ctx.simpleMode);
+                       escapeSolidus = p.getBoolean(JSON_escapeSolidus, 
ctx.escapeSolidus);
+                       addBeanTypeProperties = 
p.getBoolean(JSON_addBeanTypeProperties, ctx.addBeanTypeProperties);
                }
        }
 
-       /**
-        * Returns the {@link JsonSerializerContext#JSON_simpleMode} setting 
value for this session.
-        *
-        * @return The {@link JsonSerializerContext#JSON_simpleMode} setting 
value for this session.
-        */
-       public final boolean isSimpleMode() {
-               return simpleMode;
+
+       @Override /* SerializerSesssion */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               serializeAnything(getJsonWriter(out), o, 
getExpectedRootType(o), "root", null);
        }
 
-       /**
-        * Returns the {@link JsonSerializerContext#JSON_escapeSolidus} setting 
value for this session.
-        *
-        * @return The {@link JsonSerializerContext#JSON_escapeSolidus} setting 
value for this session.
+       /*
+        * Workhorse method.
+        * Determines the type of object, and then calls the appropriate 
type-specific serialization method.
         */
-       public final boolean isEscapeSolidus() {
-               return escapeSolidus;
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       SerializerWriter serializeAnything(JsonWriter out, Object o, 
ClassMeta<?> eType,        String attrName, BeanPropertyMeta pMeta) throws 
Exception {
+
+               if (o == null) {
+                       out.append("null");
+                       return out;
+               }
+
+               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);
+               }
+
+               String wrapperAttr = 
sType.getExtendedMeta(JsonClassMeta.class).getWrapperAttr();
+               if (wrapperAttr != null) {
+                       
out.append('{').cr(indent).attr(wrapperAttr).append(':').s(indent);
+                       indent++;
+               }
+
+               // '\0' characters are considered null.
+               if (o == null || (sType.isChar() && ((Character)o).charValue() 
== 0))
+                       out.append("null");
+               else if (sType.isNumber() || sType.isBoolean())
+                       out.append(o);
+               else if (sType.isBean())
+                       serializeBeanMap(out, toBeanMap(o), typeName);
+               else if (sType.isUri() || (pMeta != null && pMeta.isUri()))
+                       out.uriValue(o);
+               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.stringValue(toString(o));
+
+               if (wrapperAttr != null) {
+                       indent--;
+                       out.cre(indent-1).append('}');
+               }
+
+               if (! isRecursion)
+                       pop();
+               return out;
        }
 
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private SerializerWriter serializeMap(JsonWriter out, Map m, 
ClassMeta<?> type) throws Exception {
+
+               ClassMeta<?> keyType = type.getKeyType(), valueType = 
type.getValueType();
+
+               m = sort(m);
+
+               int i = indent;
+               out.append('{');
+
+               Iterator mapEntries = m.entrySet().iterator();
+
+               while (mapEntries.hasNext()) {
+                       Map.Entry e = (Map.Entry) mapEntries.next();
+                       Object value = e.getValue();
+
+                       Object key = generalize(e.getKey(), keyType);
+
+                       out.cr(i).attr(toString(key)).append(':').s(i);
+
+                       serializeAnything(out, value, valueType, (key == null ? 
null : toString(key)), null);
+
+                       if (mapEntries.hasNext())
+                               out.append(',').smi(i);
+               }
+
+               out.cre(i-1).append('}');
+
+               return out;
+       }
+
+       private SerializerWriter serializeBeanMap(JsonWriter out, BeanMap<?> m, 
String typeName) throws Exception {
+               int i = indent;
+               out.append('{');
+
+               boolean addComma = false;
+               for (BeanPropertyValue p : m.getValues(isTrimNulls(), typeName 
!= null ? createBeanTypeNameProperty(m, typeName) : null)) {
+                       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);
+
+                       if (canIgnoreValue(cMeta, key, value))
+                               continue;
+
+                       if (addComma)
+                               out.append(',').smi(i);
+
+                       out.cr(i).attr(key).append(':').s(i);
+
+                       serializeAnything(out, value, cMeta, key, pMeta);
+
+                       addComma = true;
+               }
+               out.cre(i-1).append('}');
+               return out;
+       }
+
+       @SuppressWarnings({"rawtypes", "unchecked"})
+       private SerializerWriter serializeCollection(JsonWriter out, Collection 
c, ClassMeta<?> type) throws Exception {
+
+               ClassMeta<?> elementType = type.getElementType();
+
+               c = sort(c);
+
+               out.append('[');
+
+               for (Iterator i = c.iterator(); i.hasNext();) {
+                       Object value = i.next();
+                       out.cr(indent);
+                       serializeAnything(out, value, elementType, 
"<iterator>", null);
+                       if (i.hasNext())
+                               out.append(',').smi(indent);
+               }
+               out.cre(indent-1).append(']');
+               return out;
+       }
+
+
        /**
         * Returns the {@link JsonSerializerContext#JSON_addBeanTypeProperties} 
setting value for this session.
         *
         * @return The {@link JsonSerializerContext#JSON_addBeanTypeProperties} 
setting value for this session.
         */
        @Override /* SerializerSession */
-       public final boolean isAddBeanTypeProperties() {
+       protected final boolean isAddBeanTypeProperties() {
                return addBeanTypeProperties;
        }
 
@@ -104,11 +247,13 @@ public final class JsonSerializerSession extends 
SerializerSession {
         * @return The output target object wrapped in an {@link JsonWriter}.
         * @throws Exception
         */
-       public JsonWriter getJsonWriter(SerializerOutput out) throws Exception {
+       protected final JsonWriter getJsonWriter(SerializerPipe out) throws 
Exception {
                Object output = out.getRawOutput();
                if (output instanceof JsonWriter)
                        return (JsonWriter)output;
-               return new JsonWriter(out.getWriter(), isUseWhitespace(), 
getMaxIndent(), isEscapeSolidus(), getQuoteChar(),
-                       isSimpleMode(), isTrimStrings(), getUriResolver());
+               JsonWriter w = new JsonWriter(out.getWriter(), 
isUseWhitespace(), getMaxIndent(), escapeSolidus, getQuoteChar(),
+                       simpleMode, isTrimStrings(), getUriResolver());
+               out.setWriter(w);
+               return w;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackInputStream.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackInputStream.java 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackInputStream.java
index 40a03ec..2fdc81a 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackInputStream.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackInputStream.java
@@ -17,6 +17,8 @@ import static org.apache.juneau.internal.IOUtils.*;
 
 import java.io.*;
 
+import org.apache.juneau.parser.*;
+
 /**
  * Specialized input stream for parsing MessagePack streams.
  *
@@ -27,6 +29,7 @@ import java.io.*;
  */
 public final class MsgPackInputStream extends InputStream {
 
+       private final ParserPipe pipe;
        private final InputStream is;
        private DataType currentDataType;
        private long length;
@@ -57,10 +60,12 @@ public final class MsgPackInputStream extends InputStream {
        /**
         * Constructor.
         *
-        * @param is The input stream being wrapped.
+        * @param pipe The parser input.
+        * @throws Exception
         */
-       protected MsgPackInputStream(InputStream is) {
-               this.is = is;
+       protected MsgPackInputStream(ParserPipe pipe) throws Exception {
+               this.pipe = pipe;
+               this.is = pipe.getInputStream();
        }
 
        @Override /* InputStream */
@@ -485,4 +490,13 @@ public final class MsgPackInputStream extends InputStream {
        int getPosition() {
                return pos;
        }
+
+       /**
+        * Returns the pipe that was passed into the constructor.
+        *
+        * @return The pipe that was passed into the constructor.
+        */
+       public ParserPipe getPipe() {
+               return pipe;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
index 727b465..0d9ab31 100644
--- a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
@@ -12,16 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.msgpack;
 
-import static org.apache.juneau.msgpack.DataType.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.parser.*;
-import org.apache.juneau.transform.*;
 
 /**
  * Parses a MessagePack stream into a POJO model.
@@ -37,14 +30,13 @@ import org.apache.juneau.transform.*;
  *     <li>{@link MsgPackParserContext}
  * </ul>
  */
-@SuppressWarnings({ "rawtypes", "unchecked" })
 @Consumes("octal/msgpack")
 public class MsgPackParser extends InputStreamParser {
 
        /** Default parser, all default settings.*/
        public static final MsgPackParser DEFAULT = new 
MsgPackParser(PropertyStore.create());
 
-
+       
        private final MsgPackParserContext ctx;
 
        /**
@@ -62,168 +54,8 @@ public class MsgPackParser extends InputStreamParser {
                return new MsgPackParserBuilder(propertyStore);
        }
 
-       /**
-        * Workhorse method.
-        */
-       private <T> T parseAnything(MsgPackParserSession session, ClassMeta<T> 
eType, MsgPackInputStream is, Object outer,
-                       BeanPropertyMeta pMeta) throws Exception {
-
-               if (eType == null)
-                       eType = (ClassMeta<T>)object();
-               PojoSwap<T,Object> transform = 
(PojoSwap<T,Object>)eType.getPojoSwap();
-               ClassMeta<?> sType = eType.getSerializedClassMeta();
-               session.setCurrentClass(sType);
-
-               Object o = null;
-               DataType dt = is.readDataType();
-               int length = (int)is.readLength();
-
-               if (dt != DataType.NULL) {
-                       if (dt == BOOLEAN)
-                               o = is.readBoolean();
-                       else if (dt == INT)
-                               o = is.readInt();
-                       else if (dt == LONG)
-                               o = is.readLong();
-                       else if (dt == FLOAT)
-                               o = is.readFloat();
-                       else if (dt == DOUBLE)
-                               o = is.readDouble();
-                       else if (dt == STRING)
-                               o = session.trim(is.readString());
-                       else if (dt == BIN)
-                               o = is.readBinary();
-                       else if (dt == ARRAY && sType.isObject()) {
-                               ObjectList ol = new ObjectList(session);
-                               for (int i = 0; i < length; i++)
-                                       ol.add(parseAnything(session, object(), 
is, outer, pMeta));
-                               o = ol;
-                       } else if (dt == MAP && sType.isObject()) {
-                               ObjectMap om = new ObjectMap(session);
-                               for (int i = 0; i < length; i++)
-                                       om.put(parseAnything(session, string(), 
is, outer, pMeta), parseAnything(session, object(), is, om, pMeta));
-                               o = session.cast(om, pMeta, eType);
-                       }
-
-                       if (sType.isObject()) {
-                               // Do nothing.
-                       } else if (sType.isBoolean() || sType.isCharSequence() 
|| sType.isChar() || sType.isNumber()) {
-                               o = session.convertToType(o, sType);
-                       } else if (sType.isMap()) {
-                               if (dt == MAP) {
-                                       Map m = 
(sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new 
ObjectMap(session));
-                                       for (int i = 0; i < length; i++) {
-                                               Object key = 
parseAnything(session, sType.getKeyType(), is, outer, pMeta);
-                                               ClassMeta<?> vt = 
sType.getValueType();
-                                               Object value = 
parseAnything(session, vt, is, m, pMeta);
-                                               setName(vt, value, key);
-                                               m.put(key, value);
-                                       }
-                                       o = m;
-                               } else {
-                                       throw new ParseException(session, 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
-                               }
-                       } else if (sType.canCreateNewBean(outer)) {
-                               if (dt == MAP) {
-                                       BeanMap m = session.newBeanMap(outer, 
sType.getInnerClass());
-                                       for (int i = 0; i < length; i++) {
-                                               String pName = 
parseAnything(session, string(), is, m.getBean(false), null);
-                                               BeanPropertyMeta bpm = 
m.getPropertyMeta(pName);
-                                               if (bpm == null) {
-                                                       if 
(pName.equals(session.getBeanTypePropertyName(eType)))
-                                                               
parseAnything(session, session.string(), is, null, null);
-                                                       else
-                                                               
session.onUnknownProperty(pName, m, 0, is.getPosition());
-                                               } else {
-                                                       ClassMeta<?> cm = 
bpm.getClassMeta();
-                                                       Object value = 
parseAnything(session, cm, is, m.getBean(false), bpm);
-                                                       setName(cm, value, 
pName);
-                                                       bpm.set(m, pName, 
value);
-                                               }
-                                       }
-                                       o = m.getBean();
-                               } else {
-                                       throw new ParseException(session, 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
-                               }
-                       } else if (sType.canCreateNewInstanceFromString(outer) 
&& dt == STRING) {
-                               o = sType.newInstanceFromString(outer, o == 
null ? "" : o.toString());
-                       } else if (sType.canCreateNewInstanceFromNumber(outer) 
&& dt.isOneOf(INT, LONG, FLOAT, DOUBLE)) {
-                               o = sType.newInstanceFromNumber(session, outer, 
(Number)o);
-                       } else if (sType.isCollection()) {
-                               if (dt == MAP) {
-                                       ObjectMap m = new ObjectMap(session);
-                                       for (int i = 0; i < length; i++)
-                                               m.put(parseAnything(session, 
string(), is, outer, pMeta), parseAnything(session, object(), is, m, pMeta));
-                                       o = session.cast(m, pMeta, eType);
-                               } else if (dt == ARRAY) {
-                                       Collection l = (
-                                               
sType.canCreateNewInstance(outer)
-                                               ? 
(Collection)sType.newInstance()
-                                               : new ObjectList(session)
-                                       );
-                                       for (int i = 0; i < length; i++)
-                                               l.add(parseAnything(session, 
sType.getElementType(), is, l, pMeta));
-                                       o = l;
-                               } else {
-                                       throw new ParseException(session, 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
-                               }
-                       } else if (sType.isArray() || sType.isArgs()) {
-                               if (dt == MAP) {
-                                       ObjectMap m = new ObjectMap(session);
-                                       for (int i = 0; i < length; i++)
-                                               m.put(parseAnything(session, 
string(), is, outer, pMeta), parseAnything(session, object(), is, m, pMeta));
-                                       o = session.cast(m, pMeta, eType);
-                               } else if (dt == ARRAY) {
-                                       Collection l = (
-                                               sType.isCollection() && 
sType.canCreateNewInstance(outer)
-                                               ? 
(Collection)sType.newInstance()
-                                               : new ObjectList(session)
-                                       );
-                                       for (int i = 0; i < length; i++)
-                                               l.add(parseAnything(session, 
sType.isArgs() ? sType.getArg(i) : sType.getElementType(), is, l, pMeta));
-                                       o = session.toArray(sType, l);
-                               } else {
-                                       throw new ParseException(session, 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
-                               }
-                       } else if (dt == MAP) {
-                               ObjectMap m = new ObjectMap(session);
-                               for (int i = 0; i < length; i++)
-                                       m.put(parseAnything(session, string(), 
is, outer, pMeta), parseAnything(session, object(), is, m, pMeta));
-                               if 
(m.containsKey(session.getBeanTypePropertyName(eType)))
-                                       o = session.cast(m, pMeta, eType);
-                               else
-                                       throw new ParseException(session, 
"Class ''{0}'' could not be instantiated.  Reason: ''{1}''",
-                                               
sType.getInnerClass().getName(), sType.getNotABeanReason());
-                       } else {
-                               throw new ParseException(session, "Invalid data 
type {0} encountered for parse type {1}", dt, sType);
-                       }
-               }
-
-               if (transform != null && o != null)
-                       o = transform.unswap(session, o, eType);
-
-               if (outer != null)
-                       setParent(eType, o, outer);
-
-               return (T)o;
-       }
-
-
-       
//--------------------------------------------------------------------------------
-       // Entry point methods
-       
//--------------------------------------------------------------------------------
-
-       @Override /* Parser */
-       public MsgPackParserSession createSession(Object input, ObjectMap op, 
Method javaMethod, Object outer,
-                       Locale locale, TimeZone timeZone, MediaType mediaType) {
-               return new MsgPackParserSession(ctx, op, input, javaMethod, 
outer, locale, timeZone, mediaType);
-       }
-
        @Override /* Parser */
-       protected <T> T doParse(ParserSession session, ClassMeta<T> type) 
throws Exception {
-               MsgPackParserSession s = (MsgPackParserSession)session;
-               MsgPackInputStream is = s.getInputStream();
-               T o = parseAnything(s, type, is, s.getOuter(), null);
-               return o;
+       public MsgPackParserSession createSession(ParserSessionArgs args) {
+               return new MsgPackParserSession(ctx, args);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
index 93f16e6..8827370 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
@@ -12,23 +12,23 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.msgpack;
 
-import java.io.*;
-import java.lang.reflect.*;
+import static org.apache.juneau.msgpack.DataType.*;
+
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.parser.*;
+import org.apache.juneau.transform.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link 
MsgPackParser}.
  *
  * <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 
against multiple inputs.
  */
-public final class MsgPackParserSession extends ParserSession {
-
-       private MsgPackInputStream inputStream;
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public final class MsgPackParserSession extends InputStreamParserSession {
 
        /**
         * Create a new session using properties specified in the context.
@@ -36,46 +36,166 @@ public final class MsgPackParserSession extends 
ParserSession {
         * @param ctx
         *      The context creating this session object.
         *      The context contains all the configuration settings for this 
object.
-        * @param input
-        *      The input.
-        *      Can be any of the following types:
-        *      <ul>
-        *              <li><jk>null</jk>
-        *              <li>{@link Reader}
-        *              <li>{@link CharSequence}
-        *              <li>{@link InputStream} containing UTF-8 encoded text.
-        *              <li>{@link File} containing system encoded text.
-        *      </ul>
-        * @param op
-        *      The override properties.
-        *      These override any context properties defined in the context.
-        * @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.
-        * @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 args
+        *      Runtime session arguments.
         */
-       public MsgPackParserSession(MsgPackParserContext ctx, ObjectMap op, 
Object input, Method javaMethod, Object outer,
-                       Locale locale, TimeZone timeZone, MediaType mediaType) {
-               super(ctx, op, input, javaMethod, outer, locale, timeZone, 
mediaType);
+       protected MsgPackParserSession(MsgPackParserContext ctx, 
ParserSessionArgs args) {
+               super(ctx, args);
        }
 
        @Override /* ParserSession */
-       public MsgPackInputStream getInputStream() throws ParseException {
-               if (inputStream == null)
-                       inputStream = new 
MsgPackInputStream(super.getInputStream());
-               return inputStream;
+       protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws 
Exception {
+               MsgPackInputStream is = new MsgPackInputStream(pipe);
+               T o = parseAnything(type, is, getOuter(), null);
+               return o;
        }
 
-       @Override /* ParserSession */
-       public Map<String,Object> getLastLocation() {
-               Map<String,Object> m = super.getLastLocation();
-               if (inputStream != null)
-                       m.put("position", inputStream.getPosition());
-               return m;
+       /*
+        * Workhorse method.
+        */
+       private <T> T parseAnything(ClassMeta<T> eType, MsgPackInputStream is, 
Object outer, BeanPropertyMeta pMeta) throws Exception {
+
+               if (eType == null)
+                       eType = (ClassMeta<T>)object();
+               PojoSwap<T,Object> transform = 
(PojoSwap<T,Object>)eType.getPojoSwap();
+               ClassMeta<?> sType = eType.getSerializedClassMeta();
+               setCurrentClass(sType);
+
+               Object o = null;
+               DataType dt = is.readDataType();
+               int length = (int)is.readLength();
+
+               if (dt != DataType.NULL) {
+                       if (dt == BOOLEAN)
+                               o = is.readBoolean();
+                       else if (dt == INT)
+                               o = is.readInt();
+                       else if (dt == LONG)
+                               o = is.readLong();
+                       else if (dt == FLOAT)
+                               o = is.readFloat();
+                       else if (dt == DOUBLE)
+                               o = is.readDouble();
+                       else if (dt == STRING)
+                               o = trim(is.readString());
+                       else if (dt == BIN)
+                               o = is.readBinary();
+                       else if (dt == ARRAY && sType.isObject()) {
+                               ObjectList ol = new ObjectList(this);
+                               for (int i = 0; i < length; i++)
+                                       ol.add(parseAnything(object(), is, 
outer, pMeta));
+                               o = ol;
+                       } else if (dt == MAP && sType.isObject()) {
+                               ObjectMap om = new ObjectMap(this);
+                               for (int i = 0; i < length; i++)
+                                       om.put(parseAnything(string(), is, 
outer, pMeta), parseAnything(object(), is, om, pMeta));
+                               o = cast(om, pMeta, eType);
+                       }
+
+                       if (sType.isObject()) {
+                               // Do nothing.
+                       } else if (sType.isBoolean() || sType.isCharSequence() 
|| sType.isChar() || sType.isNumber()) {
+                               o = convertToType(o, sType);
+                       } else if (sType.isMap()) {
+                               if (dt == MAP) {
+                                       Map m = 
(sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new 
ObjectMap(this));
+                                       for (int i = 0; i < length; i++) {
+                                               Object key = 
parseAnything(sType.getKeyType(), is, outer, pMeta);
+                                               ClassMeta<?> vt = 
sType.getValueType();
+                                               Object value = 
parseAnything(vt, is, m, pMeta);
+                                               setName(vt, value, key);
+                                               m.put(key, value);
+                                       }
+                                       o = m;
+                               } else {
+                                       throw new ParseException(loc(is), 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
+                               }
+                       } else if (sType.canCreateNewBean(outer)) {
+                               if (dt == MAP) {
+                                       BeanMap m = newBeanMap(outer, 
sType.getInnerClass());
+                                       for (int i = 0; i < length; i++) {
+                                               String pName = 
parseAnything(string(), is, m.getBean(false), null);
+                                               BeanPropertyMeta bpm = 
m.getPropertyMeta(pName);
+                                               if (bpm == null) {
+                                                       if 
(pName.equals(getBeanTypePropertyName(eType)))
+                                                               
parseAnything(string(), is, null, null);
+                                                       else
+                                                               
onUnknownProperty(is.getPipe(), pName, m, 0, is.getPosition());
+                                               } else {
+                                                       ClassMeta<?> cm = 
bpm.getClassMeta();
+                                                       Object value = 
parseAnything(cm, is, m.getBean(false), bpm);
+                                                       setName(cm, value, 
pName);
+                                                       bpm.set(m, pName, 
value);
+                                               }
+                                       }
+                                       o = m.getBean();
+                               } else {
+                                       throw new ParseException(loc(is), 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
+                               }
+                       } else if (sType.canCreateNewInstanceFromString(outer) 
&& dt == STRING) {
+                               o = sType.newInstanceFromString(outer, o == 
null ? "" : o.toString());
+                       } else if (sType.canCreateNewInstanceFromNumber(outer) 
&& dt.isOneOf(INT, LONG, FLOAT, DOUBLE)) {
+                               o = sType.newInstanceFromNumber(this, outer, 
(Number)o);
+                       } else if (sType.isCollection()) {
+                               if (dt == MAP) {
+                                       ObjectMap m = new ObjectMap(this);
+                                       for (int i = 0; i < length; i++)
+                                               m.put(parseAnything(string(), 
is, outer, pMeta), parseAnything(object(), is, m, pMeta));
+                                       o = cast(m, pMeta, eType);
+                               } else if (dt == ARRAY) {
+                                       Collection l = (
+                                               
sType.canCreateNewInstance(outer)
+                                               ? 
(Collection)sType.newInstance()
+                                               : new ObjectList(this)
+                                       );
+                                       for (int i = 0; i < length; i++)
+                                               
l.add(parseAnything(sType.getElementType(), is, l, pMeta));
+                                       o = l;
+                               } else {
+                                       throw new ParseException(loc(is), 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
+                               }
+                       } else if (sType.isArray() || sType.isArgs()) {
+                               if (dt == MAP) {
+                                       ObjectMap m = new ObjectMap(this);
+                                       for (int i = 0; i < length; i++)
+                                               m.put(parseAnything(string(), 
is, outer, pMeta), parseAnything(object(), is, m, pMeta));
+                                       o = cast(m, pMeta, eType);
+                               } else if (dt == ARRAY) {
+                                       Collection l = (
+                                               sType.isCollection() && 
sType.canCreateNewInstance(outer)
+                                               ? 
(Collection)sType.newInstance()
+                                               : new ObjectList(this)
+                                       );
+                                       for (int i = 0; i < length; i++)
+                                               
l.add(parseAnything(sType.isArgs() ? sType.getArg(i) : sType.getElementType(), 
is, l, pMeta));
+                                       o = toArray(sType, l);
+                               } else {
+                                       throw new ParseException(loc(is), 
"Invalid data type {0} encountered for parse type {1}", dt, sType);
+                               }
+                       } else if (dt == MAP) {
+                               ObjectMap m = new ObjectMap(this);
+                               for (int i = 0; i < length; i++)
+                                       m.put(parseAnything(string(), is, 
outer, pMeta), parseAnything(object(), is, m, pMeta));
+                               if 
(m.containsKey(getBeanTypePropertyName(eType)))
+                                       o = cast(m, pMeta, eType);
+                               else
+                                       throw new ParseException(loc(is), 
"Class ''{0}'' could not be instantiated.  Reason: ''{1}''",
+                                               
sType.getInnerClass().getName(), sType.getNotABeanReason());
+                       } else {
+                               throw new ParseException(loc(is), "Invalid data 
type {0} encountered for parse type {1}", dt, sType);
+                       }
+               }
+
+               if (transform != null && o != null)
+                       o = transform.unswap(this, o, eType);
+
+               if (outer != null)
+                       setParent(eType, o, outer);
+
+               return (T)o;
+       }
+
+       private ObjectMap loc(MsgPackInputStream is) {
+               return getLastLocation().append("position", is.getPosition());
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
index ad5ed97..ad4dbce 100644
--- a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
@@ -12,14 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.msgpack;
 
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
 
 /**
  * Serializes POJO models to MessagePack.
@@ -63,169 +58,8 @@ public class MsgPackSerializer extends 
OutputStreamSerializer {
                return new MsgPackSerializerBuilder(propertyStore);
        }
 
-       /**
-        * Workhorse method.
-        *
-        * <p>
-        * Determines the type of object, and then calls the appropriate 
type-specific serialization method.
-        */
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       MsgPackOutputStream serializeAnything(MsgPackSerializerSession session, 
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 = session.push(attrName, o, eType);
-               boolean isRecursion = aType == null;
-
-               // Handle recursion
-               if (aType == null) {
-                       o = null;
-                       aType = object();
-               }
-
-               sType = aType.getSerializedClassMeta();
-               String typeName = session.getBeanTypeName(eType, aType, pMeta);
-
-               // Swap if necessary
-               PojoSwap swap = aType.getPojoSwap();
-               if (swap != null) {
-                       o = swap.swap(session, o);
-
-                       // If the getSwapClass() method returns Object, we need 
to figure out
-                       // the actual type now.
-                       if (sType.isObject())
-                               sType = session.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(session, out, session.toBeanMap(o), 
typeName);
-               else if (sType.isUri() || (pMeta != null && pMeta.isUri()))
-                       out.appendString(session.resolveUri(o.toString()));
-               else if (sType.isMap()) {
-                       if (o instanceof BeanMap)
-                               serializeBeanMap(session, out, (BeanMap)o, 
typeName);
-                       else
-                               serializeMap(session, out, (Map)o, eType);
-               }
-               else if (sType.isCollection()) {
-                       serializeCollection(session, out, (Collection) o, 
eType);
-               }
-               else if (sType.isArray()) {
-                       serializeCollection(session, out, 
toList(sType.getInnerClass(), o), eType);
-               } else
-                       out.appendString(session.toString(o));
-
-               if (! isRecursion)
-                       session.pop();
-               return out;
-       }
-
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       private void serializeMap(MsgPackSerializerSession session, 
MsgPackOutputStream out, Map m, ClassMeta<?> type)
-                       throws Exception {
-
-               ClassMeta<?> keyType = type.getKeyType(), valueType = 
type.getValueType();
-
-               m = session.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 = session.generalize(e.key, keyType);
-
-                       serializeAnything(session, out, key, keyType, null, 
null);
-                       serializeAnything(session, out, value, valueType, null, 
null);
-               }
-       }
-
-       private void serializeBeanMap(MsgPackSerializerSession session, 
MsgPackOutputStream out, final BeanMap<?> m,
-                       String typeName) throws Exception {
-
-               List<BeanPropertyValue> values = 
m.getValues(session.isTrimNulls(), typeName != null ? 
session.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)
-                               session.onBeanGetterException(pMeta, t);
-                       else {
-                               serializeAnything(session, out, key, null, 
null, null);
-                               serializeAnything(session, 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(MsgPackSerializerSession session, 
MsgPackOutputStream out, Collection c,
-                       ClassMeta<?> type) throws Exception {
-
-               ClassMeta<?> elementType = type.getElementType();
-               List<Object> l = new ArrayList<Object>(c.size());
-
-               c = session.sort(c);
-               l.addAll(c);
-
-               out.startArray(l.size());
-
-               for (Object o : l)
-                       serializeAnything(session, out, o, elementType, 
"<iterator>", null);
-       }
-
-
-       
//--------------------------------------------------------------------------------
-       // Entry point methods
-       
//--------------------------------------------------------------------------------
-
-       @Override /* Serializer */
-       public MsgPackSerializerSession createSession(ObjectMap op, Method 
javaMethod, Locale locale,
-                       TimeZone timeZone, MediaType mediaType, UriContext 
uriContext) {
-               return new MsgPackSerializerSession(ctx, op, javaMethod, 
locale, timeZone, mediaType, uriContext);
-       }
-
        @Override /* Serializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               MsgPackSerializerSession s = (MsgPackSerializerSession)session;
-               serializeAnything(s, s.getMsgPackOutputStream(out), o, 
s.getExpectedRootType(o), "root", null);
+       public OutputStreamSerializerSession 
createSession(SerializerSessionArgs args) {
+               return new MsgPackSerializerSession(ctx, args);
        }
 }

Reply via email to