http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index 6de1afc..7ec11d6 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -12,24 +12,28 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.html;
 
+import static org.apache.juneau.html.HtmlSerializerSession.ContentResult.*;
 import static org.apache.juneau.html.HtmlSerializerContext.*;
 import static org.apache.juneau.msgpack.MsgPackSerializerContext.*;
 import static org.apache.juneau.xml.XmlUtils.*;
 
-import java.lang.reflect.*;
+import java.io.*;
 import java.util.*;
 import java.util.regex.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
 import org.apache.juneau.xml.*;
+import org.apache.juneau.xml.annotation.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link 
HtmlSerializer}.
  *
  * <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 class HtmlSerializerSession extends XmlSerializerSession {
 
@@ -54,26 +58,18 @@ public class HtmlSerializerSession extends 
XmlSerializerSession {
         * @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 HtmlSerializerSession(HtmlSerializerContext ctx, ObjectMap 
op, Method javaMethod,
-                       Locale locale, TimeZone timeZone, MediaType mediaType, 
UriContext uriContext) {
-               super(ctx, op, javaMethod, locale, timeZone, mediaType, 
uriContext);
+       protected HtmlSerializerSession(HtmlSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
                String labelParameter;
-               if (op == null || op.isEmpty()) {
+               ObjectMap p = getProperties();
+               if (p.isEmpty()) {
                        anchorText = Enum.valueOf(AnchorText.class, 
ctx.uriAnchorText);
                        detectLinksInStrings = ctx.detectLinksInStrings;
                        lookForLabelParameters = ctx.lookForLabelParameters;
@@ -81,12 +77,12 @@ public class HtmlSerializerSession extends 
XmlSerializerSession {
                        addKeyValueTableHeaders = ctx.addKeyValueTableHeaders;
                        addBeanTypeProperties = ctx.addBeanTypeProperties;
                } else {
-                       anchorText = Enum.valueOf(AnchorText.class, 
op.getString(HTML_uriAnchorText, ctx.uriAnchorText));
-                       detectLinksInStrings = 
op.getBoolean(HTML_detectLinksInStrings, ctx.detectLinksInStrings);
-                       lookForLabelParameters = 
op.getBoolean(HTML_lookForLabelParameters, ctx.lookForLabelParameters);
-                       labelParameter = op.getString(HTML_labelParameter, 
ctx.labelParameter);
-                       addKeyValueTableHeaders = 
op.getBoolean(HTML_addKeyValueTableHeaders, ctx.addKeyValueTableHeaders);
-                       addBeanTypeProperties = 
op.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
+                       anchorText = Enum.valueOf(AnchorText.class, 
p.getString(HTML_uriAnchorText, ctx.uriAnchorText));
+                       detectLinksInStrings = 
p.getBoolean(HTML_detectLinksInStrings, ctx.detectLinksInStrings);
+                       lookForLabelParameters = 
p.getBoolean(HTML_lookForLabelParameters, ctx.lookForLabelParameters);
+                       labelParameter = p.getString(HTML_labelParameter, 
ctx.labelParameter);
+                       addKeyValueTableHeaders = 
p.getBoolean(HTML_addKeyValueTableHeaders, ctx.addKeyValueTableHeaders);
+                       addBeanTypeProperties = 
p.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
                }
                labelPattern = Pattern.compile("[\\?\\&]" + 
Pattern.quote(labelParameter) + "=([^\\&]*)");
        }
@@ -98,12 +94,14 @@ public class HtmlSerializerSession extends 
XmlSerializerSession {
         * @return The output target object wrapped in an {@link HtmlWriter}.
         * @throws Exception
         */
-       public HtmlWriter getHtmlWriter(SerializerOutput out) throws Exception {
+       protected final HtmlWriter getHtmlWriter(SerializerPipe out) throws 
Exception {
                Object output = out.getRawOutput();
                if (output instanceof HtmlWriter)
                        return (HtmlWriter)output;
-               return new HtmlWriter(out.getWriter(), isUseWhitespace(), 
getMaxIndent(), isTrimStrings(), getQuoteChar(),
+               HtmlWriter w = new HtmlWriter(out.getWriter(), 
isUseWhitespace(), getMaxIndent(), isTrimStrings(), getQuoteChar(),
                        getUriResolver());
+               out.setWriter(w);
+               return w;
        }
 
        /**
@@ -196,4 +194,581 @@ public class HtmlSerializerSession extends 
XmlSerializerSession {
        public boolean isHtmlMode() {
                return true;
        }
+
+       @Override /* Serializer */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               doSerialize(o, getHtmlWriter(out));
+       }
+
+       /**
+        * Main serialization routine.
+        *
+        * @param session The serialization context object.
+        * @param o The object being serialized.
+        * @param w The writer to serialize to.
+        * @return The same writer passed in.
+        * @throws IOException If a problem occurred trying to send output to 
the writer.
+        */
+       private HtmlWriter doSerialize(Object o, HtmlWriter w) throws Exception 
{
+               serializeAnything(w, o, getExpectedRootType(o), null, 
getInitialDepth()-1, null, true);
+               return w;
+       }
+
+       /**
+        * Serialize the specified object to the specified writer.
+        *
+        * @param out The writer.
+        * @param o The object to serialize.
+        * @param eType The expected type of the object if this is a bean 
property.
+        * @param name
+        *      The attribute name of this object if this object was a field in 
a JSON object (i.e. key of a
+        *      {@link java.util.Map.Entry} or property name of a bean).
+        * @param xIndent The current indentation value.
+        * @param pMeta The bean property being serialized, or <jk>null</jk> if 
we're not serializing a bean property.
+        * @param isRoot <jk>true</jk> if this is the root element of the 
document.
+        * @return The type of content encountered.  Either simple (no 
whitespace) or normal (elements with whitespace).
+        * @throws Exception If a problem occurred trying to convert the output.
+        */
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       protected ContentResult serializeAnything(HtmlWriter out, Object o,
+                       ClassMeta<?> eType, String name, int xIndent, 
BeanPropertyMeta pMeta, boolean isRoot) throws Exception {
+
+               ClassMeta<?> aType = null;       // The actual type
+               ClassMeta<?> wType = null;     // The wrapped type (delegate)
+               ClassMeta<?> sType = object();   // The serialized type
+
+               if (eType == null)
+                       eType = object();
+
+               aType = push(name, o, eType);
+
+               // Handle recursion
+               if (aType == null) {
+                       o = null;
+                       aType = object();
+               }
+
+               indent += xIndent;
+
+               ContentResult cr = CR_NORMAL;
+
+               // Determine the type.
+               if (o == null || (aType.isChar() && ((Character)o).charValue() 
== 0)) {
+                       out.tag("null");
+                       cr = ContentResult.CR_SIMPLE;
+
+               } else {
+
+                       if (aType.isDelegate()) {
+                               wType = aType;
+                               aType = ((Delegate)o).getClassMeta();
+                       }
+
+                       sType = aType.getSerializedClassMeta();
+                       String typeName = null;
+                       if (isAddBeanTypeProperties() && ! eType.equals(aType))
+                               typeName = aType.getDictionaryName();
+
+                       // 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);
+                       }
+
+                       HtmlClassMeta html = 
sType.getExtendedMeta(HtmlClassMeta.class);
+                       HtmlRender render = (pMeta == null ? null : 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getRender());
+                       if (render == null)
+                               render = html.getRender();
+
+                       if (render != null) {
+                               Object o2 = render.getContent(this, o);
+                               if (o2 != o) {
+                                       indent -= xIndent;
+                                       pop();
+                                       out.nl(indent);
+                                       return serializeAnything(out, o2, null, 
typeName, xIndent, null, false);
+                               }
+                       }
+
+                       if (html.isAsXml() || (pMeta != null && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isAsXml())) {
+                               pop();
+                               indent++;
+                               super.serializeAnything(out, o, null, null, 
null, false, XmlFormat.MIXED, false, false, null);
+                               indent -= xIndent+1;
+                               return cr;
+
+                       } else if (html.isAsPlainText() || (pMeta != null && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isAsPlainText())) {
+                               out.write(o == null ? "null" : o.toString());
+                               cr = CR_SIMPLE;
+
+                       } else if (o == null || (sType.isChar() && 
((Character)o).charValue() == 0)) {
+                               out.tag("null");
+                               cr = CR_SIMPLE;
+
+                       } else if (sType.isNumber()) {
+                               if (eType.isNumber() && ! isRoot)
+                                       out.append(o);
+                               else
+                                       
out.sTag("number").append(o).eTag("number");
+                               cr = CR_SIMPLE;
+
+                       } else if (sType.isBoolean()) {
+                               if (eType.isBoolean() && ! isRoot)
+                                       out.append(o);
+                               else
+                                       
out.sTag("boolean").append(o).eTag("boolean");
+                               cr = CR_SIMPLE;
+
+                       } else if (sType.isMap() || (wType != null && 
wType.isMap())) {
+                               out.nlIf(! isRoot, xIndent+1);
+                               if (o instanceof BeanMap)
+                                       serializeBeanMap(out, (BeanMap)o, 
eType, pMeta);
+                               else
+                                       serializeMap(out, (Map)o, sType, 
eType.getKeyType(), eType.getValueType(), typeName, pMeta);
+
+                       } else if (sType.isBean()) {
+                               BeanMap m = toBeanMap(o);
+                               Class<?> c = o.getClass();
+                               if (c.isAnnotationPresent(HtmlLink.class)) {
+                                       HtmlLink h = 
o.getClass().getAnnotation(HtmlLink.class);
+                                       Object urlProp = 
m.get(h.hrefProperty());
+                                       Object nameProp = 
m.get(h.nameProperty());
+                                       out.oTag("a").attrUri("href", 
urlProp).append('>').text(nameProp).eTag("a");
+                                       cr = CR_SIMPLE;
+                               } else {
+                                       out.nlIf(! isRoot, xIndent+2);
+                                       serializeBeanMap(out, m, eType, pMeta);
+                               }
+
+                       } else if (sType.isCollection() || sType.isArray() || 
(wType != null && wType.isCollection())) {
+                               out.nlIf(! isRoot, xIndent+1);
+                               serializeCollection(out, o, sType, eType, name, 
pMeta);
+
+                       } else if (isUri(sType, pMeta, o)) {
+                               String label = getAnchorText(pMeta, o);
+                               out.oTag("a").attrUri("href", o).append('>');
+                               out.text(label);
+                               out.eTag("a");
+                               cr = CR_SIMPLE;
+
+                       } else {
+                               if (isRoot)
+                                       
out.sTag("string").text(toString(o)).eTag("string");
+                               else
+                                       out.text(toString(o));
+                               cr = CR_SIMPLE;
+                       }
+               }
+               pop();
+               indent -= xIndent;
+               return cr;
+       }
+
+       /**
+        * Identifies what the contents were of a serialized bean.
+        */
+       static enum ContentResult {
+               CR_SIMPLE,    // Simple content.  Shouldn't use whitespace.
+               CR_NORMAL     // Normal content.  Use whitespace.
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private void serializeMap(HtmlWriter out, Map m, ClassMeta<?> sType,
+                       ClassMeta<?> eKeyType, ClassMeta<?> eValueType, String 
typeName, BeanPropertyMeta ppMeta) throws Exception {
+
+               ClassMeta<?> keyType = eKeyType == null ? string() : eKeyType;
+               ClassMeta<?> valueType = eValueType == null ? object() : 
eValueType;
+               ClassMeta<?> aType = getClassMetaForObject(m);       // The 
actual type
+
+               int i = indent;
+
+               out.oTag(i, "table");
+
+               if (typeName != null && ppMeta != null && ppMeta.getClassMeta() 
!= aType)
+                       out.attr(getBeanTypePropertyName(sType), typeName);
+
+               out.append(">").nl(i+1);
+               if (isAddKeyValueTableHeaders() && ! 
(aType.getExtendedMeta(HtmlClassMeta.class).isNoTableHeaders()
+                               || (ppMeta != null && 
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isNoTableHeaders()))) {
+                       out.sTag(i+1, "tr").nl(i+2);
+                       out.sTag(i+2, "th").append("key").eTag("th").nl(i+3);
+                       out.sTag(i+2, "th").append("value").eTag("th").nl(i+3);
+                       out.ie(i+1).eTag("tr").nl(i+2);
+               }
+               for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
+
+                       Object key = generalize(e.getKey(), keyType);
+                       Object value = null;
+                       try {
+                               value = e.getValue();
+                       } catch (StackOverflowError t) {
+                               throw t;
+                       } catch (Throwable t) {
+                               onError(t, "Could not call getValue() on 
property ''{0}'', {1}", e.getKey(), t.getLocalizedMessage());
+                       }
+
+                       String link = getLink(ppMeta);
+                       String style = getStyle(this, ppMeta, value);
+
+                       out.sTag(i+1, "tr").nl(i+2);
+                       out.oTag(i+2, "td");
+                       if (style != null)
+                               out.attr("style", style);
+                       out.cTag();
+                       if (link != null)
+                               out.oTag(i+3, "a").attrUri("href", 
link.replace("{#}", StringUtils.toString(value))).cTag();
+                       ContentResult cr = serializeAnything(out, key, keyType, 
null, 2, null, false);
+                       if (link != null)
+                               out.eTag("a");
+                       if (cr == CR_NORMAL)
+                               out.i(i+2);
+                       out.eTag("td").nl(i+2);
+                       out.sTag(i+2, "td");
+                       cr = serializeAnything(out, value, valueType, (key == 
null ? "_x0000_" : toString(key)), 2, null, false);
+                       if (cr == CR_NORMAL)
+                               out.ie(i+2);
+                       out.eTag("td").nl(i+2);
+                       out.ie(i+1).eTag("tr").nl(i+1);
+               }
+               out.ie(i).eTag("table").nl(i);
+       }
+
+       private void serializeBeanMap(HtmlWriter out, BeanMap<?> m, 
ClassMeta<?> eType,
+                       BeanPropertyMeta ppMeta) throws Exception {
+               int i = indent;
+
+               out.oTag(i, "table");
+
+               String typeName = m.getMeta().getDictionaryName();
+               if (typeName != null && eType != m.getClassMeta())
+                       out.attr(getBeanTypePropertyName(m.getClassMeta()), 
typeName);
+
+               out.append('>').nl(i);
+               if (isAddKeyValueTableHeaders() && ! 
(m.getClassMeta().getExtendedMeta(HtmlClassMeta.class).isNoTableHeaders()
+                               || (ppMeta != null && 
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isNoTableHeaders()))) {
+                       out.sTag(i+1, "tr").nl(i+1);
+                       out.sTag(i+2, "th").append("key").eTag("th").nl(i+2);
+                       out.sTag(i+2, "th").append("value").eTag("th").nl(i+2);
+                       out.ie(i+1).eTag("tr").nl(i+1);
+               }
+
+               for (BeanPropertyValue p : m.getValues(isTrimNulls())) {
+                       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;
+
+                       String link = cMeta.isCollectionOrArray() ? null : 
getLink(pMeta);
+
+                       out.sTag(i+1, "tr").nl(i+1);
+                       out.sTag(i+2, "td").text(key).eTag("td").nl(i+2);
+                       out.oTag(i+2, "td");
+                       String style = getStyle(this, pMeta, value);
+                       if (style != null)
+                               out.attr("style", style);
+                       out.cTag();
+
+                       try {
+                               if (link != null)
+                                       out.oTag(i+3, "a").attrUri("href", 
m.resolveVars(link)).cTag();
+                               ContentResult cr = serializeAnything(out, 
value, cMeta, key, 2, pMeta, false);
+                               if (cr == CR_NORMAL)
+                                       out.i(i+2);
+                               if (link != null)
+                                       out.eTag("a");
+                       } catch (SerializeException e) {
+                               throw e;
+                       } catch (Error e) {
+                               throw e;
+                       } catch (Throwable e) {
+                               e.printStackTrace();
+                               onBeanGetterException(pMeta, e);
+                       }
+                       out.eTag("td").nl(i+2);
+                       out.ie(i+1).eTag("tr").nl(i+1);
+               }
+               out.ie(i).eTag("table").nl(i);
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private void serializeCollection(HtmlWriter out, Object in, 
ClassMeta<?> sType,
+                       ClassMeta<?> eType, String name, BeanPropertyMeta 
ppMeta) throws Exception {
+
+               ClassMeta<?> seType = sType.getElementType();
+               if (seType == null)
+                       seType = object();
+
+               Collection c = (sType.isCollection() ? (Collection)in : 
toList(sType.getInnerClass(), in));
+
+               int i = indent;
+               if (c.isEmpty()) {
+                       out.appendln(i, "<ul></ul>");
+                       return;
+               }
+
+               String type2 = null;
+               if (sType != eType)
+                       type2 = sType.getDictionaryName();
+               if (type2 == null)
+                       type2 = "array";
+
+               c = sort(c);
+
+               HtmlBeanPropertyMeta hbpMeta = (ppMeta == null ? null : 
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class));
+               String btpn = getBeanTypePropertyName(eType);
+
+               // Look at the objects to see how we're going to handle them.  
Check the first object to see how we're going to
+               // handle this.
+               // If it's a map or bean, then we'll create a table.
+               // Otherwise, we'll create a list.
+               Object[] th = getTableHeaders(c, hbpMeta);
+
+               if (th != null) {
+
+                       out.oTag(i, "table").attr(btpn, 
type2).append('>').nl(i+1);
+                       out.sTag(i+1, "tr").nl(i+2);
+                       for (Object key : th) {
+                               out.sTag(i+2, "th");
+                               out.text(convertToType(key, String.class));
+                               out.eTag("th").nl(i+2);
+                       }
+                       out.ie(i+1).eTag("tr").nl(i+1);
+
+                       for (Object o : c) {
+                               ClassMeta<?> cm = getClassMetaForObject(o);
+
+                               if (cm != null && cm.getPojoSwap() != null) {
+                                       PojoSwap f = cm.getPojoSwap();
+                                       o = f.swap(this, o);
+                                       cm = cm.getSerializedClassMeta();
+                               }
+
+                               out.oTag(i+1, "tr");
+                               String typeName = (cm == null ? null : 
cm.getDictionaryName());
+                               String typeProperty = 
getBeanTypePropertyName(cm);
+
+                               if (typeName != null && eType.getElementType() 
!= cm)
+                                       out.attr(typeProperty, typeName);
+                               out.cTag().nl(i+2);
+
+                               if (cm == null) {
+                                       serializeAnything(out, o, null, null, 
1, null, false);
+
+                               } else if (cm.isMap() && ! (cm.isBeanMap())) {
+                                       Map m2 = sort((Map)o);
+
+                                       for (Object k : th) {
+                                               out.sTag(i+2, "td");
+                                               ContentResult cr = 
serializeAnything(out, m2.get(k), eType.getElementType(), toString(k), 2, null, 
false);
+                                               if (cr == CR_NORMAL)
+                                                       out.i(i+2);
+                                               out.eTag("td").nl(i+2);
+                                       }
+                               } else {
+                                       BeanMap m2 = null;
+                                       if (o instanceof BeanMap)
+                                               m2 = (BeanMap)o;
+                                       else
+                                               m2 = toBeanMap(o);
+
+                                       for (Object k : th) {
+                                               BeanMapEntry p = 
m2.getProperty(toString(k));
+                                               BeanPropertyMeta pMeta = 
p.getMeta();
+                                               String link = 
pMeta.getClassMeta().isCollectionOrArray() ? null : getLink(pMeta);
+                                               Object value = p.getValue();
+                                               String style = getStyle(this, 
pMeta, value);
+                                               out.oTag(i+2, "td");
+                                               if (style != null)
+                                                       out.attr("style", 
style);
+                                               out.cTag();
+                                               if (link != null)
+                                                       
out.oTag("a").attrUri("href", m2.resolveVars(link)).cTag();
+                                               ContentResult cr = 
serializeAnything(out, value, pMeta.getClassMeta(), p.getKey().toString(), 2, 
pMeta, false);
+                                               if (cr == CR_NORMAL)
+                                                       out.i(i+2);
+                                               if (link != null)
+                                                       out.eTag("a");
+                                               out.eTag("td").nl(i+2);
+                                       }
+                               }
+                               out.ie(i+1).eTag("tr").nl(i+1);
+                       }
+                       out.ie(i).eTag("table").nl(i);
+
+               } else {
+                       out.oTag(i, "ul");
+                       if (! type2.equals("array"))
+                               out.attr(btpn, type2);
+                       out.append('>').nl(i+1);
+                       for (Object o : c) {
+                               out.oTag(i+1, "li");
+                               String style = getStyle(this, ppMeta, o);
+                               String link = getLink(ppMeta);
+                               if (style != null)
+                                       out.attr("style", style);
+                               out.cTag();
+                               if (link != null)
+                                       out.oTag(i+2, "a").attrUri("href", 
link.replace("{#}", StringUtils.toString(o))).cTag();
+                               ContentResult cr = serializeAnything(out, o, 
eType.getElementType(), name, 1, null, false);
+                               if (link != null)
+                                       out.eTag("a");
+                               if (cr == CR_NORMAL)
+                                       out.ie(i+1);
+                               out.eTag("li").nl(i+1);
+                       }
+                       out.ie(i).eTag("ul").nl(i);
+               }
+       }
+
+       private static HtmlRender<?> getRender(HtmlSerializerSession session, 
BeanPropertyMeta pMeta, Object value) {
+               if (pMeta == null)
+                       return null;
+               HtmlBeanPropertyMeta hpMeta = 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);
+               HtmlRender<?> render = hpMeta.getRender();
+               if (render != null)
+                       return render;
+               ClassMeta<?> cMeta = session.getClassMetaForObject(value);
+               render = cMeta == null ? null : 
cMeta.getExtendedMeta(HtmlClassMeta.class).getRender();
+               return render;
+       }
+
+       @SuppressWarnings({"rawtypes","unchecked"})
+       private static String getStyle(HtmlSerializerSession session, 
BeanPropertyMeta pMeta, Object value) {
+               HtmlRender render = getRender(session, pMeta, value);
+               return render == null ? null : render.getStyle(session, value);
+       }
+
+       private static String getLink(BeanPropertyMeta pMeta) {
+               return pMeta == null ? null : 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getLink();
+       }
+
+       /*
+        * Returns the table column headers for the specified collection of 
objects.
+        * Returns null if collection should not be serialized as a 
2-dimensional table.
+        * 2-dimensional tables are used for collections of objects that all 
have the same set of property names.
+        */
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       private Object[] getTableHeaders(Collection c, HtmlBeanPropertyMeta 
hbpMeta) throws Exception {
+               if (c.size() == 0)
+                       return null;
+               c = sort(c);
+               Object[] th;
+               Set<ClassMeta> prevC = new HashSet<ClassMeta>();
+               Object o1 = null;
+               for (Object o : c)
+                       if (o != null) {
+                               o1 = o;
+                               break;
+                       }
+               if (o1 == null)
+                       return null;
+               ClassMeta<?> cm = getClassMetaForObject(o1);
+               if (cm.getPojoSwap() != null) {
+                       PojoSwap f = cm.getPojoSwap();
+                       o1 = f.swap(this, o1);
+                       cm = cm.getSerializedClassMeta();
+               }
+               if (cm == null || ! cm.isMapOrBean())
+                       return null;
+               if (cm.getInnerClass().isAnnotationPresent(HtmlLink.class))
+                       return null;
+               HtmlClassMeta h = cm.getExtendedMeta(HtmlClassMeta.class);
+               if (h.isNoTables() || (hbpMeta != null && hbpMeta.isNoTables()))
+                       return null;
+               if (h.isNoTableHeaders() || (hbpMeta != null && 
hbpMeta.isNoTableHeaders()))
+                       return new Object[0];
+               if (canIgnoreValue(cm, null, o1))
+                       return null;
+               if (cm.isMap() && ! cm.isBeanMap()) {
+                       Set<Object> set = new LinkedHashSet<Object>();
+                       for (Object o : c) {
+                               if (! canIgnoreValue(cm, null, o)) {
+                                       if (! cm.isInstance(o))
+                                               return null;
+                                       Map m = sort((Map)o);
+                                       for (Map.Entry e : 
(Set<Map.Entry>)m.entrySet()) {
+                                               if (e.getValue() != null)
+                                                       set.add(e.getKey() == 
null ? null : e.getKey());
+                                       }
+                               }
+                       }
+                       th = set.toArray(new Object[set.size()]);
+               } else {
+                       Map<String,Boolean> m = new 
LinkedHashMap<String,Boolean>();
+                       for (Object o : c) {
+                               if (! canIgnoreValue(cm, null, o)) {
+                                       if (! cm.isInstance(o))
+                                               return null;
+                                       BeanMap<?> bm = (o instanceof BeanMap ? 
(BeanMap)o : toBeanMap(o));
+                                       for (Map.Entry<String,Object> e : 
bm.entrySet()) {
+                                               String key = e.getKey();
+                                               if (e.getValue() != null)
+                                                       m.put(key, true);
+                                               else if (! m.containsKey(key))
+                                                       m.put(key, false);
+                                       }
+                               }
+                       }
+                       for (Iterator<Boolean> i = m.values().iterator(); 
i.hasNext();)
+                               if (! i.next())
+                                       i.remove();
+                       th = m.keySet().toArray(new Object[m.size()]);
+               }
+               prevC.add(cm);
+               boolean isSortable = true;
+               for (Object o : th)
+                       isSortable &= (o instanceof Comparable);
+               Set<Object> s = (isSortable ? new TreeSet<Object>() : new 
LinkedHashSet<Object>());
+               s.addAll(Arrays.asList(th));
+
+               for (Object o : c) {
+                       if (o == null)
+                               continue;
+                       cm = getClassMetaForObject(o);
+                       if (cm != null && cm.getPojoSwap() != null) {
+                               PojoSwap f = cm.getPojoSwap();
+                               o = f.swap(this, o);
+                               cm = cm.getSerializedClassMeta();
+                       }
+                       if (prevC.contains(cm))
+                               continue;
+                       if (cm == null || ! (cm.isMap() || cm.isBean()))
+                               return null;
+                       if 
(cm.getInnerClass().isAnnotationPresent(HtmlLink.class))
+                               return null;
+                       if (canIgnoreValue(cm, null, o))
+                               return null;
+                       if (cm.isMap() && ! cm.isBeanMap()) {
+                               Map m = (Map)o;
+                               if (th.length != m.keySet().size())
+                                       return null;
+                               for (Object k : m.keySet())
+                                       if (! s.contains(k.toString()))
+                                               return null;
+                       } else {
+                               BeanMap<?> bm = (o instanceof BeanMap ? 
(BeanMap)o : toBeanMap(o));
+                               int l = 0;
+                               for (String k : bm.keySet()) {
+                                       if (! s.contains(k))
+                                               return null;
+                                       l++;
+                               }
+                               if (s.size() != l)
+                                       return null;
+                       }
+               }
+               return th;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
index 938fecf..2d61aab 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
@@ -12,9 +12,6 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.html;
 
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.serializer.*;
@@ -47,19 +44,8 @@ public class HtmlStrippedDocSerializer extends 
HtmlSerializer {
                super(propertyStore);
        }
 
-       
//---------------------------------------------------------------------------
-       // Overridden methods
-       
//---------------------------------------------------------------------------
-
        @Override /* Serializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               HtmlSerializerSession s = (HtmlSerializerSession)session;
-               HtmlWriter w = s.getHtmlWriter(out);
-               if (o == null
-                       || (o instanceof Collection && 
((Collection<?>)o).size() == 0)
-                       || (o.getClass().isArray() && Array.getLength(o) == 0))
-                       w.sTag(1, "p").append("No Results").eTag("p").nl(1);
-               else
-                       super.doSerialize(s, out, o);
+       public WriterSerializerSession createSession(SerializerSessionArgs 
args) {
+               return new HtmlStrippedDocSerializerSession(ctx, args);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializerSession.java
new file mode 100644
index 0000000..7589781
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializerSession.java
@@ -0,0 +1,51 @@
+// 
***************************************************************************************************************************
+// * 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.html;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.serializer.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link 
HtmlStrippedDocSerializer}.
+ *
+ * <p>
+ * This class is NOT thread safe.  It is meant to be discarded after one-time 
use.
+ */
+public class HtmlStrippedDocSerializerSession extends HtmlSerializerSession {
+
+       /**
+        * 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.
+        */
+       protected HtmlStrippedDocSerializerSession(HtmlSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+       }
+
+       @Override /* SerializerSession */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               HtmlWriter w = getHtmlWriter(out);
+               if (o == null
+                       || (o instanceof Collection && 
((Collection<?>)o).size() == 0)
+                       || (o.getClass().isArray() && Array.getLength(o) == 0))
+                       w.sTag(1, "p").append("No Results").eTag("p").nl(1);
+               else
+                       super.doSerialize(out, o);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
index c93aa5d..e841931 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
@@ -129,8 +129,6 @@ enum HtmlTag {
                        t = (end ? xP : P);
                else if (c == 'h')
                        t = (end ? xHTML : HTML);
-               if (t == null)
-                       throw new XmlParseException(null, "Unknown tag ''{0}'' 
encountered", tag);
                return t;
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java 
b/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
index b2da86a..1c3626e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
@@ -261,7 +261,7 @@ public final class IOUtils {
         *      reader.
         */
        public static Reader getBufferedReader(Reader r) {
-               if (r instanceof BufferedReader || r instanceof StringReader)
+               if (r == null || r instanceof BufferedReader || r instanceof 
StringReader)
                        return r;
                return new BufferedReader(r);
        }
@@ -410,6 +410,59 @@ public final class IOUtils {
        }
 
        /**
+        * Flushes multiple output streams and writers in a single call.
+        *
+        * @param o
+        *      The objects to flush.
+        *      <jk>null</jk> entries are ignored.
+        * @throws IOException
+        */
+       public static void flush(Object...o) throws IOException {
+               IOException ex = null;
+               for (Object o2 : o) {
+                       try {
+                               if (o2 instanceof OutputStream)
+                                       ((OutputStream)o2).flush();
+                               if (o2 instanceof Writer)
+                                       ((Writer)o2).flush();
+                       } catch (IOException e) {
+                               ex = e;
+                       }
+               }
+               if (ex != null)
+                       throw ex;
+       }
+
+       /**
+        * Close all specified input streams, output streams, readers, and 
writers.
+        *
+        * @param o
+        *      The list of all objects to close.
+        *      <jk>null</jk> entries are ignored.
+        * @throws IOException
+        */
+       public static void close(Object...o) throws IOException {
+               IOException ex = null;
+               for (Object o2 : o) {
+                       try {
+                               if (o2 instanceof InputStream)
+                                       ((InputStream)o2).close();
+                               if (o2 instanceof OutputStream)
+                                       ((OutputStream)o2).close();
+                               if (o2 instanceof Reader)
+                                       ((Reader)o2).close();
+                               if (o2 instanceof Writer)
+                                       ((Writer)o2).close();
+                       } catch (IOException e) {
+                               ex = e;
+                       }
+               }
+               if (ex != null)
+                       throw ex;
+       }
+
+
+       /**
         * Converts an object to an <code>InputStream</code>.
         *
         * @param o

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/jso/JsoParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/jso/JsoParser.java 
b/juneau-core/src/main/java/org/apache/juneau/jso/JsoParser.java
index 67a302f..599fa17 100644
--- a/juneau-core/src/main/java/org/apache/juneau/jso/JsoParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/jso/JsoParser.java
@@ -46,15 +46,8 @@ public final class JsoParser extends InputStreamParser {
                return new JsoParserBuilder(propertyStore);
        }
 
-
-       
//--------------------------------------------------------------------------------
-       // Overridden methods
-       
//--------------------------------------------------------------------------------
-
-       @SuppressWarnings("unchecked")
-       @Override /* InputStreamParser */
-       protected <T> T doParse(ParserSession session, ClassMeta<T> type) 
throws Exception {
-               ObjectInputStream ois = new 
ObjectInputStream(session.getInputStream());
-               return (T)ois.readObject();
+       @Override /* Parser */
+       public InputStreamParserSession createSession(ParserSessionArgs args) {
+               return new JsoParserSession(args);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/jso/JsoParserSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/jso/JsoParserSession.java 
b/juneau-core/src/main/java/org/apache/juneau/jso/JsoParserSession.java
new file mode 100644
index 0000000..12f9cf2
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/jso/JsoParserSession.java
@@ -0,0 +1,45 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.jso;
+
+import java.io.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.parser.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link 
JsoParser}.
+ *
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused 
against multiple inputs.
+ */
+@SuppressWarnings("unchecked")
+public class JsoParserSession extends InputStreamParserSession {
+
+       /**
+        * Create a new session using properties specified in the context.
+        *
+        * @param args
+        *      Runtime session arguments.
+        */
+       protected JsoParserSession(ParserSessionArgs args) {
+               super(args);
+       }
+
+       @Override /* ParserSession */
+       protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws 
Exception {
+               ObjectInputStream ois = new 
ObjectInputStream(pipe.getInputStream());
+               return (T)ois.readObject();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializer.java
index 6ea9e43..6e3ceb8 100644
--- a/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializer.java
@@ -34,6 +34,7 @@ public class JsoSerializer extends OutputStreamSerializer {
        /** Default serializer, all default settings.*/
        public static final JsoSerializer DEFAULT = new 
JsoSerializer(PropertyStore.create());
 
+       private final SerializerContext ctx;
 
        /**
         * Constructor.
@@ -42,6 +43,7 @@ public class JsoSerializer extends OutputStreamSerializer {
         */
        public JsoSerializer(PropertyStore propertyStore) {
                super(propertyStore);
+               this.ctx = createContext(SerializerContext.class);
        }
 
        @Override /* CoreObject */
@@ -49,15 +51,8 @@ public class JsoSerializer extends OutputStreamSerializer {
                return new JsoSerializerBuilder(propertyStore);
        }
 
-       
//--------------------------------------------------------------------------------
-       // Overridden methods
-       
//--------------------------------------------------------------------------------
-
-       @Override /* OutputStreamSerializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               ObjectOutputStream oos = new 
ObjectOutputStream(out.getOutputStream());
-               oos.writeObject(o);
-               oos.flush();
-               oos.close();
+       @Override /* Serializer */
+       public OutputStreamSerializerSession 
createSession(SerializerSessionArgs args) {
+               return new JsoSerializerSession(ctx, args);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializerSession.java
new file mode 100644
index 0000000..a445ac4
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/jso/JsoSerializerSession.java
@@ -0,0 +1,52 @@
+// 
***************************************************************************************************************************
+// * 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.jso;
+
+import java.io.*;
+
+import org.apache.juneau.serializer.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link 
JsoSerializer}.
+ *
+ * <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 JsoSerializerSession extends OutputStreamSerializerSession {
+
+       /**
+        * 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 JsoSerializerSession(SerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+       }
+
+       @Override /* OutputStreamSerializerSession */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               ObjectOutputStream oos = new 
ObjectOutputStream(out.getOutputStream());
+               oos.writeObject(o);
+               oos.flush();
+               oos.close();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/json/JsonParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/json/JsonParser.java 
b/juneau-core/src/main/java/org/apache/juneau/json/JsonParser.java
index 3afd115..460ae5d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/JsonParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/json/JsonParser.java
@@ -13,18 +13,10 @@
 package org.apache.juneau.json;
 
 import static org.apache.juneau.parser.ParserContext.*;
-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.annotation.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
-import org.apache.juneau.transform.*;
 
 /**
  * Parses any valid JSON text into a POJO model.
@@ -116,7 +108,6 @@ import org.apache.juneau.transform.*;
  *     <li>{@link JsonParserContext}
  * </ul>
  */
-@SuppressWarnings({ "rawtypes", "unchecked" })
 @Consumes("application/json,text/json")
 public class JsonParser extends ReaderParser {
 
@@ -126,9 +117,6 @@ public class JsonParser extends ReaderParser {
        /** Default parser, all default settings.*/
        public static final JsonParser DEFAULT_STRICT = new 
JsonParser.Strict(PropertyStore.create());
 
-       private static final AsciiSet decChars = new AsciiSet("0123456789");
-
-
        /** Default parser, strict mode. */
        public static class Strict extends JsonParser {
 
@@ -138,12 +126,7 @@ public class JsonParser extends ReaderParser {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public Strict(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(PARSER_strict, true);
+                       super(propertyStore.copy().append(PARSER_strict, true));
                }
        }
 
@@ -165,680 +148,8 @@ public class JsonParser extends ReaderParser {
                return new JsonParserBuilder(propertyStore);
        }
 
-       private <T> T parseAnything(JsonParserSession session, 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();
-               session.setCurrentClass(sType);
-               String wrapperAttr = 
sType.getExtendedMeta(JsonClassMeta.class).getWrapperAttr();
-
-               Object o = null;
-
-               skipCommentsAndSpace(session, r);
-               if (wrapperAttr != null)
-                       skipWrapperAttrStart(session, r, wrapperAttr);
-               int c = r.peek();
-               if (c == -1) {
-                       if (session.isStrict())
-                               throw new ParseException(session, "Empty 
input.");
-                       // Let o be null.
-               } else if ((c == ',' || c == '}' || c == ']')) {
-                       if (session.isStrict())
-                               throw new ParseException(session, "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(session, "null", r);
-               } else if (sType.isObject()) {
-                       if (c == '{') {
-                               ObjectMap m2 = new ObjectMap(session);
-                               parseIntoMap2(session, r, m2, string(), 
object(), pMeta);
-                               o = session.cast(m2, pMeta, eType);
-                       } else if (c == '[') {
-                               o = parseIntoCollection2(session, r, new 
ObjectList(session), object(), pMeta);
-                       } else if (c == '\'' || c == '"') {
-                               o = parseString(session, r);
-                               if (sType.isChar())
-                                       o = o.toString().charAt(0);
-                       } else if (c >= '0' && c <= '9' || c == '-' || c == 
'.') {
-                               o = parseNumber(session, r, null);
-                       } else if (c == 't') {
-                               parseKeyword(session, "true", r);
-                               o = Boolean.TRUE;
-                       } else {
-                               parseKeyword(session, "false", r);
-                               o = Boolean.FALSE;
-                       }
-               } else if (sType.isBoolean()) {
-                       o = parseBoolean(session, r);
-               } else if (sType.isCharSequence()) {
-                       o = parseString(session, r);
-               } else if (sType.isChar()) {
-                       o = parseString(session, r).charAt(0);
-               } else if (sType.isNumber()) {
-                       o = parseNumber(session, r, (Class<? extends 
Number>)sType.getInnerClass());
-               } else if (sType.isMap()) {
-                       Map m = (sType.canCreateNewInstance(outer) ? 
(Map)sType.newInstance(outer) : new ObjectMap(session));
-                       o = parseIntoMap2(session, r, m, sType.getKeyType(), 
sType.getValueType(), pMeta);
-               } else if (sType.isCollection()) {
-                       if (c == '{') {
-                               ObjectMap m = new ObjectMap(session);
-                               parseIntoMap2(session, r, m, string(), 
object(), pMeta);
-                               o = session.cast(m, pMeta, eType);
-                       } else {
-                               Collection l = 
(sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance() : new 
ObjectList(session));
-                               o = parseIntoCollection2(session, r, l, sType, 
pMeta);
-                       }
-               } else if (sType.canCreateNewBean(outer)) {
-                       BeanMap m = session.newBeanMap(outer, 
sType.getInnerClass());
-                       o = parseIntoBeanMap2(session, r, m).getBean();
-               } else if (sType.canCreateNewInstanceFromString(outer) && (c == 
'\'' || c == '"')) {
-                       o = sType.newInstanceFromString(outer, 
parseString(session, r));
-               } else if (sType.canCreateNewInstanceFromNumber(outer) && 
isFirstNumberChar((char)c)) {
-                       o = sType.newInstanceFromNumber(session, outer, 
parseNumber(session, r, sType.getNewInstanceFromNumberClass()));
-               } else if (sType.isArray() || sType.isArgs()) {
-                       if (c == '{') {
-                               ObjectMap m = new ObjectMap(session);
-                               parseIntoMap2(session, r, m, string(), 
object(), pMeta);
-                               o = session.cast(m, pMeta, eType);
-                       } else {
-                               ArrayList l = 
(ArrayList)parseIntoCollection2(session, r, new ArrayList(), sType, pMeta);
-                               o = session.toArray(sType, l);
-                       }
-               } else if (c == '{') {
-                       Map m = new ObjectMap(session);
-                       parseIntoMap2(session, r, m, sType.getKeyType(), 
sType.getValueType(), pMeta);
-                       if 
(m.containsKey(session.getBeanTypePropertyName(eType)))
-                               o = session.cast((ObjectMap)m, pMeta, eType);
-                       else
-                               throw new ParseException(session, "Class 
''{0}'' could not be instantiated.  Reason: ''{1}''",
-                                               
sType.getInnerClass().getName(), sType.getNotABeanReason());
-               } else if (sType.canCreateNewInstanceFromString(outer) && ! 
session.isStrict()) {
-                       o = sType.newInstanceFromString(outer, 
parseString(session, r));
-               } else {
-                       throw new ParseException(session, "Unrecognized syntax 
for class type ''{0}'', starting character ''{1}''",
-                               sType, (char)c);
-               }
-
-               if (wrapperAttr != null)
-                       skipWrapperAttrEnd(session, r);
-
-               if (transform != null && o != null)
-                       o = transform.unswap(session, o, eType);
-
-               if (outer != null)
-                       setParent(eType, o, outer);
-
-               return (T)o;
-       }
-
-       private Number parseNumber(JsonParserSession session, ParserReader r, 
Class<? extends Number> type) throws Exception {
-               int c = r.peek();
-               if (c == '\'' || c == '"')
-                       return parseNumber(session, parseString(session, r), 
type);
-               return parseNumber(session, parseNumberString(r), type);
-       }
-
-       private static Number parseNumber(JsonParserSession session, 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 (session.isStrict()) {
-
-                       // Lax allows blank strings to represent 0.
-                       // Strict does not allow blank strings.
-                       if (s.length() == 0)
-                               throw new ParseException(session, "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(session, "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(session, 
"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(session, "Invalid JSON 
number: ''{0}''", s);
-
-               }
-               return StringUtils.parseNumber(s, type);
-       }
-
-       private Boolean parseBoolean(JsonParserSession session, ParserReader r) 
throws Exception {
-               int c = r.peek();
-               if (c == '\'' || c == '"')
-                       return Boolean.valueOf(parseString(session, r));
-               if (c == 't') {
-                       parseKeyword(session, "true", r);
-                       return Boolean.TRUE;
-               }
-               parseKeyword(session, "false", r);
-               return Boolean.FALSE;
-       }
-
-
-       private <K,V> Map<K,V> parseIntoMap2(JsonParserSession session, 
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 (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       currAttr = parseFieldName(session, 
r.unread());
-                                       state = S3;
-                               }
-                       } else if (state == S3) {
-                               if (c == ':')
-                                       state = S4;
-                       } else if (state == S4) {
-                               if (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       K key = convertAttrToType(session, m, 
currAttr, keyType);
-                                       V value = parseAnything(session, 
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 (session.isCommentOrWhitespace(c))
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               else if (c == '}') {
-                                       return m;
-                               } else {
-                                       break;
-                               }
-                       } else if (state == S6) {
-                               if (c == '}') {
-                                       break;
-                               } else if (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       currAttr = parseFieldName(session, 
r.unread());
-                                       state = S3;
-                               }
-                       }
-               }
-               if (state == S0)
-                       throw new ParseException(session, "Expected '{' at 
beginning of JSON object.");
-               if (state == S1)
-                       throw new ParseException(session, "Could not find 
attribute name on JSON object.");
-               if (state == S3)
-                       throw new ParseException(session, "Could not find ':' 
following attribute name on JSON object.");
-               if (state == S4)
-                       throw new ParseException(session, "Expected one of the 
following characters: {,[,',\",LITERAL.");
-               if (state == S5)
-                       throw new ParseException(session, "Could not find '}' 
marking end of JSON object.");
-               if (state == S6)
-                       throw new ParseException(session, "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(JsonParserSession session, ParserReader 
r) throws Exception {
-               int c = r.peek();
-               if (c == '\'' || c == '"')
-                       return parseString(session, r);
-               if (session.isStrict())
-                       throw new ParseException(session, "Unquoted attribute 
detected.");
-               r.mark();
-               // Look for whitespace.
-               while (c != -1) {
-                       c = r.read();
-                       if (c == ':' || session.isWhitespace(c) || c == '/') {
-                               r.unread();
-                               String s = r.getMarked().intern();
-                               return s.equals("null") ? null : s;
-                       }
-               }
-               throw new ParseException(session, "Could not find the end of 
the field name.");
-       }
-
-       private <E> Collection<E> parseIntoCollection2(JsonParserSession 
session, 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 (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else if (c != -1) {
-                                       l.add((E)parseAnything(session, 
type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), r.unread(), l, 
pMeta));
-                                       state = S2;
-                               }
-                       } else if (state == S2) {
-                               if (c == ',') {
-                                       state = S3;
-                               } else if (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else if (c == ']') {
-                                       return l;
-                               } else {
-                                       break;  // Invalid character found.
-                               }
-                       } else if (state == S3) {
-                               if (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else if (c == ']') {
-                                       break;
-                               } else if (c != -1) {
-                                       l.add((E)parseAnything(session, 
type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), r.unread(), l, 
pMeta));
-                                       state = S2;
-                               }
-                       }
-               }
-               if (state == S0)
-                       throw new ParseException(session, "Expected '[' at 
beginning of JSON array.");
-               if (state == S1)
-                       throw new ParseException(session, "Expected one of the 
following characters: {,[,',\",LITERAL.");
-               if (state == S2)
-                       throw new ParseException(session, "Expected ',' or 
']'.");
-               if (state == S3)
-                       throw new ParseException(session, "Unexpected trailing 
comma in array.");
-
-               return null;  // Unreachable.
-       }
-
-       private <T> BeanMap<T> parseIntoBeanMap2(JsonParserSession session, 
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 (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       r.unread();
-                                       currAttrLine= r.getLine();
-                                       currAttrCol = r.getColumn();
-                                       currAttr = parseFieldName(session, r);
-                                       state = S3;
-                               }
-                       } else if (state == S3) {
-                               if (c == ':')
-                                       state = S4;
-                       } else if (state == S4) {
-                               if (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       if (! 
currAttr.equals(session.getBeanTypePropertyName(m.getClassMeta()))) {
-                                               BeanPropertyMeta pMeta = 
m.getPropertyMeta(currAttr);
-                                               
session.setCurrentProperty(pMeta);
-                                               if (pMeta == null) {
-                                                       
session.onUnknownProperty(currAttr, m, currAttrLine, currAttrCol);
-                                                       parseAnything(session, 
object(), r.unread(), m.getBean(false), null); // Read content anyway to ignore 
it
-                                               } else {
-                                                       ClassMeta<?> cm = 
pMeta.getClassMeta();
-                                                       Object value = 
parseAnything(session, cm, r.unread(), m.getBean(false), pMeta);
-                                                       setName(cm, value, 
currAttr);
-                                                       pMeta.set(m, currAttr, 
value);
-                                               }
-                                               
session.setCurrentProperty(null);
-                                       }
-                                       state = S5;
-                               }
-                       } else if (state == S5) {
-                               if (c == ',')
-                                       state = S1;
-                               else if (session.isCommentOrWhitespace(c))
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               else if (c == '}') {
-                                       return m;
-                               }
-                       }
-               }
-               if (state == S0)
-                       throw new ParseException(session, "Expected '{' at 
beginning of JSON object.");
-               if (state == S1)
-                       throw new ParseException(session, "Could not find 
attribute name on JSON object.");
-               if (state == S3)
-                       throw new ParseException(session, "Could not find ':' 
following attribute name on JSON object.");
-               if (state == S4)
-                       throw new ParseException(session, "Expected one of the 
following characters: {,[,',\",LITERAL.");
-               if (state == S5)
-                       throw new ParseException(session, "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(JsonParserSession session, ParserReader r) 
throws Exception  {
-               r.mark();
-               int qc = r.read();              // The quote character being 
used (" or ')
-               if (qc != '"' && session.isStrict()) {
-                       String msg = (
-                               qc == '\''
-                               ? "Invalid quote character \"{0}\" being used."
-                               : "Did not find quote character marking 
beginning of string.  Character=\"{0}\""
-                       );
-                       throw new ParseException(session, 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 (session.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(session, "Invalid Unicode escape sequence in string.");
-                                               }
-                                               break;
-                                       }
-                                       default:
-                                               throw new 
ParseException(session, "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 == ']' || 
session.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(session, "Could not find 
expected end character ''{0}''.", (char)qc);
-
-               // Look for concatenated string (i.e. whitespace followed by +).
-               skipCommentsAndSpace(session, r);
-               if (r.peek() == '+') {
-                       if (session.isStrict())
-                               throw new ParseException(session, "String 
concatenation detected.");
-                       r.read();       // Skip past '+'
-                       skipCommentsAndSpace(session, r);
-                       s += parseString(session, r);
-               }
-               return session.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 static void parseKeyword(JsonParserSession session, String 
keyword, ParserReader r) throws Exception {
-               try {
-                       String s = r.read(keyword.length());
-                       if (s.equals(keyword))
-                               return;
-                       throw new ParseException(session, "Unrecognized 
syntax.");
-               } catch (IndexOutOfBoundsException e) {
-                       throw new ParseException(session, "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 static void skipCommentsAndSpace(JsonParserSession session, 
ParserReader r) throws Exception {
-               int c = 0;
-               while ((c = r.read()) != -1) {
-                       if (! session.isWhitespace(c)) {
-                               if (c == '/') {
-                                       if (session.isStrict())
-                                               throw new 
ParseException(session, "Javascript comment detected.");
-                                       skipComments(session, 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(JsonParserSession session, 
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 (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       currAttr = parseFieldName(session, 
r.unread());
-                                       if (! currAttr.equals(wrapperAttr))
-                                               throw new 
ParseException(session,
-                                                       "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 (session.isCommentOrWhitespace(c)) {
-                                       skipCommentsAndSpace(session, 
r.unread());
-                               } else {
-                                       r.unread();
-                                       return;
-                               }
-                       }
-               }
-               if (state == S0)
-                       throw new ParseException(session, "Expected '{' at 
beginning of JSON object.");
-               if (state == S1)
-                       throw new ParseException(session, "Could not find 
attribute name on JSON object.");
-               if (state == S3)
-                       throw new ParseException(session, "Could not find ':' 
following attribute name on JSON object.");
-               if (state == S4)
-                       throw new ParseException(session, "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 static void skipWrapperAttrEnd(JsonParserSession session, 
ParserReader r) throws ParseException, IOException {
-               int c = 0;
-               while ((c = r.read()) != -1) {
-                       if (! session.isWhitespace(c)) {
-                               if (c == '/') {
-                                       if (session.isStrict())
-                                               throw new 
ParseException(session, "Javascript comment detected.");
-                                       skipComments(session, r);
-                               } else if (c == '}') {
-                                       return;
-                               } else {
-                                       throw new ParseException(session, 
"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 static void skipComments(JsonParserSession session, 
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(session, "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 static void validateEnd(JsonParserSession session, ParserReader 
r) throws Exception {
-               skipCommentsAndSpace(session, r);
-               int c = r.read();
-               if (c != -1 && c != ';')  // var x = {...}; expressions can end 
with a semicolon.
-                       throw new ParseException(session, "Remainder after 
parse: ''{0}''.", (char)c);
-       }
-
-
-       
//--------------------------------------------------------------------------------
-       // Entry point methods
-       
//--------------------------------------------------------------------------------
-
-       @Override /* Parser */
-       public JsonParserSession createSession(Object input, ObjectMap op, 
Method javaMethod, Object outer, Locale locale,
-                       TimeZone timeZone, MediaType mediaType) {
-               return new JsonParserSession(ctx, op, input, javaMethod, outer, 
locale, timeZone, mediaType);
-       }
-
        @Override /* Parser */
-       protected <T> T doParse(ParserSession session, ClassMeta<T> type) 
throws Exception {
-               JsonParserSession s = (JsonParserSession)session;
-               ParserReader r = s.getReader();
-               if (r == null)
-                       return null;
-               T o = parseAnything(s, type, r, s.getOuter(), null);
-               validateEnd(s, r);
-               return o;
-       }
-
-       @Override /* ReaderParser */
-       protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> 
m, Type keyType, Type valueType) throws Exception {
-               JsonParserSession s = (JsonParserSession)session;
-               ParserReader r = s.getReader();
-               m = parseIntoMap2(s, r, m, 
(ClassMeta<K>)s.getClassMeta(keyType), (ClassMeta<V>)s.getClassMeta(valueType), 
null);
-               validateEnd(s, r);
-               return m;
-       }
-
-       @Override /* ReaderParser */
-       protected <E> Collection<E> doParseIntoCollection(ParserSession 
session, Collection<E> c, Type elementType) throws Exception {
-               JsonParserSession s = (JsonParserSession)session;
-               ParserReader r = s.getReader();
-               c = parseIntoCollection2(s, r, c, s.getClassMeta(elementType), 
null);
-               validateEnd(s, r);
-               return c;
+       public ReaderParserSession createSession(ParserSessionArgs args) {
+               return new JsonParserSession(ctx, args);
        }
 }

Reply via email to