Repository: incubator-juneau
Updated Branches:
  refs/heads/master 8879750c6 -> 2a37f3103


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index f711dc1..1603f0d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -14,7 +14,10 @@ package org.apache.juneau.xml;
 
 import static org.apache.juneau.msgpack.MsgPackSerializerContext.*;
 import static org.apache.juneau.xml.NamespaceFactory.*;
+import static org.apache.juneau.xml.XmlSerializerSession.ContentResult.*;
+import static org.apache.juneau.xml.XmlSerializerSession.JsonType.*;
 import static org.apache.juneau.xml.XmlSerializerContext.*;
+import static org.apache.juneau.xml.annotation.XmlFormat.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.internal.ArrayUtils.*;
 
@@ -22,30 +25,32 @@ import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
+import org.apache.juneau.xml.annotation.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link 
XmlSerializer}.
  *
  * <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.
  */
-@SuppressWarnings("hiding")
-public class XmlSerializerSession extends SerializerSession {
+@SuppressWarnings({"hiding","unchecked","rawtypes"})
+public class XmlSerializerSession extends WriterSerializerSession {
 
-       private final boolean
+       final boolean
                autoDetectNamespaces,
                enableNamespaces,
                addNamespaceUrlsToRoot,
                addBeanTypeProperties;
 
-       private Namespace
+       Namespace
                defaultNamespace;
-       private final Namespace
+       final Namespace
                xsNamespace;
 
-       private Namespace[] namespaces = new Namespace[0];
+       Namespace[] namespaces = new Namespace[0];
 
        /**
         * Create a new session using properties specified in the context.
@@ -53,25 +58,17 @@ public class XmlSerializerSession extends SerializerSession 
{
         * @param ctx
         *      The context creating this session object.
         *      The context contains all the configuration settings for this 
object.
-        * @param op
-        *      The override properties.
-        *      These override any context properties defined in the context.
-        * @param javaMethod The java method that called this serializer, 
usually the method in a REST servlet.
-        * @param locale
-        *      The session locale.
-        *      If <jk>null</jk>, then the locale defined on the context is 
used.
-        * @param timeZone
-        *      The session timezone.
-        *      If <jk>null</jk>, then the timezone defined on the context is 
used.
-        * @param mediaType The session media type (e.g. 
<js>"application/json"</js>).
-        * @param uriContext
-        *      The URI context.
-        *      Identifies the current request URI used for resolution of URIs 
to absolute or root-relative form.
+        * @param args
+        *      Runtime arguments.
+        *      These specify session-level information such as locale and URI 
context.
+        *      It also include session-level properties that override the 
properties defined on the bean and
+        *      serializer contexts.
+        *      <br>If <jk>null</jk>, defaults to {@link 
SerializerSessionArgs#DEFAULT}.
         */
-       public XmlSerializerSession(XmlSerializerContext ctx, ObjectMap op, 
Method javaMethod, Locale locale,
-                       TimeZone timeZone, MediaType mediaType, UriContext 
uriContext) {
-               super(ctx, op, javaMethod, locale, timeZone, mediaType, 
uriContext);
-               if (op == null || op.isEmpty()) {
+       protected XmlSerializerSession(XmlSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+               ObjectMap p = getProperties();
+               if (p.isEmpty()) {
                        enableNamespaces = ctx.enableNamespaces;
                        autoDetectNamespaces = ctx.autoDetectNamespaces;
                        addNamespaceUrlsToRoot = ctx.addNamespaceUrlsToRoot;
@@ -80,13 +77,13 @@ public class XmlSerializerSession extends SerializerSession 
{
                        xsNamespace = ctx.xsNamespace;
                        addBeanTypeProperties = ctx.addBeanTypeProperties;
                } else {
-                       enableNamespaces = op.getBoolean(XML_enableNamespaces, 
ctx.enableNamespaces);
-                       autoDetectNamespaces = 
op.getBoolean(XML_autoDetectNamespaces, ctx.autoDetectNamespaces);
-                       addNamespaceUrlsToRoot = 
op.getBoolean(XML_addNamespaceUrisToRoot, ctx.addNamespaceUrlsToRoot);
-                       namespaces = (op.containsKey(XML_namespaces) ? 
parseNamespaces(op.get(XML_namespaces)) : ctx.namespaces);
-                       defaultNamespace = 
findDefaultNamespace(op.containsKey(XML_defaultNamespace) ? 
op.getString(XML_defaultNamespace) : ctx.defaultNamespace);
-                       xsNamespace = (op.containsKey(XML_xsNamespace) ? 
parseNamespace(op.get(XML_xsNamespace)) : ctx.xsNamespace);
-                       addBeanTypeProperties = 
op.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
+                       enableNamespaces = p.getBoolean(XML_enableNamespaces, 
ctx.enableNamespaces);
+                       autoDetectNamespaces = 
p.getBoolean(XML_autoDetectNamespaces, ctx.autoDetectNamespaces);
+                       addNamespaceUrlsToRoot = 
p.getBoolean(XML_addNamespaceUrisToRoot, ctx.addNamespaceUrlsToRoot);
+                       namespaces = (p.containsKey(XML_namespaces) ? 
parseNamespaces(p.get(XML_namespaces)) : ctx.namespaces);
+                       defaultNamespace = 
findDefaultNamespace(p.containsKey(XML_defaultNamespace) ? 
p.getString(XML_defaultNamespace) : ctx.defaultNamespace);
+                       xsNamespace = (p.containsKey(XML_xsNamespace) ? 
parseNamespace(p.get(XML_xsNamespace)) : ctx.xsNamespace);
+                       addBeanTypeProperties = 
p.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
                }
        }
 
@@ -105,12 +102,12 @@ public class XmlSerializerSession extends 
SerializerSession {
                        addNamespace(ns);
        }
 
-       /**
+       /*
         * Add a namespace to this session.
         *
         * @param ns The namespace being added.
         */
-       public void addNamespace(Namespace ns) {
+       private void addNamespace(Namespace ns) {
                if (ns == defaultNamespace)
                        return;
 
@@ -125,93 +122,607 @@ public class XmlSerializerSession extends 
SerializerSession {
        }
 
        /**
-        * Returns the list of namespaces being used in the current XML 
serialization.
+        * Returns the {@link XmlSerializerContext#XML_addBeanTypeProperties} 
setting value for this session.
         *
-        * @return The list of namespaces being used in the current XML 
serialization.
+        * @return The {@link XmlSerializerContext#XML_addBeanTypeProperties} 
setting value for this session.
         */
-       public Namespace[] getNamespaces() {
-               return namespaces;
+       @Override /* SerializerSession */
+       protected boolean isAddBeanTypeProperties() {
+               return addBeanTypeProperties;
        }
 
        /**
-        * Returns the {@link XmlSerializerContext#XML_autoDetectNamespaces} 
setting value in this context.
+        * Returns <jk>true</jk> if we're serializing HTML.
+        *
+        * <p>
+        * The difference in behavior is how empty non-void elements are 
handled.
+        * The XML serializer will produce a collapsed tag, whereas the HTML 
serializer will produce a start and end tag.
         *
-        * @return The {@link XmlSerializerContext#XML_autoDetectNamespaces} 
setting value in this context.
+        * @return <jk>true</jk> if we're generating HTML.
         */
-       public final boolean isAutoDetectNamespaces() {
-               return enableNamespaces && autoDetectNamespaces;
+       protected boolean isHtmlMode() {
+               return false;
        }
 
        /**
-        * Returns the {@link XmlSerializerContext#XML_enableNamespaces} 
setting value in this context.
+        * Converts the specified output target object to an {@link XmlWriter}.
         *
-        * @return The {@link XmlSerializerContext#XML_enableNamespaces} 
setting value in this context.
+        * @param out The output target object.
+        * @return The output target object wrapped in an {@link XmlWriter}.
+        * @throws Exception
         */
-       public final boolean isEnableNamespaces() {
-               return enableNamespaces;
+       public final XmlWriter getXmlWriter(SerializerPipe out) throws 
Exception {
+               Object output = out.getRawOutput();
+               if (output instanceof XmlWriter)
+                       return (XmlWriter)output;
+               XmlWriter w = new XmlWriter(out.getWriter(), isUseWhitespace(), 
getMaxIndent(), isTrimStrings(), getQuoteChar(), getUriResolver(), 
enableNamespaces, defaultNamespace);
+               out.setWriter(w);
+               return w;
        }
 
-       /**
-        * Returns the {@link XmlSerializerContext#XML_addNamespaceUrisToRoot} 
setting value in this context.
-        *
-        * @return The {@link XmlSerializerContext#XML_addNamespaceUrisToRoot} 
setting value in this context.
-        */
-       public final boolean isAddNamespaceUrlsToRoot() {
-               return addNamespaceUrlsToRoot;
+       @Override /* Serializer */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               if (enableNamespaces && autoDetectNamespaces)
+                       findNsfMappings(o);
+               serializeAnything(getXmlWriter(out), o, getExpectedRootType(o), 
null, null, enableNamespaces && addNamespaceUrlsToRoot, XmlFormat.DEFAULT, 
false, false, null);
        }
 
        /**
-        * Returns the {@link XmlSerializerContext#XML_addBeanTypeProperties} 
setting value for this session.
+        * Recursively searches for the XML namespaces on the specified POJO 
and adds them to the serializer context object.
         *
-        * @return The {@link XmlSerializerContext#XML_addBeanTypeProperties} 
setting value for this session.
+        * @param o The POJO to check.
+        * @throws SerializeException
         */
-       @Override /* SerializerSession */
-       public boolean isAddBeanTypeProperties() {
-               return addBeanTypeProperties;
+       protected final void findNsfMappings(Object o) throws 
SerializeException {
+               ClassMeta<?> aType = null;                                      
        // The actual type
+               aType = push(null, o, null);
+
+               if (aType != null) {
+                       Namespace ns = 
aType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+                       if (ns != null) {
+                               if (ns.uri != null)
+                                       addNamespace(ns);
+                               else
+                                       ns = null;
+                       }
+               }
+
+               // Handle recursion
+               if (aType != null && ! aType.isPrimitive()) {
+
+                       BeanMap<?> bm = null;
+                       if (aType.isBeanMap()) {
+                               bm = (BeanMap<?>)o;
+                       } else if (aType.isBean()) {
+                               bm = toBeanMap(o);
+                       } else if (aType.isDelegate()) {
+                               ClassMeta<?> innerType = 
((Delegate<?>)o).getClassMeta();
+                               Namespace ns = 
innerType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+                               if (ns != null) {
+                                       if (ns.uri != null)
+                                               addNamespace(ns);
+                                       else
+                                               ns = null;
+                               }
+
+                               if (innerType.isBean()) {
+                                       for (BeanPropertyMeta bpm : 
innerType.getBeanMeta().getPropertyMetas()) {
+                                               ns = 
bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+                                               if (ns != null && ns.uri != 
null)
+                                                       addNamespace(ns);
+                                       }
+
+                               } else if (innerType.isMap()) {
+                                       for (Object o2 : ((Map<?,?>)o).values())
+                                               findNsfMappings(o2);
+                               } else if (innerType.isCollection()) {
+                                       for (Object o2 : ((Collection<?>)o))
+                                               findNsfMappings(o2);
+                               }
+
+                       } else if (aType.isMap()) {
+                               for (Object o2 : ((Map<?,?>)o).values())
+                                       findNsfMappings(o2);
+                       } else if (aType.isCollection()) {
+                               for (Object o2 : ((Collection<?>)o))
+                                       findNsfMappings(o2);
+                       } else if (aType.isArray() && ! 
aType.getElementType().isPrimitive()) {
+                               for (Object o2 : ((Object[])o))
+                                       findNsfMappings(o2);
+                       }
+                       if (bm != null) {
+                               for (BeanPropertyValue p : 
bm.getValues(isTrimNulls())) {
+
+                                       Namespace ns = 
p.getMeta().getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+                                       if (ns != null && ns.uri != null)
+                                               addNamespace(ns);
+
+                                       try {
+                                               findNsfMappings(p.getValue());
+                                       } catch (Throwable x) {
+                                               // Ignore
+                                       }
+                               }
+                       }
+               }
+
+               pop();
        }
 
        /**
-        * Returns the {@link XmlSerializerContext#XML_defaultNamespace} 
setting value in this context.
+        * Workhorse method.
         *
-        * @return The {@link XmlSerializerContext#XML_defaultNamespace} 
setting value in this context.
+        * @param out The writer to send the output to.
+        * @param o The object to serialize.
+        * @param eType The expected type if this is a bean property value 
being serialized.
+        * @param elementName The root element name.
+        * @param elementNamespace The namespace of the element.
+        * @param addNamespaceUris Flag indicating that namespace URIs need to 
be added.
+        * @param format The format to serialize the output to.
+        * @param isMixed We're serializing mixed content, so don't use 
whitespace.
+        * @param preserveWhitespace
+        *      <jk>true</jk> if we're serializing {@link XmlFormat#MIXED_PWS} 
or {@link XmlFormat#TEXT_PWS}.
+        * @param pMeta The bean property metadata if this is a bean property 
being serialized.
+        * @return The same writer passed in so that calls to the writer can be 
chained.
+        * @throws Exception If a problem occurred trying to convert the output.
         */
-       public final Namespace getDefaultNamespace() {
-               return defaultNamespace;
+       protected XmlWriter serializeAnything(
+                       XmlWriter out,
+                       Object o,
+                       ClassMeta<?> eType,
+                       String elementName,
+                       Namespace elementNamespace,
+                       boolean addNamespaceUris,
+                       XmlFormat format,
+                       boolean isMixed,
+                       boolean preserveWhitespace,
+                       BeanPropertyMeta pMeta) throws Exception {
+
+               JsonType type = null;              // The type string (e.g. 
<type> or <x x='type'>
+               int i = isMixed ? 0 : indent;       // Current indentation
+               ClassMeta<?> aType = null;     // The actual type
+               ClassMeta<?> wType = null;     // The wrapped type (delegate)
+               ClassMeta<?> sType = object(); // The serialized type
+
+               aType = push(elementName, o, eType);
+
+               if (eType == null)
+                       eType = object();
+
+               // Handle recursion
+               if (aType == null) {
+                       o = null;
+                       aType = object();
+               }
+
+               if (o != null) {
+
+                       if (aType.isDelegate()) {
+                               wType = aType;
+                               eType = aType = ((Delegate<?>)o).getClassMeta();
+                       }
+
+                       sType = aType.getSerializedClassMeta();
+
+                       // 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);
+                       }
+               } else {
+                       sType = eType.getSerializedClassMeta();
+               }
+
+               // Does the actual type match the expected type?
+               boolean isExpectedType = true;
+               if (o == null || ! eType.same(aType)) {
+                       if (eType.isNumber())
+                               isExpectedType = aType.isNumber();
+                       else if (eType.isMap())
+                               isExpectedType = aType.isMap();
+                       else if (eType.isCollectionOrArray())
+                               isExpectedType = aType.isCollectionOrArray();
+                       else
+                               isExpectedType = false;
+               }
+
+               String resolvedDictionaryName = isExpectedType ? null : 
aType.getDictionaryName();
+
+               // Note that the dictionary name may be specified on the actual 
type or the serialized type.
+               // HTML templates will have them defined on the serialized type.
+               String dictionaryName = aType.getDictionaryName();
+               if (dictionaryName == null)
+                       dictionaryName = sType.getDictionaryName();
+
+               // char '\0' is interpreted as null.
+               if (o != null && sType.isChar() && ((Character)o).charValue() 
== 0)
+                       o = null;
+
+               boolean isCollapsed = false;            // If 'true', this is a 
collection and we're not rendering the outer element.
+
+               // Get the JSON type string.
+               if (o == null) {
+                       type = NULL;
+               } else if (sType.isCharSequence() || sType.isChar()) {
+                       type = STRING;
+               } else if (sType.isNumber()) {
+                       type = NUMBER;
+               } else if (sType.isBoolean()) {
+                       type = BOOLEAN;
+               } else if (sType.isMapOrBean()) {
+                       isCollapsed = 
sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED;
+                       type = OBJECT;
+               } else if (sType.isCollectionOrArray()) {
+                       isCollapsed = (format == COLLAPSED && ! 
addNamespaceUris);
+                       type = ARRAY;
+               } else {
+                       type = STRING;
+               }
+
+               if (format.isOneOf(MIXED,MIXED_PWS,TEXT,TEXT_PWS,XMLTEXT) && 
type.isOneOf(NULL,STRING,NUMBER,BOOLEAN))
+                       isCollapsed = true;
+
+               // Is there a name associated with this bean?
+               if (elementName == null && dictionaryName != null) {
+                       elementName = dictionaryName;
+                       isExpectedType = true;
+               }
+
+               if (enableNamespaces) {
+                       if (elementNamespace == null)
+                               elementNamespace = 
sType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+                       if (elementNamespace == null)
+                               elementNamespace = 
aType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+                       if (elementNamespace != null && elementNamespace.uri == 
null)
+                               elementNamespace = null;
+                       if (elementNamespace == null)
+                               elementNamespace = defaultNamespace;
+               } else {
+                       elementNamespace = null;
+               }
+
+               // Do we need a carriage return after the start tag?
+               boolean cr = o != null && (sType.isMapOrBean() || 
sType.isCollectionOrArray()) && ! isMixed;
+
+               String en = elementName;
+               if (en == null) {
+                       en = type.toString();
+                       type = null;
+               }
+               boolean encodeEn = elementName != null;
+               String ns = (elementNamespace == null ? null : 
elementNamespace.name);
+               String dns = null, elementNs = null;
+               if (enableNamespaces) {
+                       dns = elementName == null && defaultNamespace != null ? 
defaultNamespace.name : null;
+                       elementNs = elementName == null ? dns : ns;
+                       if (elementName == null)
+                               elementNamespace = null;
+               }
+
+               // Render the start tag.
+               if (! isCollapsed) {
+                       out.oTag(i, elementNs, en, encodeEn);
+                       if (addNamespaceUris) {
+                               out.attr((String)null, "xmlns", 
defaultNamespace.getUri());
+
+                               for (Namespace n : namespaces)
+                                       out.attr("xmlns", n.getName(), 
n.getUri());
+                       }
+                       if (! isExpectedType) {
+                               if (resolvedDictionaryName != null)
+                                       out.attr(dns, 
getBeanTypePropertyName(eType), resolvedDictionaryName);
+                               else if (type != null && type != STRING)
+                                       out.attr(dns, 
getBeanTypePropertyName(eType), type);
+                       }
+                       if (o == null) {
+                               if ((sType.isBoolean() || sType.isNumber()) && 
! sType.isNullable())
+                                       o = sType.getPrimitiveDefault();
+                       }
+
+                       if (o != null && ! (sType.isMapOrBean()))
+                               out.append('>');
+
+                       if (cr && ! (sType.isMapOrBean()))
+                               out.nl(i+1);
+               }
+
+               ContentResult rc = CR_ELEMENTS;
+
+               // Render the tag contents.
+               if (o != null) {
+                       if (sType.isUri() || (pMeta != null && pMeta.isUri())) {
+                               out.textUri(o);
+                       } else if (sType.isCharSequence() || sType.isChar()) {
+                               if (format == XMLTEXT)
+                                       out.append(o);
+                               else
+                                       out.text(o, preserveWhitespace);
+                       } else if (sType.isNumber() || sType.isBoolean()) {
+                               out.append(o);
+                       } else if (sType.isMap() || (wType != null && 
wType.isMap())) {
+                               if (o instanceof BeanMap)
+                                       rc = serializeBeanMap(out, (BeanMap)o, 
elementNamespace, isCollapsed, isMixed);
+                               else
+                                       rc = serializeMap(out, (Map)o, sType, 
eType.getKeyType(), eType.getValueType(), isMixed);
+                       } else if (sType.isBean()) {
+                               rc = serializeBeanMap(out, toBeanMap(o), 
elementNamespace, isCollapsed, isMixed);
+                       } else if (sType.isCollection() || (wType != null && 
wType.isCollection())) {
+                               if (isCollapsed)
+                                       this.indent--;
+                               serializeCollection(out, o, sType, eType, 
pMeta, isMixed);
+                               if (isCollapsed)
+                                       this.indent++;
+                       } else if (sType.isArray()) {
+                               if (isCollapsed)
+                                       this.indent--;
+                               serializeCollection(out, o, sType, eType, 
pMeta, isMixed);
+                               if (isCollapsed)
+                                       this.indent++;
+                       } else {
+                               if (format == XMLTEXT)
+                                       out.append(toString(o));
+                               else
+                                       out.text(toString(o));
+                       }
+               }
+
+               pop();
+
+               // Render the end tag.
+               if (! isCollapsed) {
+                       if (rc == CR_EMPTY) {
+                               if (isHtmlMode())
+                                       out.append('>').eTag(elementNs, en, 
encodeEn);
+                               else
+                                       out.append('/').append('>');
+                       } else if (rc == CR_VOID || o == null) {
+                               out.append('/').append('>');
+                       }
+                       else
+                               out.ie(cr && rc != CR_MIXED ? i : 
0).eTag(elementNs, en, encodeEn);
+                       if (! isMixed)
+                               out.nl(i);
+               }
+
+               return out;
        }
 
-       /**
-        * Returns the {@link XmlSerializerContext#XML_xsNamespace} setting 
value in this context.
-        *
-        * @return The {@link XmlSerializerContext#XML_xsNamespace} setting 
value in this context.
-        */
-       public final Namespace getXsNamespace() {
-               return xsNamespace;
+       private ContentResult serializeMap(XmlWriter out, Map m, ClassMeta<?> 
sType,
+                       ClassMeta<?> eKeyType, ClassMeta<?> eValueType, boolean 
isMixed) throws Exception {
+
+               m = sort(m);
+
+               ClassMeta<?> keyType = eKeyType == null ? sType.getKeyType() : 
eKeyType;
+               ClassMeta<?> valueType = eValueType == null ? 
sType.getValueType() : eValueType;
+
+               boolean hasChildren = false;
+               for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
+                       Map.Entry e = (Map.Entry)i.next();
+
+                       Object k = e.getKey();
+                       if (k == null) {
+                               k = "\u0000";
+                       } else {
+                               k = generalize(k, keyType);
+                               if (isTrimStrings() && k instanceof String)
+                                       k = k.toString().trim();
+                       }
+
+                       Object value = e.getValue();
+
+                       if (! hasChildren) {
+                               hasChildren = true;
+                               out.append('>').nlIf(! isMixed, indent);
+                       }
+                       serializeAnything(out, value, valueType, toString(k), 
null, false, XmlFormat.DEFAULT, isMixed, false, null);
+               }
+               return hasChildren ? CR_ELEMENTS : CR_EMPTY;
        }
 
-       /**
-        * Returns <jk>true</jk> if we're serializing HTML.
-        *
-        * <p>
-        * The difference in behavior is how empty non-void elements are 
handled.
-        * The XML serializer will produce a collapsed tag, whereas the HTML 
serializer will produce a start and end tag.
-        *
-        * @return <jk>true</jk> if we're generating HTML.
-        */
-       public boolean isHtmlMode() {
-               return false;
+       private ContentResult serializeBeanMap(XmlWriter out, BeanMap<?> m,
+                       Namespace elementNs, boolean isCollapsed, boolean 
isMixed) throws Exception {
+               boolean hasChildren = false;
+               BeanMeta<?> bm = m.getMeta();
+
+               List<BeanPropertyValue> lp = m.getValues(isTrimNulls());
+
+               XmlBeanMeta xbm = bm.getExtendedMeta(XmlBeanMeta.class);
+
+               Set<String>
+                       attrs = xbm.getAttrPropertyNames(),
+                       elements = xbm.getElementPropertyNames(),
+                       collapsedElements = xbm.getCollapsedPropertyNames();
+               String
+                       attrsProperty = xbm.getAttrsPropertyName(),
+                       contentProperty = xbm.getContentPropertyName();
+
+               XmlFormat cf = null;
+
+               Object content = null;
+               ClassMeta<?> contentType = null;
+               for (BeanPropertyValue p : lp) {
+                       String n = p.getName();
+                       if (attrs.contains(n) || attrs.contains("*") || 
n.equals(attrsProperty)) {
+                               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;
+
+                               Namespace ns = (enableNamespaces && 
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() != elementNs ? 
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() : null);
+
+                               if (pMeta.isUri()  ) {
+                                       out.attrUri(ns, key, value);
+                               } else if (n.equals(attrsProperty)) {
+                                       if (value instanceof BeanMap) {
+                                               BeanMap<?> bm2 = (BeanMap)value;
+                                               for (BeanPropertyValue p2 : 
bm2.getValues(true)) {
+                                                       String key2 = 
p2.getName();
+                                                       Object value2 = 
p2.getValue();
+                                                       Throwable t2 = 
p2.getThrown();
+                                                       if (t2 != null)
+                                                               
onBeanGetterException(pMeta, t);
+                                                       out.attr(ns, key2, 
value2);
+                                               }
+                                       } else /* Map */ {
+                                               Map m2 = (Map)value;
+                                               for (Map.Entry e : 
(Set<Map.Entry>)(m2.entrySet())) {
+                                                       out.attr(ns, 
toString(e.getKey()), e.getValue());
+                                               }
+                                       }
+                               } else {
+                                       out.attr(ns, key, value);
+                               }
+                       }
+               }
+
+               boolean
+                       hasContent = false,
+                       preserveWhitespace = false,
+                       isVoidElement = xbm.getContentFormat() == VOID;
+
+               for (BeanPropertyValue p : lp) {
+                       BeanPropertyMeta pMeta = p.getMeta();
+                       ClassMeta<?> cMeta = p.getClassMeta();
+
+                       String n = p.getName();
+                       if (n.equals(contentProperty)) {
+                               content = p.getValue();
+                               contentType = p.getClassMeta();
+                               hasContent = true;
+                               cf = xbm.getContentFormat();
+                               if 
(cf.isOneOf(MIXED,MIXED_PWS,TEXT,TEXT_PWS,XMLTEXT))
+                                       isMixed = true;
+                               if (cf.isOneOf(MIXED_PWS, TEXT_PWS))
+                                       preserveWhitespace = true;
+                               if (contentType.isCollection() && 
((Collection)content).isEmpty())
+                                       hasContent = false;
+                               else if (contentType.isArray() && 
Array.getLength(content) == 0)
+                                       hasContent = false;
+                       } else if (elements.contains(n) || 
collapsedElements.contains(n) || elements.contains("*") || 
collapsedElements.contains("*") ) {
+                               String key = p.getName();
+                               Object value = p.getValue();
+                               Throwable t = p.getThrown();
+                               if (t != null)
+                                       onBeanGetterException(pMeta, t);
+
+                               if (canIgnoreValue(cMeta, key, value))
+                                       continue;
+
+                               if (! hasChildren) {
+                                       hasChildren = true;
+                                       out.appendIf(! isCollapsed, '>').nlIf(! 
isMixed, indent);
+                               }
+
+                               XmlBeanPropertyMeta xbpm = 
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+                               serializeAnything(out, value, cMeta, key, 
xbpm.getNamespace(), false, xbpm.getXmlFormat(), isMixed, false, pMeta);
+                       }
+               }
+               if (! hasContent)
+                       return (hasChildren ? CR_ELEMENTS : isVoidElement ? 
CR_VOID : CR_EMPTY);
+               out.append('>').nlIf(! isMixed, indent);
+
+               // Serialize XML content.
+               if (content != null) {
+                       if (contentType == null) {
+                       } else if (contentType.isCollection()) {
+                               Collection c = (Collection)content;
+                               for (Iterator i = c.iterator(); i.hasNext();) {
+                                       Object value = i.next();
+                                       serializeAnything(out, value, 
contentType.getElementType(), null, null, false, cf, isMixed, 
preserveWhitespace, null);
+                               }
+                       } else if (contentType.isArray()) {
+                               Collection c = toList(Object[].class, content);
+                               for (Iterator i = c.iterator(); i.hasNext();) {
+                                       Object value = i.next();
+                                       serializeAnything(out, value, 
contentType.getElementType(), null, null, false, cf, isMixed, 
preserveWhitespace, null);
+                               }
+                       } else {
+                               serializeAnything(out, content, contentType, 
null, null, false, cf, isMixed, preserveWhitespace, null);
+                       }
+               } else {
+                       if (! isTrimNulls()) {
+                               if (! isMixed)
+                                       out.i(indent);
+                               out.text(content);
+                               if (! isMixed)
+                                       out.nl(indent);
+                       }
+               }
+               return isMixed ? CR_MIXED : CR_ELEMENTS;
+       }
+
+       private XmlWriter serializeCollection(XmlWriter out, Object in, 
ClassMeta<?> sType,
+                       ClassMeta<?> eType, BeanPropertyMeta ppMeta, boolean 
isMixed) throws Exception {
+
+               ClassMeta<?> seType = sType.getElementType();
+               if (seType == null)
+                       seType = object();
+               ClassMeta<?> eeType = eType.getElementType();
+
+               Collection c = (sType.isCollection() ? (Collection)in : 
toList(sType.getInnerClass(), in));
+
+               c = sort(c);
+
+               String type2 = null;
+               if (sType != eType)
+                       type2 = sType.getDictionaryName();
+
+               String eName = type2;
+               Namespace eNs = null;
+
+               if (ppMeta != null) {
+                       XmlBeanPropertyMeta xbpm = 
ppMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+                       eName = xbpm.getChildName();
+                       eNs = xbpm.getNamespace();
+               }
+
+               for (Iterator i = c.iterator(); i.hasNext();) {
+                       Object value = i.next();
+                       serializeAnything(out, value, eeType, eName, eNs, 
false, XmlFormat.DEFAULT, isMixed, false, null);
+               }
+               return out;
+       }
+
+       static enum JsonType {
+               
STRING("string"),BOOLEAN("boolean"),NUMBER("number"),ARRAY("array"),OBJECT("object"),NULL("null");
+
+               private final String value;
+               private JsonType(String value) {
+                       this.value = value;
+               }
+
+               @Override
+               public String toString() {
+                       return value;
+               }
+
+               boolean isOneOf(JsonType...types) {
+                       for (JsonType type : types)
+                               if (type == this)
+                                       return true;
+                       return false;
+               }
        }
 
        /**
-        * Converts the specified output target object to an {@link XmlWriter}.
-        *
-        * @param out The output target object.
-        * @return The output target object wrapped in an {@link XmlWriter}.
-        * @throws Exception
+        * Identifies what the contents were of a serialized bean.
         */
-       public XmlWriter getXmlWriter(SerializerOutput out) throws Exception {
-               Object output = out.getRawOutput();
-               if (output instanceof XmlWriter)
-                       return (XmlWriter)output;
-               return new XmlWriter(out.getWriter(), isUseWhitespace(), 
getMaxIndent(), isTrimStrings(), getQuoteChar(), getUriResolver(), 
isEnableNamespaces(), getDefaultNamespace());
+       static enum ContentResult {
+               CR_VOID,      // No content...append "/>" to the start tag.
+               CR_EMPTY,     // No content...append "/>" to the start tag if 
XML, "/></end>" if HTML.
+               CR_MIXED,     // Mixed content...don't add whitespace.
+               CR_ELEMENTS   // Elements...use normal whitespace rules.
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/overview.html 
b/juneau-core/src/main/javadoc/overview.html
index 855fcec..2f41325 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -6892,14 +6892,32 @@
                <h6 class='topic'>org.apache.juneau</h6>
                <ul class='spaced-list'>
                        <li>
-                               Serializers can now serialize to {@link 
StringBuilder StringBuilders}.
+                               Serializers can now serialize to {@link 
java.util.StringBuilder StringBuilders}.
+                       <li>
+                               {@link 
org.apache.juneau.serializer.SerializerSession} and {@link 
org.apache.juneau.parser.ParserSession}
+                               objects are now reusable if used within the 
same thread.
+                               <p class='bcode'>
+       <jc>// Old way (still works)</jc>
+       JsonSerializer.<jsf>DEFAULT</jsf>.serialize(writer1, pojo1);
+       JsonSerializer.<jsf>DEFAULT</jsf>.serialize(writer2, pojo2);
+       
+       <jc>// Same, but using a session object</jc>
+       SerializerSession session = 
JsonSerializer.<jsf>DEFAULT</jsf>.createSession();
+       <jk>try</jk> {
+         session.serialize(writer1, pojo1);
+         session.serialize(writer2, pojo2);
+       } <jk>finally</jk> {
+         session.close();
+       }                       
+                               </p>
+                               This is mostly an internal change and doesn't 
affect the existing APIs.
                </ul>
                
                <h6 class='topic'>org.apache.juneau.rest</h6>
                <ul class='spaced-list'>
                        <li>
                                Simplified {@link 
org.apache.juneau.rest.widget.MenuItemWidget}.
-                               <br>Exposes an abstract method {@link 
org.apache.juneau.rest.widget.MenuItemWidget#getContent()} that
+                               <br>Exposes an abstract method {@link 
org.apache.juneau.rest.widget.MenuItemWidget#getContent(RestRequest)} that
                                can return raw HTML via readers or 
char-sequences, or any other object (such as HTML5 beans) that will
                                get converted to HTML using {@link 
org.apache.juneau.html.HtmlSerializer#DEFAULT}.
                        <li>
@@ -7265,7 +7283,7 @@
                                        <li>{@link 
org.apache.juneau.rest.client.RestClientBuilder#listeners(Class,Class)}
                                </ul>
                        <li>The {@link 
org.apache.juneau.BeanContext#BEAN_debug} flag will now capture parser input 
and make it
-                               available through the {@link 
org.apache.juneau.parser.ParserSession#getInputAsString()} method so that it 
can be used
+                               available through the 
<code><del>ParserSession.getInputAsString()</del></code> method so that it can 
be used
                                in the listeners.
                        <li>Significant new functionality introduced to the 
HTML serializer.  
                                <br>Lots of new options for customizing the 
HTML output.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
 
b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
index 94cefcc..79e094a 100644
--- 
a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
+++ 
b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
@@ -142,11 +142,17 @@ public class PhotosResource extends Resource {
                        super(propertyStore);
                }
 
-               @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       RenderedImage image = (RenderedImage)o;
-                       String mediaType = session.getProperty("mediaType");
-                       ImageIO.write(image, 
mediaType.substring(mediaType.indexOf('/')+1), out.getOutputStream());
+               @Override /* Serializer */ 
+               public OutputStreamSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new OutputStreamSerializerSession(args) {
+                               
+                               @Override /* SerializerSession */ 
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       RenderedImage image = (RenderedImage)o;
+                                       String mediaType = 
getProperty("mediaType");
+                                       ImageIO.write(image, 
mediaType.substring(mediaType.indexOf('/')+1), out.getOutputStream());
+                               }
+                       };
                }
        }
 
@@ -163,9 +169,15 @@ public class PhotosResource extends Resource {
                }
 
                @Override /* Parser */
-               @SuppressWarnings("unchecked")
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)ImageIO.read(session.getInputStream());
+               public InputStreamParserSession createSession(final 
ParserSessionArgs args) {
+                       return new InputStreamParserSession(args) {
+                               
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return 
(T)ImageIO.read(pipe.getInputStream());
+                               }
+                       };
                }
        }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java
 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java
index 4e2adb8..9b8f45b 100644
--- 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java
+++ 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java
@@ -70,7 +70,7 @@ public class RestCallLogger extends RestCallInterceptor {
        public void onRetry(RestCall restCall, int statusCode, HttpRequest req, 
HttpResponse res, Exception ex) {
                if (log.isLoggable(level)) {
                        if (ex == null)
-                       log.log(level, format("Call to {0} returned {1}.  Will 
retry.", req.getRequestLine().getUri(), statusCode));
+                               log.log(level, format("Call to {0} returned 
{1}.  Will retry.", req.getRequestLine().getUri(), statusCode));
                        else
                                log.log(level, format("Call to {0} caused 
exception {1}.  Will retry.", req.getRequestLine().getUri(), 
ex.getLocalizedMessage()), ex);
                }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java
 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java
index 8767730..c37bb84 100644
--- 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java
+++ 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java
@@ -53,17 +53,18 @@ public final class RestRequestEntity extends 
BasicHttpEntity {
                                if (serializer == null) {
                                        // If no serializer specified, just 
close the stream.
                                        os.close();
-                               } else if (! serializer.isWriterSerializer()) {
-                                       OutputStreamSerializer s2 = 
(OutputStreamSerializer)serializer;
-                                       s2.serialize(output, os);
-                                       os.flush();
-                                       os.close();
                                } else {
-                                       Writer w = new OutputStreamWriter(os, 
UTF8);
-                                       WriterSerializer s2 = 
(WriterSerializer)serializer;
-                                       s2.serialize(output, w);
-                                       w.flush();
-                                       w.close();
+                                       SerializerSession session = 
serializer.createSession();
+                                       if (session.isWriterSerializer()) {
+                                               Writer w = new 
OutputStreamWriter(os, UTF8);
+                                               session.serialize(w, output);
+                                               w.flush();
+                                               w.close();
+                                       } else {
+                                               session.serialize(os, output);
+                                               os.flush();
+                                               os.close();
+                                       }
                                }
                        } catch (SerializeException e) {
                                throw new 
org.apache.juneau.rest.client.RestCallException(e);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
 
b/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
index a2137a1..ecdee93 100644
--- 
a/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
+++ 
b/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
@@ -105,7 +105,7 @@ public class BaseProvider implements 
MessageBodyReader<Object>, MessageBodyWrite
 
        @Override /* MessageBodyWriter */
        public void writeTo(Object o, Class<?> type, Type gType, Annotation[] 
a, MediaType mediaType,
-                       MultivaluedMap<String,Object> headers, OutputStream 
out) throws IOException, WebApplicationException {
+                       MultivaluedMap<String,Object> headers, OutputStream os) 
throws IOException, WebApplicationException {
                try {
                        SerializerMatch sm = 
serializers.getSerializerMatch(mediaType.toString());
                        if (sm == null)
@@ -115,21 +115,16 @@ public class BaseProvider implements 
MessageBodyReader<Object>, MessageBodyWrite
                        mp.append("mediaType", mediaType.toString());
                        Locale locale = getLocale(headers);
                        TimeZone timeZone = getTimeZone(headers);
+                       
+                       SerializerSession session = s.createSession(new 
SerializerSessionArgs(mp, null, locale, timeZone, sm.getMediaType(), null));
+
                        if (s.isWriterSerializer()) {
-                               WriterSerializer s2 = (WriterSerializer)s;
-                               OutputStreamWriter w = new 
OutputStreamWriter(out, UTF8);
-                               SerializerOutput sout = new SerializerOutput(w);
-                               SerializerSession session = s.createSession(mp, 
null, locale, timeZone, sm.getMediaType(), null);
-                               s2.serialize(session, sout, o);
-                               w.flush();
-                               w.close();
+                               OutputStreamWriter w = new 
OutputStreamWriter(os, UTF8);
+                               session.serialize(w, o);
+                               w.close();  // Leave open if exception occurs.
                        } else {
-                               OutputStreamSerializer s2 = 
(OutputStreamSerializer)s;
-                               SerializerOutput sout = new 
SerializerOutput(s2);
-                               SerializerSession session = s.createSession(mp, 
null, locale, timeZone, sm.getMediaType(), null);
-                               s2.serialize(session, sout, o);
-                               out.flush();
-                               out.close();
+                               session.serialize(os, o);
+                               os.close();  // Leave open if exception occurs.
                        }
                } catch (SerializeException e) {
                        throw new IOException(e);
@@ -153,15 +148,13 @@ public class BaseProvider implements 
MessageBodyReader<Object>, MessageBodyWrite
                        mp.put("mediaType", mediaType.toString());
                        Locale locale = getLocale(headers);
                        TimeZone timeZone = getTimeZone(headers);
-                       if (p.isReaderParser()) {
-                               ReaderParser p2 = (ReaderParser)p;
-                               InputStreamReader r = new InputStreamReader(in, 
UTF8);
-                               ParserSession session = p2.createSession(r, mp, 
null, null, locale, timeZone, pm.getMediaType());
-                               return p2.parseSession(session, 
p.getBeanContext().getClassMeta(gType));
+                       ParserSession session = p.createSession(new 
ParserSessionArgs(mp, null, locale, timeZone, pm.getMediaType(), null));
+                       try {
+                               Object in2 = session.isReaderParser() ? new 
InputStreamReader(in, UTF8) : in;
+                               return session.parse(in2, 
p.getBeanContext().getClassMeta(gType));
+                       } finally {
+                               session.close();
                        }
-                       InputStreamParser p2 = (InputStreamParser)p;
-                       ParserSession session = p2.createSession(in, mp, null, 
null, locale, timeZone, pm.getMediaType());
-                       return p2.parseSession(session, 
p.getBeanContext().getClassMeta(gType));
                } catch (ParseException e) {
                        throw new IOException(e);
                }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
index 94051a7..4919b75 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
@@ -61,10 +61,16 @@ public class AcceptCharsetResource extends RestServlet {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)session.getProperty("characterEncoding");
+               public InputStreamParserSession createSession(ParserSessionArgs 
args) {
+                       return new InputStreamParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return 
(T)getProperty("characterEncoding");
+                               }
+                       };
                }
        }
 
@@ -76,11 +82,16 @@ public class AcceptCharsetResource extends RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       Writer w = new 
OutputStreamWriter(out.getOutputStream());
-                       
w.append(o.toString()).append('/').append(session.getProperty("characterEncoding"));
-                       w.flush();
-                       w.close();
+               public OutputStreamSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new OutputStreamSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       Writer w = new 
OutputStreamWriter(out.getOutputStream());
+                                       
w.append(o.toString()).append('/').append(getProperty("characterEncoding"));
+                                       w.flush();
+                               }
+                       };
                }
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
index e9cf51e..e9ed395 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
@@ -39,10 +39,16 @@ public class CharsetEncodingsResource extends RestServlet {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)read(session.getReader());
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)read(pipe.getReader());
+                               }
+                       };
                }
        }
 
@@ -54,8 +60,14 @@ public class CharsetEncodingsResource extends RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       out.getWriter().write(o.toString());
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write(o.toString());
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
index 2634056..22fd963 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
@@ -112,10 +112,16 @@ public class DefaultContentTypesResource extends 
RestServlet {
                        this.name = name;
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)name;
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)name;
+                               }
+                       };
                }
        }
 
@@ -129,8 +135,14 @@ public class DefaultContentTypesResource extends 
RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object output) throws Exception {
-                       out.getWriter().write(name + "/" + output);
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write(name + "/" + o);
+                               }
+                       };
                }
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
index 493136d..233e9ef 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
@@ -44,8 +44,14 @@ public class GroupsResource extends RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object output) throws Exception {
-                       out.getWriter().write("text/s," + output);
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write("text/s," + o);
+                               }
+                       };
                }
        }
 
@@ -56,10 +62,16 @@ public class GroupsResource extends RestServlet {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)read(session.getReader());
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)read(pipe.getReader());
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
index 7d5af0d..5b25414 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
@@ -229,8 +229,14 @@ public class InheritanceResource extends RestServlet {
                }
 
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return null;
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return null;
+                               }
+                       };
                }
        }
 
@@ -241,8 +247,14 @@ public class InheritanceResource extends RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       out.getWriter().write(o.toString());
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write(o.toString());
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
index 62de96b..183889d 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
@@ -60,8 +60,14 @@ public class NlsPropertyResource extends RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       
out.getWriter().write(session.getProperty("TestProperty"));
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       
out.getWriter().write(getProperty("TestProperty"));
+                               }
+                       };
                }
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
index c509fc5..04e1218 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
@@ -12,11 +12,15 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.test;
 
+import java.util.*;
+
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.annotation.Properties;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
 
 /**
  * JUnit automated testcase resource.
@@ -43,14 +47,22 @@ public class OnPostCallResource extends RestServlet {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       
out.getWriter().write("p1="+session.getProperty("p1")+",p2="+session.getProperty("p2")+",p3="+session.getProperty("p3")+",p4="+session.getProperty("p4")+",p5="+session.getProperty("p5")+",contentType="+session.getProperty("mediaType"));
-               }
-               @Override /* Serializer */
-               public ObjectMap getResponseHeaders(ObjectMap properties) {
-                       if (properties.containsKey("Override-Content-Type"))
-                               return new ObjectMap().append("Content-Type", 
properties.get("Override-Content-Type"));
-                       return null;
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       
out.getWriter().write("p1="+getProperty("p1")+",p2="+getProperty("p2")+",p3="+getProperty("p3")+",p4="+getProperty("p4")+",p5="+getProperty("p5")+",contentType="+getProperty("mediaType"));
+                               }
+                               
+                               @Override /* SerializerSession */
+                               public Map<String,String> getResponseHeaders() {
+                                       ObjectMap p = getProperties();
+                                       if 
(p.containsKey("Override-Content-Type"))
+                                               return new 
AMap<String,String>().append("Content-Type", 
p.getString("Override-Content-Type"));
+                                       return Collections.emptyMap();
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java
index d4f6e20..81e24e3 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java
@@ -44,11 +44,17 @@ public class OnPreCallResource extends RestServlet {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       String matchingContentType = 
session.getProperty("mediaType");
-                       return 
(T)("p1="+session.getProperty("p1")+",p2="+session.getProperty("p2")+",p3="+session.getProperty("p3")+",p4="+session.getProperty("p4")+",p5="+session.getProperty("p5")+",contentType="+matchingContentType);
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       String matchingContentType = 
getProperty("mediaType");
+                                       return 
(T)("p1="+getProperty("p1")+",p2="+getProperty("p2")+",p3="+getProperty("p3")+",p4="+getProperty("p4")+",p5="+getProperty("p5")+",contentType="+matchingContentType);
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java
index 24823a2..1142263 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java
@@ -41,10 +41,16 @@ public class ParsersResource extends RestServletDefault {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)("text/a - " + 
read(session.getReader()).trim());
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)("text/a - " + 
read(pipe.getReader()).trim());
+                               }
+                       };
                }
        }
 
@@ -71,10 +77,16 @@ public class ParsersResource extends RestServletDefault {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)("text/b - " + 
read(session.getReader()).trim());
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)("text/b - " + 
read(pipe.getReader()).trim());
+                               }
+                       };
                }
        }
 
@@ -93,10 +105,16 @@ public class ParsersResource extends RestServletDefault {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)("text/c - " + 
read(session.getReader()).trim());
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)("text/c - " + 
read(pipe.getReader()).trim());
+                               }
+                       };
                }
        }
 
@@ -115,10 +133,16 @@ public class ParsersResource extends RestServletDefault {
                        super(propertyStore);
                }
 
-               @SuppressWarnings("unchecked")
                @Override /* Parser */
-               protected <T> T doParse(ParserSession session, ClassMeta<T> 
type) throws Exception {
-                       return (T)("text/d - " + 
read(session.getReader()).trim());
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)("text/d - " + 
read(pipe.getReader()).trim());
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
index dcb0873..604d485 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
@@ -67,10 +67,16 @@ public class PropertiesResource extends RestServletDefault {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object output) throws Exception {
-                       
out.getWriter().write(format("A1=%s,A2=%s,B1=%s,B2=%s,C=%s,R1a=%s,R1b=%s,R2=%s,R3=%s,R4=%s,R5=%s,R6=%s",
-                               session.getProperty("A1"), 
session.getProperty("A2"), session.getProperty("B1"), 
session.getProperty("B2"), session.getProperty("C"),
-                               session.getProperty("R1a"), 
session.getProperty("R1b"), session.getProperty("R2"), 
session.getProperty("R3"), session.getProperty("R4"), 
session.getProperty("R5"), session.getProperty("R6")));
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       
out.getWriter().write(format("A1=%s,A2=%s,B1=%s,B2=%s,C=%s,R1a=%s,R1b=%s,R2=%s,R3=%s,R4=%s,R5=%s,R6=%s",
+                                               getProperty("A1"), 
getProperty("A2"), getProperty("B1"), getProperty("B2"), getProperty("C"),
+                                               getProperty("R1a"), 
getProperty("R1b"), getProperty("R2"), getProperty("R3"), getProperty("R4"), 
getProperty("R5"), getProperty("R6")));
+                               }
+                       };
                }
        }
 
@@ -90,8 +96,14 @@ public class PropertiesResource extends RestServletDefault {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object output) throws Exception {
-                       out.getWriter().write(format("A=%s,P=%s,H=%s", 
session.getProperty("A"), session.getProperty("P"), session.getProperty("h")));
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       
out.getWriter().write(format("A=%s,P=%s,H=%s", getProperty("A"), 
getProperty("P"), getProperty("h")));
+                               }
+                       };
                }
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
index 092c9af..c4578c2 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
@@ -38,8 +38,14 @@ public class SerializersResource extends RestServletDefault {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       out.getWriter().write("text/a - " + o);
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write("text/a - " + o);
+                               }
+                       };
                }
        }
 
@@ -51,8 +57,14 @@ public class SerializersResource extends RestServletDefault {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       out.getWriter().write("text/b - " + o);
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write("text/b - " + o);
+                               }
+                       };
                }
        }
 
@@ -88,8 +100,14 @@ public class SerializersResource extends RestServletDefault 
{
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       out.getWriter().write("text/c - " + o);
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write("text/c - " + o);
+                               }
+                       };
                }
        }
 
@@ -109,8 +127,14 @@ public class SerializersResource extends 
RestServletDefault {
                }
 
                @Override /* Serializer */
-               protected void doSerialize(SerializerSession session, 
SerializerOutput out, Object o) throws Exception {
-                       out.getWriter().write("text/d - " + o);
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write("text/d - " + o);
+                               }
+                       };
                }
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java
index 5da647a..40ad1f7 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java
@@ -358,14 +358,9 @@ public class RequestBody {
                                MediaType mediaType = pm.getMediaType();
                                try {
                                        req.getProperties().append("mediaType", 
mediaType).append("characterEncoding", req.getCharacterEncoding());
-                                       if (! p.isReaderParser()) {
-                                               InputStreamParser p2 = 
(InputStreamParser)p;
-                                               ParserSession session = 
p2.createSession(getInputStream(), req.getProperties(), req.getJavaMethod(), 
req.getContext().getResource(), locale, timeZone, mediaType);
-                                               return p2.parseSession(session, 
cm);
-                                       }
-                                       ReaderParser p2 = (ReaderParser)p;
-                                       ParserSession session = 
p2.createSession(getUnbufferedReader(), req.getProperties(), 
req.getJavaMethod(), req.getContext().getResource(), locale, timeZone, 
mediaType);
-                                       return p2.parseSession(session, cm);
+                                       ParserSession session = 
p.createSession(new ParserSessionArgs(req.getProperties(), req.getJavaMethod(), 
locale, timeZone, mediaType, req.getContext().getResource()));
+                                       Object in = session.isReaderParser() ? 
getUnbufferedReader() : getInputStream();
+                                       return session.parse(in, cm);
                                } catch (ParseException e) {
                                        throw new RestException(SC_BAD_REQUEST,
                                                "Could not convert request body 
content to class type ''{0}'' using parser ''{1}''.",

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
index 0bc4181..60d1ff3 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java
@@ -118,7 +118,7 @@ public class RestConfig implements ServletConfig {
        String[] htmlLinks;
        String clientVersionHeader = "X-Client-Version";
 
-       Object resourceResolver = RestResourceResolver.Default.class;
+       Object resourceResolver = RestResourceResolverSimple.class;
        Object logger = RestLogger.Normal.class;
        Object callHandler = RestCallHandler.class;
        Object infoProvider = RestInfoProvider.class;
@@ -156,7 +156,7 @@ public class RestConfig implements ServletConfig {
                this.inner = config;
                this.resourceClass = resourceClass;
                this.parentContext = parentContext;
-               this.resourceResolver = parentContext == null ? 
RestResourceResolver.Default.class : parentContext.getResourceResolver();
+               this.resourceResolver = parentContext == null ? 
RestResourceResolverSimple.class : parentContext.getResourceResolver();
                try {
 
                        ConfigFileBuilder cfb = new ConfigFileBuilder();
@@ -1024,7 +1024,7 @@ public class RestConfig implements ServletConfig {
         * <p>
         * The resource resolver is used to resolve instances from {@link 
Class} objects defined in the
         * {@link RestResource#children()} annotation.
-        * The default value is {@link RestResourceResolver.Default}.
+        * The default value is {@link RestResourceResolverSimple}.
         *
         * <p>
         * This is the programmatic equivalent to the

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
index 1d21176..4a1fb02 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -200,6 +200,9 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                                + "\n=== END 
========================================================================";
                        context.getLogger().log(Level.WARNING, msg);
                }
+
+               if (isPlainText())
+                       
this.properties.put(SerializerContext.SERIALIZER_useWhitespace, true);
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
index 337fbce..30f9d83 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java
@@ -12,10 +12,6 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
-import static org.apache.juneau.internal.ClassUtils.*;
-
-import java.lang.reflect.*;
-
 import org.apache.juneau.rest.annotation.*;
 
 /**
@@ -34,52 +30,12 @@ import org.apache.juneau.rest.annotation.*;
  * </ul>
  *
  * <p>
- * The default implementation simply instantiates the class using one of the 
following constructors:
- * <ul>
- *     <li><code><jk>public</jk> T(RestConfig)</code>
- *     <li><code><jk>public</jk> T()</code>
- * </ul>
- *
- * <p>
- * The former constructor can be used to get access to the {@link RestConfig} 
object to get access to the
- * config file and initialization information or make programmatic 
modifications to the resource before
- * full initialization.
- *
- * <p>
- * Non-<code>RestServlet</code> classes can also add the following two methods 
to get access to the
- * {@link RestConfig} and {@link RestContext} objects:
- * <ul>
- *     <li><code><jk>public void</jk> init(RestConfig);</code>
- *     <li><code><jk>public void</jk> init(RestContext);</code>
- * </ul>
- * 
- * <p>
  * An instance of this class can also be passed in through the servlet context 
as the context attribute
  * {@link RestContext#REST_resourceResolver}.
  */
 public interface RestResourceResolver {
 
        /**
-        * Denotes the default resolver.
-        */
-       public static class Default implements RestResourceResolver {
-               @Override
-               public Object resolve(Class<?> c, RestConfig config) throws 
RestServletException {
-                       try {
-                               Constructor<?> c1 = findPublicConstructor(c, 
RestConfig.class);
-                               if (c1 != null)
-                                       return c1.newInstance(config);
-                               c1 = findPublicConstructor(c);
-                               if (c1 != null)
-                                       return c1.newInstance();
-                       } catch (Exception e) {
-                               throw new RestServletException("Could not 
instantiate resource class ''{0}''", c.getName()).initCause(e);
-                       }
-                       throw new RestServletException("Could not find public 
constructor for class ''{0}''.", c);
-               }
-       }
-
-       /**
         * Resolves the specified class to a resource object.
         *
         * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java
 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java
new file mode 100644
index 0000000..91bf3eb
--- /dev/null
+++ 
b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java
@@ -0,0 +1,59 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+
+/**
+ * Denotes the default resolver.
+ * 
+ * <p>
+ * The default implementation simply instantiates the class using one of the 
following constructors:
+ * <ul>
+ *     <li><code><jk>public</jk> T(RestConfig)</code>
+ *     <li><code><jk>public</jk> T()</code>
+ * </ul>
+ *
+ * <p>
+ * The former constructor can be used to get access to the {@link RestConfig} 
object to get access to the
+ * config file and initialization information or make programmatic 
modifications to the resource before
+ * full initialization.
+ *
+ * <p>
+ * Non-<code>RestServlet</code> classes can also add the following two methods 
to get access to the
+ * {@link RestConfig} and {@link RestContext} objects:
+ * <ul>
+ *     <li><code><jk>public void</jk> init(RestConfig);</code>
+ *     <li><code><jk>public void</jk> init(RestContext);</code>
+ * </ul>
+ *
+ */
+public class RestResourceResolverSimple implements RestResourceResolver {
+
+       @Override /* RestResourceResolver */
+       public Object resolve(Class<?> c, RestConfig config) throws 
RestServletException {
+               try {
+                       Constructor<?> c1 = findPublicConstructor(c, 
RestConfig.class);
+                       if (c1 != null)
+                               return c1.newInstance(config);
+                       c1 = findPublicConstructor(c);
+                       if (c1 != null)
+                               return c1.newInstance();
+               } catch (Exception e) {
+                       throw new RestServletException("Could not instantiate 
resource class ''{0}''", c.getName()).initCause(e);
+               }
+               throw new RestServletException("Could not find public 
constructor for class ''{0}''.", c);
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
index 48473a9..025bb03 100644
--- 
a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
+++ 
b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
@@ -635,7 +635,7 @@ public @interface RestResource {
         * <br>The value (class or instance) can also be set via the servlet 
context attribute 
         * * {@link RestContext#REST_resourceResolver}.
         */
-       Class<? extends RestResourceResolver> resourceResolver() default 
RestResourceResolver.Default.class;
+       Class<? extends RestResourceResolver> resourceResolver() default 
RestResourceResolverSimple.class;
 
        /**
         * Specifies the logger class to use for logging.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
index 42e9b70..aac9172 100644
--- 
a/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
+++ 
b/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
@@ -15,6 +15,7 @@ package org.apache.juneau.rest.response;
 import static javax.servlet.http.HttpServletResponse.*;
 
 import java.io.*;
+import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
@@ -49,43 +50,35 @@ public class DefaultHandler implements ResponseHandler {
                        if (mediaType == null)
                                mediaType = sm.getMediaType();
                        res.setContentType(mediaType.toString());
-                       ObjectMap headers = 
s.getResponseHeaders(res.getProperties());
-                       if (headers != null)
-                               for (String key : headers.keySet())
-                                       res.setHeader(key, 
headers.getString(key));
 
                        try {
                                ObjectMap p = res.getProperties();
                                if (req.isPlainText()) {
-                                       
p.put(SerializerContext.SERIALIZER_useWhitespace, true);
                                        res.setContentType("text/plain");
                                }
                                p.append("mediaType", 
mediaType).append("characterEncoding", res.getCharacterEncoding());
-                               if (! s.isWriterSerializer()) {
+
+                               SerializerSession session = s.createSession(new 
SerializerSessionArgs(p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType, req.getUriContext()));
+
+                               for (Map.Entry<String,String> h : 
session.getResponseHeaders().entrySet())
+                                       res.setHeader(h.getKey(), h.getValue());
+
+                               if (! session.isWriterSerializer()) {
                                        if (req.isPlainText()) {
-                                               OutputStreamSerializer s2 = 
(OutputStreamSerializer)s;
                                                Writer w = 
res.getNegotiatedWriter();
                                                ByteArrayOutputStream baos = 
new ByteArrayOutputStream();
-                                               SerializerOutput sout = new 
SerializerOutput(baos);
-                                               SerializerSession session = 
s.createSession(p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType, req.getUriContext());
-                                               s2.serialize(session, sout, 
output);
+                                               session.serialize(baos, output);
                                                
w.write(StringUtils.toHex(baos.toByteArray()));
-                                               w.close();
+                                               w.close();  // Leave open if 
exception occurs.
                                        } else {
-                                               OutputStreamSerializer s2 = 
(OutputStreamSerializer)s;
                                                OutputStream os = 
res.getNegotiatedOutputStream();
-                                               SerializerOutput sout = new 
SerializerOutput(os);
-                                               SerializerSession session = 
s.createSession(p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType, req.getUriContext());
-                                               s2.serialize(session, sout, 
output);
-                                               os.close();
+                                               session.serialize(os, output);
+                                               os.close();  // Leave open if 
exception occurs.
                                        }
                                } else {
-                                       WriterSerializer s2 = 
(WriterSerializer)s;
                                        Writer w = res.getNegotiatedWriter();
-                                       SerializerOutput sout = new 
SerializerOutput(w);
-                                       SerializerSession session = 
s.createSession(p, req.getJavaMethod(), req.getLocale(), 
req.getHeaders().getTimeZone(), mediaType, req.getUriContext());
-                                       s2.serialize(session, sout, output);
-                                       w.close();
+                                       session.serialize(w, output);
+                                       w.close();  // Leave open if exception 
occurs.
                                }
                        } catch (SerializeException e) {
                                throw new 
RestException(SC_INTERNAL_SERVER_ERROR, e);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java
index 66c773e..a3962e2 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java
@@ -63,10 +63,7 @@ import org.apache.juneau.utils.*;
  */
 public class FileVar extends DefaultingVar {
 
-       /**
-        * The name of the session or context object that identifies the {@link 
RestRequest} object.
-        */
-       public static final String SESSION_req = "req";
+       private static final String SESSION_req = "req";
 
        /**
         * The name of this variable.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
index 550a57e..a90d28d 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
@@ -23,7 +23,7 @@ import org.apache.juneau.svl.*;
  *
  * <p>
  * The format for this var is <js>"$R{key[,defaultValue]}"</js>.
- * 
+ *
  * <p>
  * The possible values are:
  * <ul>
@@ -63,6 +63,7 @@ public class RequestVar extends DefaultingVar {
         */
        public static final String SESSION_req = "req";
 
+
        /** The name of this variable. */
        public static final String NAME = "R";
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java
index 12fa846..365d48e 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java
@@ -42,10 +42,7 @@ import org.apache.juneau.svl.*;
  */
 public class UrlVar extends SimpleVar {
 
-       /**
-        * The name of the session or context object that identifies the {@link 
RestRequest} object.
-        */
-       public static final String SESSION_req = "req";
+       private static final String SESSION_req = "req";
 
        /** The name of this variable. */
        public static final String NAME = "U";

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
index 1b11155..2c3516c 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
@@ -40,7 +40,7 @@ public class WidgetVar extends SimpleVar {
        /**
         * The name of the session or context object that identifies the {@link 
RestRequest} object.
         */
-       public static final String SESSION_req = "req";
+       private static final String SESSION_req = "req";
 
        /**
         * The name of this variable.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java 
b/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
index e65ca3f..3671573 100644
--- 
a/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
+++ 
b/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
@@ -17,6 +17,7 @@ import java.io.*;
 import org.apache.juneau.html.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.serializer.*;
 
 /**
  * A subclass of widgets for rendering menu items with drop-down windows.
@@ -78,15 +79,23 @@ public abstract class MenuItemWidget extends Widget {
                sb.append(""
                        + "<div class='menu-item'>"
                        + "\n\t<a class='link' 
onclick='menuClick(this)'>"+getLabel(req)+"</a>"
-                       + "\n\t<div class='popup-content'>"
+                       + "\n\t<div class='popup-content'>\n"
                );
                Object o = getContent(req);
                if (o instanceof Reader)
                        IOUtils.pipe((Reader)o, new StringBuilderWriter(sb));
                else if (o instanceof CharSequence)
                        sb.append((CharSequence)o);
-               else
-                       HtmlSerializer.DEFAULT.serialize(getContent(req), sb);
+               else {
+                       SerializerSessionArgs args = new 
SerializerSessionArgs(req.getProperties(), null, req.getLocale(), null, null, 
req.getUriContext());
+                       WriterSerializerSession session = 
HtmlSerializer.DEFAULT.createSession(args);
+                       try {
+                               session.indent = 2;
+                               session.serialize(sb, o);
+                       } finally {
+                               session.close();
+                       }
+               }
                sb.append(""
                        + "\n\t</div>"
                        + "\n</div>"
@@ -114,8 +123,8 @@ public abstract class MenuItemWidget extends Widget {
         *              <li>{@link Reader} - Serialized directly to the output.
         *              <li>{@link CharSequence} - Serialized directly to the 
output.
         *              <li>Other - Serialized as HTML using {@link 
HtmlSerializer#DEFAULT}.
+        *                      <br>Note that this includes any of the {@link 
org.apache.juneau.dto.html5} beans.
         *      </ul>
-        *      Note that this includes any of the {@link 
org.apache.juneau.dto.html5} beans.
         * @throws Exception
         */
        public abstract Object getContent(RestRequest req) throws Exception;

Reply via email to