http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
index 12f3fb6..28a895a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
@@ -12,20 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.html;
 
-import static javax.xml.stream.XMLStreamConstants.*;
-import static org.apache.juneau.html.HtmlTag.*;
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import javax.xml.stream.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.parser.*;
-import org.apache.juneau.transform.*;
 import org.apache.juneau.xml.*;
 
 /**
@@ -48,7 +37,7 @@ import org.apache.juneau.xml.*;
  *     <li>{@link HtmlSerializerContext}
  * </ul>
  */
-@SuppressWarnings({ "rawtypes", "unchecked", "hiding" })
+@SuppressWarnings({ "hiding" })
 @Consumes("text/html,text/html+stripped")
 public class HtmlParser extends XmlParser {
 
@@ -73,529 +62,8 @@ public class HtmlParser extends XmlParser {
                return new HtmlParserBuilder(propertyStore);
        }
 
-       /*
-        * Reads anything starting at the current event.
-        * <p>
-        * Precondition:  Must be pointing at outer START_ELEMENT.
-        * Postcondition:  Pointing at outer END_ELEMENT.
-        */
-       private <T> T parseAnything(HtmlParserSession session, ClassMeta<T> 
eType, XMLStreamReader r, Object outer,
-                       boolean isRoot, BeanPropertyMeta pMeta) throws 
Exception {
-
-               if (eType == null)
-                       eType = (ClassMeta<T>)object();
-               PojoSwap<T,Object> transform = 
(PojoSwap<T,Object>)eType.getPojoSwap();
-               ClassMeta<?> sType = eType.getSerializedClassMeta();
-               session.setCurrentClass(sType);
-
-               int event = r.getEventType();
-               if (event != START_ELEMENT)
-                       throw new XmlParseException(r.getLocation(), 
"parseAnything must be called on outer start element.");
-
-               if (! isRoot)
-                       event = r.next();
-               boolean isEmpty = (event == END_ELEMENT);
-
-               // Skip until we find a start element, end document, or 
non-empty text.
-               if (! isEmpty)
-                       event = skipWs(r);
-
-               if (event == END_DOCUMENT)
-                       throw new XmlParseException(r.getLocation(), 
"Unexpected end of stream in parseAnything for type ''{0}''", eType);
-
-               // Handle @Html(asXml=true) beans.
-               HtmlClassMeta hcm = sType.getExtendedMeta(HtmlClassMeta.class);
-               if (hcm.isAsXml())
-                       return super.parseAnything(session, eType, null, r, 
outer, false, pMeta);
-
-               Object o = null;
-
-               boolean isValid = true;
-               HtmlTag tag = (event == CHARACTERS ? null : 
HtmlTag.forString(r.getName().getLocalPart(), false));
-
-               if (tag == HTML)
-                       tag = skipToData(r);
-
-               if (isEmpty) {
-                       o = "";
-               } else if (tag == null || tag.isOneOf(BR,BS,FF,SP)) {
-                       String text = session.parseText(r);
-                       if (sType.isObject() || sType.isCharSequence())
-                               o = text;
-                       else if (sType.isChar())
-                               o = text.charAt(0);
-                       else if (sType.isBoolean())
-                               o = Boolean.parseBoolean(text);
-                       else if (sType.isNumber())
-                               o = parseNumber(text, (Class<? extends 
Number>)eType.getInnerClass());
-                       else if (sType.canCreateNewInstanceFromString(outer))
-                               o = sType.newInstanceFromString(outer, text);
-                       else if (sType.canCreateNewInstanceFromNumber(outer))
-                               o = sType.newInstanceFromNumber(session, outer, 
parseNumber(text, sType.getNewInstanceFromNumberClass()));
-                       else
-                               isValid = false;
-
-               } else if (tag == STRING || (tag == A && pMeta != null
-                               && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getLink() != null)) {
-                       String text = session.getElementText(r);
-                       if (sType.isObject() || sType.isCharSequence())
-                               o = text;
-                       else if (sType.isChar())
-                               o = text.charAt(0);
-                       else if (sType.canCreateNewInstanceFromString(outer))
-                               o = sType.newInstanceFromString(outer, text);
-                       else if (sType.canCreateNewInstanceFromNumber(outer))
-                               o = sType.newInstanceFromNumber(session, outer, 
parseNumber(text, sType.getNewInstanceFromNumberClass()));
-                       else
-                               isValid = false;
-                       skipTag(r, tag == STRING ? xSTRING : xA);
-
-               } else if (tag == NUMBER) {
-                       String text = session.getElementText(r);
-                       if (sType.isObject())
-                               o = parseNumber(text, Number.class);
-                       else if (sType.isNumber())
-                               o = parseNumber(text, (Class<? extends 
Number>)sType.getInnerClass());
-                       else if (sType.canCreateNewInstanceFromNumber(outer))
-                               o = sType.newInstanceFromNumber(session, outer, 
parseNumber(text, sType.getNewInstanceFromNumberClass()));
-                       else
-                               isValid = false;
-                       skipTag(r, xNUMBER);
-
-               } else if (tag == BOOLEAN) {
-                       String text = session.getElementText(r);
-                       if (sType.isObject() || sType.isBoolean())
-                               o = Boolean.parseBoolean(text);
-                       else
-                               isValid = false;
-                       skipTag(r, xBOOLEAN);
-
-               } else if (tag == P) {
-                       String text = session.getElementText(r);
-                       if (! "No Results".equals(text))
-                               isValid = false;
-                       skipTag(r, xP);
-
-               } else if (tag == NULL) {
-                       skipTag(r, NULL);
-                       skipTag(r, xNULL);
-
-               } else if (tag == A) {
-                       o = parseAnchor(session, r, eType);
-                       skipTag(r, xA);
-
-               } else if (tag == TABLE) {
-
-                       String typeName = getAttribute(r, 
session.getBeanTypePropertyName(eType), "object");
-                       ClassMeta cm = session.getClassMeta(typeName, pMeta, 
eType);
-
-                       if (cm != null) {
-                               sType = eType = cm;
-                               typeName = sType.isArray() ? "array" : "object";
-                       } else if (! "array".equals(typeName)) {
-                               // Type name could be a subtype name.
-                               typeName = "object";
-                       }
-
-                       if (typeName.equals("object")) {
-                               if (sType.isObject()) {
-                                       o = parseIntoMap(session, r, (Map)new 
ObjectMap(session), sType.getKeyType(), sType.getValueType(),
-                                               pMeta);
-                               } else if (sType.isMap()) {
-                                       o = parseIntoMap(session, r, 
(Map)(sType.canCreateNewInstance(outer) ? sType.newInstance(outer)
-                                               : new ObjectMap(session)), 
sType.getKeyType(), sType.getValueType(), pMeta);
-                               } else if (sType.canCreateNewBean(outer)) {
-                                       BeanMap m = session.newBeanMap(outer, 
sType.getInnerClass());
-                                       o = parseIntoBean(session, r, 
m).getBean();
-                               } else {
-                                       isValid = false;
-                               }
-                               skipTag(r, xTABLE);
-
-                       } else if (typeName.equals("array")) {
-                               if (sType.isObject())
-                                       o = parseTableIntoCollection(session, 
r, (Collection)new ObjectList(session), sType, pMeta);
-                               else if (sType.isCollection())
-                                       o = parseTableIntoCollection(session, 
r, (Collection)(sType.canCreateNewInstance(outer)
-                                               ? sType.newInstance(outer) : 
new ObjectList(session)), sType, pMeta);
-                               else if (sType.isArray() || sType.isArgs()) {
-                                       ArrayList l = 
(ArrayList)parseTableIntoCollection(session, r, new ArrayList(), sType, pMeta);
-                                       o = session.toArray(sType, l);
-                               }
-                               else
-                                       isValid = false;
-                               skipTag(r, xTABLE);
-
-                       } else {
-                               isValid = false;
-                       }
-
-               } else if (tag == UL) {
-                       String typeName = getAttribute(r, 
session.getBeanTypePropertyName(eType), "array");
-                       ClassMeta cm = session.getClassMeta(typeName, pMeta, 
eType);
-                       if (cm != null)
-                               sType = eType = cm;
-
-                       if (sType.isObject())
-                               o = parseIntoCollection(session, r, new 
ObjectList(session), sType, pMeta);
-                       else if (sType.isCollection() || sType.isObject())
-                               o = parseIntoCollection(session, r, 
(Collection)(sType.canCreateNewInstance(outer)
-                                       ? sType.newInstance(outer) : new 
ObjectList(session)), sType, pMeta);
-                       else if (sType.isArray() || sType.isArgs())
-                               o = session.toArray(sType, 
parseIntoCollection(session, r, new ArrayList(), sType, pMeta));
-                       else
-                               isValid = false;
-                       skipTag(r, xUL);
-
-               }
-
-               if (! isValid)
-                       throw new XmlParseException(r.getLocation(), 
"Unexpected tag ''{0}'' for type ''{1}''", tag, eType);
-
-               if (transform != null && o != null)
-                       o = transform.unswap(session, o, eType);
-
-               if (outer != null)
-                       setParent(eType, o, outer);
-
-               skipWs(r);
-               return (T)o;
-       }
-
-       /**
-        * For parsing output from HtmlDocSerializer, this skips over the head, 
title, and links.
-        */
-       private static HtmlTag skipToData(XMLStreamReader r) throws Exception {
-               while (true) {
-                       int event = r.next();
-                       if (event == START_ELEMENT && 
"div".equals(r.getLocalName()) && "data".equals(r.getAttributeValue(null, 
"id"))) {
-                               r.nextTag();
-                               event = r.getEventType();
-                               boolean isEmpty = (event == END_ELEMENT);
-                               // Skip until we find a start element, end 
document, or non-empty text.
-                               if (! isEmpty)
-                                       event = skipWs(r);
-                               if (event == END_DOCUMENT)
-                                       throw new 
XmlParseException(r.getLocation(), "Unexpected end of stream looking for 
data.");
-                               return (event == CHARACTERS ? null : 
HtmlTag.forString(r.getName().getLocalPart(), false));
-                       }
-               }
-       }
-
-       private static String getAttribute(XMLStreamReader r, String name, 
String def) {
-               for (int i = 0; i < r.getAttributeCount(); i++)
-                       if (r.getAttributeLocalName(i).equals(name))
-                               return r.getAttributeValue(i);
-               return def;
-       }
-
-       /*
-        * Reads an anchor tag and converts it into a bean.
-        */
-       private static <T> T parseAnchor(HtmlParserSession session, 
XMLStreamReader r, ClassMeta<T> beanType)
-                       throws Exception {
-               String href = r.getAttributeValue(null, "href");
-               String name = session.getElementText(r);
-               Class<T> beanClass = beanType.getInnerClass();
-               if (beanClass.isAnnotationPresent(HtmlLink.class)) {
-                       HtmlLink h = beanClass.getAnnotation(HtmlLink.class);
-                       BeanMap<T> m = session.newBeanMap(beanClass);
-                       m.put(h.hrefProperty(), href);
-                       m.put(h.nameProperty(), name);
-                       return m.getBean();
-               }
-               return session.convertToType(href, beanType);
-       }
-
-       private static Map<String,String> getAttributes(XMLStreamReader r) {
-               Map<String,String> m = new TreeMap<String,String>() ;
-               for (int i = 0; i < r.getAttributeCount(); i++)
-                       m.put(r.getAttributeLocalName(i), 
r.getAttributeValue(i));
-               return m;
-       }
-
-       /*
-        * Reads contents of <table> element.
-        * Precondition:  Must be pointing at <table> event.
-        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
-        */
-       private <K,V> Map<K,V> parseIntoMap(HtmlParserSession session, 
XMLStreamReader r, Map<K,V> m, ClassMeta<K> keyType,
-                       ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws 
Exception {
-               while (true) {
-                       HtmlTag tag = nextTag(r, TR, xTABLE);
-                       if (tag == xTABLE)
-                               break;
-                       tag = nextTag(r, TD, TH);
-                       // Skip over the column headers.
-                       if (tag == TH) {
-                               skipTag(r);
-                               r.nextTag();
-                               skipTag(r);
-                       } else {
-                               K key = parseAnything(session, keyType, r, m, 
false, pMeta);
-                               nextTag(r, TD);
-                               V value = parseAnything(session, valueType, r, 
m, false, pMeta);
-                               setName(valueType, value, key);
-                               m.put(key, value);
-                       }
-                       nextTag(r, xTR);
-               }
-
-               return m;
-       }
-
-       /*
-        * Reads contents of <ul> element.
-        * Precondition:  Must be pointing at event following <ul> event.
-        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
-        */
-       private <E> Collection<E> parseIntoCollection(HtmlParserSession 
session, XMLStreamReader r, Collection<E> l,
-                       ClassMeta<?> type, BeanPropertyMeta pMeta) throws 
Exception {
-               int argIndex = 0;
-               while (true) {
-                       HtmlTag tag = nextTag(r, LI, xUL);
-                       if (tag == xUL)
-                               break;
-                       ClassMeta<?> elementType = type.isArgs() ? 
type.getArg(argIndex++) : type.getElementType();
-                       l.add((E)parseAnything(session, elementType, r, l, 
false, pMeta));
-               }
-               return l;
-       }
-
-       /*
-        * Reads contents of <ul> element.
-        * Precondition:  Must be pointing at event following <ul> event.
-        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
-        */
-       private <E> Collection<E> parseTableIntoCollection(HtmlParserSession 
session, XMLStreamReader r, Collection<E> l,
-                       ClassMeta<E> type, BeanPropertyMeta pMeta) throws 
Exception {
-
-               HtmlTag tag = nextTag(r, TR);
-               List<String> keys = new ArrayList<String>();
-               while (true) {
-                       tag = nextTag(r, TH, xTR);
-                       if (tag == xTR)
-                               break;
-                       keys.add(session.getElementText(r));
-               }
-
-               int argIndex = 0;
-
-               while (true) {
-                       r.nextTag();
-                       tag = HtmlTag.forEvent(r);
-                       if (tag == xTABLE)
-                               break;
-
-                       ClassMeta elementType = null;
-                       String beanType = getAttribute(r, 
session.getBeanTypePropertyName(type), null);
-                       if (beanType != null)
-                               elementType = session.getClassMeta(beanType, 
pMeta, null);
-                       if (elementType == null)
-                               elementType = type.isArgs() ? 
type.getArg(argIndex++) : type.getElementType();
-                       if (elementType == null)
-                               elementType = session.object();
-
-                       if (elementType.canCreateNewBean(l)) {
-                               BeanMap m = session.newBeanMap(l, 
elementType.getInnerClass());
-                               for (int i = 0; i < keys.size(); i++) {
-                                       tag = nextTag(r, TD, NULL);
-                                       if (tag == NULL) {
-                                               m = null;
-                                               nextTag(r, xNULL);
-                                               break;
-                                       }
-                                       String key = keys.get(i);
-                                       BeanMapEntry e = m.getProperty(key);
-                                       if (e == null) {
-                                               //onUnknownProperty(key, m, -1, 
-1);
-                                               parseAnything(session, 
object(), r, l, false, null);
-                                       } else {
-                                               BeanPropertyMeta bpm = 
e.getMeta();
-                                               ClassMeta<?> cm = 
bpm.getClassMeta();
-                                               Object value = 
parseAnything(session, cm, r, m.getBean(false), false, bpm);
-                                               setName(cm, value, key);
-                                               bpm.set(m, key, value);
-                                       }
-                               }
-                               l.add(m == null ? null : (E)m.getBean());
-                       } else {
-                               String c = 
getAttributes(r).get(session.getBeanTypePropertyName(type.getElementType()));
-                               Map m = (Map)(elementType.isMap() && 
elementType.canCreateNewInstance(l) ? elementType.newInstance(l)
-                                       : new ObjectMap(session));
-                               for (int i = 0; i < keys.size(); i++) {
-                                       tag = nextTag(r, TD, NULL);
-                                       if (tag == NULL) {
-                                               m = null;
-                                               nextTag(r, xNULL);
-                                               break;
-                                       }
-                                       String key = keys.get(i);
-                                       if (m != null) {
-                                               ClassMeta<?> kt = 
elementType.getKeyType(), vt = elementType.getValueType();
-                                               Object value = 
parseAnything(session, vt, r, l, false, pMeta);
-                                               setName(vt, value, key);
-                                               
m.put(session.convertToType(key, kt), value);
-                                       }
-                               }
-                               if (m != null && c != null) {
-                                       ObjectMap m2 = (m instanceof ObjectMap 
? (ObjectMap)m : new ObjectMap(m).setBeanSession(session));
-                                       
m2.put(session.getBeanTypePropertyName(type.getElementType()), c);
-                                       l.add((E)session.cast(m2, pMeta, 
elementType));
-                               } else {
-                                       l.add((E)m);
-                               }
-                       }
-                       nextTag(r, xTR);
-               }
-               return l;
-       }
-
-       /*
-        * Reads contents of <table> element.
-        * Precondition:  Must be pointing at event following <table> event.
-        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
-        */
-       private <T> BeanMap<T> parseIntoBean(HtmlParserSession session, 
XMLStreamReader r, BeanMap<T> m) throws Exception {
-               while (true) {
-                       HtmlTag tag = nextTag(r, TR, xTABLE);
-                       if (tag == xTABLE)
-                               break;
-                       tag = nextTag(r, TD, TH);
-                       // Skip over the column headers.
-                       if (tag == TH) {
-                               skipTag(r);
-                               r.nextTag();
-                               skipTag(r);
-                       } else {
-                               String key = session.getElementText(r);
-                               nextTag(r, TD);
-                               BeanPropertyMeta pMeta = m.getPropertyMeta(key);
-                               if (pMeta == null) {
-                                       session.onUnknownProperty(key, m, -1, 
-1);
-                                       parseAnything(session, object(), r, 
null, false, null);
-                               } else {
-                                       ClassMeta<?> cm = pMeta.getClassMeta();
-                                       Object value = parseAnything(session, 
cm, r, m.getBean(false), false, pMeta);
-                                       setName(cm, value, key);
-                                       pMeta.set(m, key, value);
-                               }
-                       }
-                       nextTag(r, xTR);
-               }
-               return m;
-       }
-
-       /*
-        * Reads the next tag.  Advances past anything that's not a start or 
end tag.  Throws an exception if
-        *      it's not one of the expected tags.
-        * Precondition:  Must be pointing before the event we want to parse.
-        * Postcondition:  Pointing at the tag just parsed.
-        */
-       private static HtmlTag nextTag(XMLStreamReader r, HtmlTag...expected) 
throws Exception {
-               int et = r.next();
-
-               while (et != START_ELEMENT && et != END_ELEMENT && et != 
END_DOCUMENT)
-                       et = r.next();
-
-               if (et == END_DOCUMENT)
-                       throw new XmlParseException(r.getLocation(), 
"Unexpected end of document.");
-
-               HtmlTag tag = HtmlTag.forEvent(r);
-               if (expected.length == 0)
-                       return tag;
-               for (HtmlTag t : expected)
-                       if (t == tag)
-                               return tag;
-
-               throw new XmlParseException(r.getLocation(), "Unexpected tag: 
''{0}''.  Expected one of the following: {1}", tag, expected);
-       }
-
-       /*
-        * Skips over the current element and advances to the next element.
-        * <p>
-        * Precondition:  Pointing to opening tag.
-        * Postcondition:  Pointing to next opening tag.
-        *
-        * @param r The stream being read from.
-        * @throws XMLStreamException
-        */
-       private static void skipTag(XMLStreamReader r) throws Exception {
-               int et = r.getEventType();
-
-               if (et != START_ELEMENT)
-                       throw new XmlParseException(
-                               r.getLocation(),
-                               "skipToNextTag() call on invalid event ''{0}''. 
 Must only be called on START_ELEMENT events.",
-                               XmlUtils.toReadableEvent(r)
-                       );
-
-               String n = r.getLocalName();
-
-               int depth = 0;
-               while (true) {
-                       et = r.next();
-                       if (et == START_ELEMENT) {
-                               String n2 = r.getLocalName();
-                                       if (n.equals(n2))
-                               depth++;
-                       } else if (et == END_ELEMENT) {
-                               String n2 = r.getLocalName();
-                               if (n.equals(n2))
-                                       depth--;
-                               if (depth < 0)
-                                       return;
-                       }
-               }
-       }
-
-       private static void skipTag(XMLStreamReader r, HtmlTag...expected) 
throws Exception {
-               HtmlTag tag = HtmlTag.forEvent(r);
-               if (tag.isOneOf(expected))
-                       r.next();
-               else
-                       throw new XmlParseException(
-                               r.getLocation(),
-                               "Unexpected tag: ''{0}''.  Expected one of the 
following: {1}",
-                               tag, expected);
-       }
-
-       private static int skipWs(XMLStreamReader r)  throws XMLStreamException 
{
-               int event = r.getEventType();
-               while (event != START_ELEMENT && event != END_ELEMENT && event 
!= END_DOCUMENT && r.isWhiteSpace())
-                       event = r.next();
-               return event;
-       }
-
-
-       
//--------------------------------------------------------------------------------
-       // Entry point methods
-       
//--------------------------------------------------------------------------------
-
        @Override /* Parser */
-       public HtmlParserSession createSession(Object input, ObjectMap op, 
Method javaMethod, Object outer, Locale locale,
-                       TimeZone timeZone, MediaType mediaType) {
-               return new HtmlParserSession(ctx, op, input, javaMethod, outer, 
locale, timeZone, mediaType);
-       }
-
-       @Override /* Parser */
-       protected <T> T doParse(ParserSession session, ClassMeta<T> type) 
throws Exception {
-               HtmlParserSession s = (HtmlParserSession)session;
-               return parseAnything(s, type, s.getXmlStreamReader(), 
s.getOuter(), true, null);
-       }
-
-       @Override /* ReaderParser */
-       protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> 
m, Type keyType, Type valueType)
-                       throws Exception {
-               HtmlParserSession s = (HtmlParserSession)session;
-               return parseIntoMap(s, s.getXmlStreamReader(), m, 
(ClassMeta<K>)s.getClassMeta(keyType),
-                       (ClassMeta<V>)s.getClassMeta(valueType), null);
-       }
-
-       @Override /* ReaderParser */
-       protected <E> Collection<E> doParseIntoCollection(ParserSession 
session, Collection<E> c, Type elementType)
-                       throws Exception {
-               HtmlParserSession s = (HtmlParserSession)session;
-               return parseIntoCollection(s, s.getXmlStreamReader(), c, 
s.getClassMeta(elementType), null);
+       public HtmlParserSession createSession(ParserSessionArgs args) {
+               return new HtmlParserSession(ctx, args);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index 5b4d9d6..376843a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -16,22 +16,24 @@ import static javax.xml.stream.XMLStreamConstants.*;
 import static org.apache.juneau.html.HtmlTag.*;
 import static org.apache.juneau.internal.StringUtils.*;
 
-import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
 import javax.xml.stream.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.transform.*;
 import org.apache.juneau.xml.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link 
HtmlParser}.
  *
  * <p>
- * This class is NOT thread safe.  It is meant to be discarded after one-time 
use.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused 
against multiple inputs.
  */
+@SuppressWarnings({ "unchecked", "rawtypes" })
 public final class HtmlParserSession extends XmlParserSession {
 
        private static final Set<String> whitespaceElements = new 
HashSet<String>(
@@ -46,31 +48,527 @@ public final class HtmlParserSession extends 
XmlParserSession {
         * @param ctx
         *      The context creating this session object.
         *      The context contains all the configuration settings for this 
object.
-        * @param input
-        *      The input.  Can be any of the following types:
-        *      <ul>
-        *              <li><jk>null</jk>
-        *              <li>{@link Reader}
-        *              <li>{@link CharSequence}
-        *              <li>{@link InputStream} containing UTF-8 encoded text.
-        *              <li>{@link File} containing system encoded text.
-        *      </ul>
-        * @param op
-        *      The override properties.
-        *      These override any context properties defined in the context.
-        * @param javaMethod The java method that called this parser, usually 
the method in a REST servlet.
-        * @param outer The outer object for instantiating top-level non-static 
inner classes.
-        * @param locale
-        *      The session locale.
-        *      If <jk>null</jk>, then the locale defined on the context is 
used.
-        * @param timeZone
-        *      The session timezone.
-        *      If <jk>null</jk>, then the timezone defined on the context is 
used.
-        * @param mediaType The session media type (e.g. 
<js>"application/json"</js>).
+        * @param args
+        *      Runtime session arguments.
         */
-       public HtmlParserSession(HtmlParserContext ctx, ObjectMap op, Object 
input, Method javaMethod, Object outer,
-                       Locale locale, TimeZone timeZone, MediaType mediaType) {
-               super(ctx, op, input, javaMethod, outer, locale, timeZone, 
mediaType);
+       protected HtmlParserSession(HtmlParserContext ctx, ParserSessionArgs 
args) {
+               super(ctx, args);
+       }
+
+       @Override /* ParserSession */
+       protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws 
Exception {
+               return parseAnything(type, getXmlReader(pipe), getOuter(), 
true, null);
+       }
+
+       @Override /* ReaderParserSession */
+       protected <K,V> Map<K,V> doParseIntoMap(ParserPipe pipe, Map<K,V> m, 
Type keyType, Type valueType)
+                       throws Exception {
+               return parseIntoMap(getXmlReader(pipe), m, 
(ClassMeta<K>)getClassMeta(keyType),
+                       (ClassMeta<V>)getClassMeta(valueType), null);
+       }
+
+       @Override /* ReaderParserSession */
+       protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, 
Collection<E> c, Type elementType)
+                       throws Exception {
+               return parseIntoCollection(getXmlReader(pipe), c, 
getClassMeta(elementType), null);
+       }
+
+       /*
+        * Reads anything starting at the current event.
+        * <p>
+        * Precondition:  Must be pointing at outer START_ELEMENT.
+        * Postcondition:  Pointing at outer END_ELEMENT.
+        */
+       private <T> T parseAnything(ClassMeta<T> eType, XmlReader r, Object 
outer, boolean isRoot, BeanPropertyMeta pMeta) throws Exception {
+
+               if (eType == null)
+                       eType = (ClassMeta<T>)object();
+               PojoSwap<T,Object> transform = 
(PojoSwap<T,Object>)eType.getPojoSwap();
+               ClassMeta<?> sType = eType.getSerializedClassMeta();
+               setCurrentClass(sType);
+
+               int event = r.getEventType();
+               if (event != START_ELEMENT)
+                       throw new XmlParseException(r.getLocation(), 
"parseAnything must be called on outer start element.");
+
+               if (! isRoot)
+                       event = r.next();
+               boolean isEmpty = (event == END_ELEMENT);
+
+               // Skip until we find a start element, end document, or 
non-empty text.
+               if (! isEmpty)
+                       event = skipWs(r);
+
+               if (event == END_DOCUMENT)
+                       throw new XmlParseException(r.getLocation(), 
"Unexpected end of stream in parseAnything for type ''{0}''", eType);
+
+               // Handle @Html(asXml=true) beans.
+               HtmlClassMeta hcm = sType.getExtendedMeta(HtmlClassMeta.class);
+               if (hcm.isAsXml())
+                       return super.parseAnything(eType, null, r, outer, 
false, pMeta);
+
+               Object o = null;
+
+               boolean isValid = true;
+               HtmlTag tag = (event == CHARACTERS ? null : 
HtmlTag.forString(r.getName().getLocalPart(), false));
+
+               // If it's not a known tag, then parse it as XML.
+               // Allows us to parse stuff like "<div/>" into HTML5 beans.
+               if (tag == null && event != CHARACTERS)
+                       return super.parseAnything(eType, null, r, outer, 
false, pMeta);
+
+               if (tag == HTML)
+                       tag = skipToData(r);
+
+               if (isEmpty) {
+                       o = "";
+               } else if (tag == null || tag.isOneOf(BR,BS,FF,SP)) {
+                       String text = parseText(r);
+                       if (sType.isObject() || sType.isCharSequence())
+                               o = text;
+                       else if (sType.isChar())
+                               o = text.charAt(0);
+                       else if (sType.isBoolean())
+                               o = Boolean.parseBoolean(text);
+                       else if (sType.isNumber())
+                               o = parseNumber(text, (Class<? extends 
Number>)eType.getInnerClass());
+                       else if (sType.canCreateNewInstanceFromString(outer))
+                               o = sType.newInstanceFromString(outer, text);
+                       else if (sType.canCreateNewInstanceFromNumber(outer))
+                               o = sType.newInstanceFromNumber(this, outer, 
parseNumber(text, sType.getNewInstanceFromNumberClass()));
+                       else
+                               isValid = false;
+
+               } else if (tag == STRING || (tag == A && pMeta != null
+                               && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getLink() != null)) {
+                       String text = getElementText(r);
+                       if (sType.isObject() || sType.isCharSequence())
+                               o = text;
+                       else if (sType.isChar())
+                               o = text.charAt(0);
+                       else if (sType.canCreateNewInstanceFromString(outer))
+                               o = sType.newInstanceFromString(outer, text);
+                       else if (sType.canCreateNewInstanceFromNumber(outer))
+                               o = sType.newInstanceFromNumber(this, outer, 
parseNumber(text, sType.getNewInstanceFromNumberClass()));
+                       else
+                               isValid = false;
+                       skipTag(r, tag == STRING ? xSTRING : xA);
+
+               } else if (tag == NUMBER) {
+                       String text = getElementText(r);
+                       if (sType.isObject())
+                               o = parseNumber(text, Number.class);
+                       else if (sType.isNumber())
+                               o = parseNumber(text, (Class<? extends 
Number>)sType.getInnerClass());
+                       else if (sType.canCreateNewInstanceFromNumber(outer))
+                               o = sType.newInstanceFromNumber(this, outer, 
parseNumber(text, sType.getNewInstanceFromNumberClass()));
+                       else
+                               isValid = false;
+                       skipTag(r, xNUMBER);
+
+               } else if (tag == BOOLEAN) {
+                       String text = getElementText(r);
+                       if (sType.isObject() || sType.isBoolean())
+                               o = Boolean.parseBoolean(text);
+                       else
+                               isValid = false;
+                       skipTag(r, xBOOLEAN);
+
+               } else if (tag == P) {
+                       String text = getElementText(r);
+                       if (! "No Results".equals(text))
+                               isValid = false;
+                       skipTag(r, xP);
+
+               } else if (tag == NULL) {
+                       skipTag(r, NULL);
+                       skipTag(r, xNULL);
+
+               } else if (tag == A) {
+                       o = parseAnchor(r, eType);
+                       skipTag(r, xA);
+
+               } else if (tag == TABLE) {
+
+                       String typeName = getAttribute(r, 
getBeanTypePropertyName(eType), "object");
+                       ClassMeta cm = getClassMeta(typeName, pMeta, eType);
+
+                       if (cm != null) {
+                               sType = eType = cm;
+                               typeName = sType.isArray() ? "array" : "object";
+                       } else if (! "array".equals(typeName)) {
+                               // Type name could be a subtype name.
+                               typeName = "object";
+                       }
+
+                       if (typeName.equals("object")) {
+                               if (sType.isObject()) {
+                                       o = parseIntoMap(r, (Map)new 
ObjectMap(this), sType.getKeyType(), sType.getValueType(),
+                                               pMeta);
+                               } else if (sType.isMap()) {
+                                       o = parseIntoMap(r, 
(Map)(sType.canCreateNewInstance(outer) ? sType.newInstance(outer)
+                                               : new ObjectMap(this)), 
sType.getKeyType(), sType.getValueType(), pMeta);
+                               } else if (sType.canCreateNewBean(outer)) {
+                                       BeanMap m = newBeanMap(outer, 
sType.getInnerClass());
+                                       o = parseIntoBean(r, m).getBean();
+                               } else {
+                                       isValid = false;
+                               }
+                               skipTag(r, xTABLE);
+
+                       } else if (typeName.equals("array")) {
+                               if (sType.isObject())
+                                       o = parseTableIntoCollection(r, 
(Collection)new ObjectList(this), sType, pMeta);
+                               else if (sType.isCollection())
+                                       o = parseTableIntoCollection(r, 
(Collection)(sType.canCreateNewInstance(outer)
+                                               ? sType.newInstance(outer) : 
new ObjectList(this)), sType, pMeta);
+                               else if (sType.isArray() || sType.isArgs()) {
+                                       ArrayList l = 
(ArrayList)parseTableIntoCollection(r, new ArrayList(), sType, pMeta);
+                                       o = toArray(sType, l);
+                               }
+                               else
+                                       isValid = false;
+                               skipTag(r, xTABLE);
+
+                       } else {
+                               isValid = false;
+                       }
+
+               } else if (tag == UL) {
+                       String typeName = getAttribute(r, 
getBeanTypePropertyName(eType), "array");
+                       ClassMeta cm = getClassMeta(typeName, pMeta, eType);
+                       if (cm != null)
+                               sType = eType = cm;
+
+                       if (sType.isObject())
+                               o = parseIntoCollection(r, new 
ObjectList(this), sType, pMeta);
+                       else if (sType.isCollection() || sType.isObject())
+                               o = parseIntoCollection(r, 
(Collection)(sType.canCreateNewInstance(outer)
+                                       ? sType.newInstance(outer) : new 
ObjectList(this)), sType, pMeta);
+                       else if (sType.isArray() || sType.isArgs())
+                               o = toArray(sType, parseIntoCollection(r, new 
ArrayList(), sType, pMeta));
+                       else
+                               isValid = false;
+                       skipTag(r, xUL);
+
+               }
+
+               if (! isValid)
+                       throw new XmlParseException(r.getLocation(), 
"Unexpected tag ''{0}'' for type ''{1}''", tag, eType);
+
+               if (transform != null && o != null)
+                       o = transform.unswap(this, o, eType);
+
+               if (outer != null)
+                       setParent(eType, o, outer);
+
+               skipWs(r);
+               return (T)o;
+       }
+
+       /*
+        * For parsing output from HtmlDocSerializer, this skips over the head, 
title, and links.
+        */
+       private static HtmlTag skipToData(XmlReader r) throws Exception {
+               while (true) {
+                       int event = r.next();
+                       if (event == START_ELEMENT && 
"div".equals(r.getLocalName()) && "data".equals(r.getAttributeValue(null, 
"id"))) {
+                               r.nextTag();
+                               event = r.getEventType();
+                               boolean isEmpty = (event == END_ELEMENT);
+                               // Skip until we find a start element, end 
document, or non-empty text.
+                               if (! isEmpty)
+                                       event = skipWs(r);
+                               if (event == END_DOCUMENT)
+                                       throw new 
XmlParseException(r.getLocation(), "Unexpected end of stream looking for 
data.");
+                               return (event == CHARACTERS ? null : 
HtmlTag.forString(r.getName().getLocalPart(), false));
+                       }
+               }
+       }
+
+       private static String getAttribute(XmlReader r, String name, String 
def) {
+               for (int i = 0; i < r.getAttributeCount(); i++)
+                       if (r.getAttributeLocalName(i).equals(name))
+                               return r.getAttributeValue(i);
+               return def;
+       }
+
+       /*
+        * Reads an anchor tag and converts it into a bean.
+        */
+       private <T> T parseAnchor(XmlReader r, ClassMeta<T> beanType)
+                       throws Exception {
+               String href = r.getAttributeValue(null, "href");
+               String name = getElementText(r);
+               Class<T> beanClass = beanType.getInnerClass();
+               if (beanClass.isAnnotationPresent(HtmlLink.class)) {
+                       HtmlLink h = beanClass.getAnnotation(HtmlLink.class);
+                       BeanMap<T> m = newBeanMap(beanClass);
+                       m.put(h.hrefProperty(), href);
+                       m.put(h.nameProperty(), name);
+                       return m.getBean();
+               }
+               return convertToType(href, beanType);
+       }
+
+       private static Map<String,String> getAttributes(XmlReader r) {
+               Map<String,String> m = new TreeMap<String,String>() ;
+               for (int i = 0; i < r.getAttributeCount(); i++)
+                       m.put(r.getAttributeLocalName(i), 
r.getAttributeValue(i));
+               return m;
+       }
+
+       /*
+        * Reads contents of <table> element.
+        * Precondition:  Must be pointing at <table> event.
+        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
+        */
+       private <K,V> Map<K,V> parseIntoMap(XmlReader r, Map<K,V> m, 
ClassMeta<K> keyType,
+                       ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws 
Exception {
+               while (true) {
+                       HtmlTag tag = nextTag(r, TR, xTABLE);
+                       if (tag == xTABLE)
+                               break;
+                       tag = nextTag(r, TD, TH);
+                       // Skip over the column headers.
+                       if (tag == TH) {
+                               skipTag(r);
+                               r.nextTag();
+                               skipTag(r);
+                       } else {
+                               K key = parseAnything(keyType, r, m, false, 
pMeta);
+                               nextTag(r, TD);
+                               V value = parseAnything(valueType, r, m, false, 
pMeta);
+                               setName(valueType, value, key);
+                               m.put(key, value);
+                       }
+                       nextTag(r, xTR);
+               }
+
+               return m;
+       }
+
+       /*
+        * Reads contents of <ul> element.
+        * Precondition:  Must be pointing at event following <ul> event.
+        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
+        */
+       private <E> Collection<E> parseIntoCollection(XmlReader r, 
Collection<E> l,
+                       ClassMeta<?> type, BeanPropertyMeta pMeta) throws 
Exception {
+               int argIndex = 0;
+               while (true) {
+                       HtmlTag tag = nextTag(r, LI, xUL);
+                       if (tag == xUL)
+                               break;
+                       ClassMeta<?> elementType = type.isArgs() ? 
type.getArg(argIndex++) : type.getElementType();
+                       l.add((E)parseAnything(elementType, r, l, false, 
pMeta));
+               }
+               return l;
+       }
+
+       /*
+        * Reads contents of <ul> element.
+        * Precondition:  Must be pointing at event following <ul> event.
+        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
+        */
+       private <E> Collection<E> parseTableIntoCollection(XmlReader r, 
Collection<E> l,
+                       ClassMeta<E> type, BeanPropertyMeta pMeta) throws 
Exception {
+
+               HtmlTag tag = nextTag(r, TR);
+               List<String> keys = new ArrayList<String>();
+               while (true) {
+                       tag = nextTag(r, TH, xTR);
+                       if (tag == xTR)
+                               break;
+                       keys.add(getElementText(r));
+               }
+
+               int argIndex = 0;
+
+               while (true) {
+                       r.nextTag();
+                       tag = HtmlTag.forEvent(r);
+                       if (tag == xTABLE)
+                               break;
+
+                       ClassMeta elementType = null;
+                       String beanType = getAttribute(r, 
getBeanTypePropertyName(type), null);
+                       if (beanType != null)
+                               elementType = getClassMeta(beanType, pMeta, 
null);
+                       if (elementType == null)
+                               elementType = type.isArgs() ? 
type.getArg(argIndex++) : type.getElementType();
+                       if (elementType == null)
+                               elementType = object();
+
+                       if (elementType.canCreateNewBean(l)) {
+                               BeanMap m = newBeanMap(l, 
elementType.getInnerClass());
+                               for (int i = 0; i < keys.size(); i++) {
+                                       tag = nextTag(r, TD, NULL);
+                                       if (tag == NULL) {
+                                               m = null;
+                                               nextTag(r, xNULL);
+                                               break;
+                                       }
+                                       String key = keys.get(i);
+                                       BeanMapEntry e = m.getProperty(key);
+                                       if (e == null) {
+                                               //onUnknownProperty(key, m, -1, 
-1);
+                                               parseAnything(object(), r, l, 
false, null);
+                                       } else {
+                                               BeanPropertyMeta bpm = 
e.getMeta();
+                                               ClassMeta<?> cm = 
bpm.getClassMeta();
+                                               Object value = 
parseAnything(cm, r, m.getBean(false), false, bpm);
+                                               setName(cm, value, key);
+                                               bpm.set(m, key, value);
+                                       }
+                               }
+                               l.add(m == null ? null : (E)m.getBean());
+                       } else {
+                               String c = 
getAttributes(r).get(getBeanTypePropertyName(type.getElementType()));
+                               Map m = (Map)(elementType.isMap() && 
elementType.canCreateNewInstance(l) ? elementType.newInstance(l)
+                                       : new ObjectMap(this));
+                               for (int i = 0; i < keys.size(); i++) {
+                                       tag = nextTag(r, TD, NULL);
+                                       if (tag == NULL) {
+                                               m = null;
+                                               nextTag(r, xNULL);
+                                               break;
+                                       }
+                                       String key = keys.get(i);
+                                       if (m != null) {
+                                               ClassMeta<?> kt = 
elementType.getKeyType(), vt = elementType.getValueType();
+                                               Object value = 
parseAnything(vt, r, l, false, pMeta);
+                                               setName(vt, value, key);
+                                               m.put(convertToType(key, kt), 
value);
+                                       }
+                               }
+                               if (m != null && c != null) {
+                                       ObjectMap m2 = (m instanceof ObjectMap 
? (ObjectMap)m : new ObjectMap(m).setBeanSession(this));
+                                       
m2.put(getBeanTypePropertyName(type.getElementType()), c);
+                                       l.add((E)cast(m2, pMeta, elementType));
+                               } else {
+                                       l.add((E)m);
+                               }
+                       }
+                       nextTag(r, xTR);
+               }
+               return l;
+       }
+
+       /*
+        * Reads contents of <table> element.
+        * Precondition:  Must be pointing at event following <table> event.
+        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
+        */
+       private <T> BeanMap<T> parseIntoBean(XmlReader r, BeanMap<T> m) throws 
Exception {
+               while (true) {
+                       HtmlTag tag = nextTag(r, TR, xTABLE);
+                       if (tag == xTABLE)
+                               break;
+                       tag = nextTag(r, TD, TH);
+                       // Skip over the column headers.
+                       if (tag == TH) {
+                               skipTag(r);
+                               r.nextTag();
+                               skipTag(r);
+                       } else {
+                               String key = getElementText(r);
+                               nextTag(r, TD);
+                               BeanPropertyMeta pMeta = m.getPropertyMeta(key);
+                               if (pMeta == null) {
+                                       onUnknownProperty(r.getPipe(), key, m, 
-1, -1);
+                                       parseAnything(object(), r, null, false, 
null);
+                               } else {
+                                       ClassMeta<?> cm = pMeta.getClassMeta();
+                                       Object value = parseAnything(cm, r, 
m.getBean(false), false, pMeta);
+                                       setName(cm, value, key);
+                                       pMeta.set(m, key, value);
+                               }
+                       }
+                       nextTag(r, xTR);
+               }
+               return m;
+       }
+
+       /*
+        * Reads the next tag.  Advances past anything that's not a start or 
end tag.  Throws an exception if
+        *      it's not one of the expected tags.
+        * Precondition:  Must be pointing before the event we want to parse.
+        * Postcondition:  Pointing at the tag just parsed.
+        */
+       private static HtmlTag nextTag(XmlReader r, HtmlTag...expected) throws 
Exception {
+               int et = r.next();
+
+               while (et != START_ELEMENT && et != END_ELEMENT && et != 
END_DOCUMENT)
+                       et = r.next();
+
+               if (et == END_DOCUMENT)
+                       throw new XmlParseException(r.getLocation(), 
"Unexpected end of document.");
+
+               HtmlTag tag = HtmlTag.forEvent(r);
+               if (expected.length == 0)
+                       return tag;
+               for (HtmlTag t : expected)
+                       if (t == tag)
+                               return tag;
+
+               throw new XmlParseException(r.getLocation(), "Unexpected tag: 
''{0}''.  Expected one of the following: {1}", tag, expected);
+       }
+
+       /*
+        * Skips over the current element and advances to the next element.
+        * <p>
+        * Precondition:  Pointing to opening tag.
+        * Postcondition:  Pointing to next opening tag.
+        *
+        * @param r The stream being read from.
+        * @throws XMLStreamException
+        */
+       private static void skipTag(XmlReader r) throws Exception {
+               int et = r.getEventType();
+
+               if (et != START_ELEMENT)
+                       throw new XmlParseException(
+                               r.getLocation(),
+                               "skipToNextTag() call on invalid event ''{0}''. 
 Must only be called on START_ELEMENT events.",
+                               XmlUtils.toReadableEvent(r)
+                       );
+
+               String n = r.getLocalName();
+
+               int depth = 0;
+               while (true) {
+                       et = r.next();
+                       if (et == START_ELEMENT) {
+                               String n2 = r.getLocalName();
+                                       if (n.equals(n2))
+                               depth++;
+                       } else if (et == END_ELEMENT) {
+                               String n2 = r.getLocalName();
+                               if (n.equals(n2))
+                                       depth--;
+                               if (depth < 0)
+                                       return;
+                       }
+               }
+       }
+
+       private static void skipTag(XmlReader r, HtmlTag...expected) throws 
Exception {
+               HtmlTag tag = HtmlTag.forEvent(r);
+               if (tag.isOneOf(expected))
+                       r.next();
+               else
+                       throw new XmlParseException(
+                               r.getLocation(),
+                               "Unexpected tag: ''{0}''.  Expected one of the 
following: {1}",
+                               tag, expected);
+       }
+
+       private static int skipWs(XmlReader r)  throws XMLStreamException {
+               int event = r.getEventType();
+               while (event != START_ELEMENT && event != END_ELEMENT && event 
!= END_DOCUMENT && r.isWhiteSpace())
+                       event = r.next();
+               return event;
        }
 
        /**
@@ -85,7 +583,7 @@ public final class HtmlParserSession extends 
XmlParserSession {
         * @throws XMLStreamException
         */
        @Override /* XmlParserSession */
-       public String parseText(XMLStreamReader r) throws Exception {
+       protected final String parseText(XmlReader r) throws Exception {
 
                StringBuilder sb = getStringBuilder();
 
@@ -165,7 +663,7 @@ public final class HtmlParserSession extends 
XmlParserSession {
        }
 
        /**
-        * Identical to {@link #parseText(XMLStreamReader)} except assumes the 
current event is the opening tag.
+        * Identical to {@link #parseText(XmlReader)} except assumes the 
current event is the opening tag.
         *
         * <p>
         * Precondition:  Pointing to opening tag.
@@ -176,19 +674,19 @@ public final class HtmlParserSession extends 
XmlParserSession {
         * @throws XMLStreamException
         */
        @Override /* XmlParserSession */
-       public String getElementText(XMLStreamReader r) throws Exception {
+       protected final String getElementText(XmlReader r) throws Exception {
                r.next();
                return parseText(r);
        }
 
        @Override /* XmlParserSession */
-       public boolean isWhitespaceElement(XMLStreamReader r) {
+       protected final boolean isWhitespaceElement(XmlReader r) {
                String s = r.getLocalName();
                return whitespaceElements.contains(s);
        }
 
        @Override /* XmlParserSession */
-       public String parseWhitespaceElement(XMLStreamReader r) throws 
Exception {
+       protected final String parseWhitespaceElement(XmlReader r) throws 
Exception {
 
                HtmlTag tag = HtmlTag.forEvent(r);
                int et = r.next();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
index 5d95e3f..ca452f6 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializer.java
@@ -12,17 +12,11 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.html;
 
-import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.serializer.SerializerContext.*;
 
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
 
 /**
  * Serializes POJO metamodels to HTML.
@@ -57,108 +51,12 @@ public final class HtmlSchemaDocSerializer extends 
HtmlDocSerializer {
         * @param propertyStore The property store to use for creating the 
context for this serializer.
         */
        public HtmlSchemaDocSerializer(PropertyStore propertyStore) {
-               super(propertyStore);
+               super(propertyStore.copy().append(SERIALIZER_detectRecursions, 
true).append(SERIALIZER_ignoreRecursions, true));
                this.ctx = createContext(HtmlDocSerializerContext.class);
        }
 
-       /**
-        * Constructor.
-        *
-        * @param propertyStore The property store to use for creating the 
context for this serializer.
-        * @param overrideProperties
-        */
-       public HtmlSchemaDocSerializer(PropertyStore propertyStore, 
Map<String,Object> overrideProperties) {
-               super(propertyStore);
-               this.ctx = 
this.propertyStore.create(overrideProperties).getContext(HtmlDocSerializerContext.class);
-       }
-
-       @Override /* CoreObject */
-       protected ObjectMap getOverrideProperties() {
-               return 
super.getOverrideProperties().append(SERIALIZER_detectRecursions, 
true).append(SERIALIZER_ignoreRecursions, true);
-       }
-
        @Override /* Serializer */
-       public HtmlDocSerializerSession createSession(ObjectMap op, Method 
javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext 
uriContext) {
-               return new HtmlDocSerializerSession(ctx, op, javaMethod, 
locale, timeZone, mediaType, uriContext);
-       }
-
-       @Override /* ISchemaSerializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               HtmlSerializerSession s = (HtmlSerializerSession)session;
-               ObjectMap schema = getSchema(s, 
session.getClassMetaForObject(o), "root", null);
-               super.doSerialize(s, out, schema);
-       }
-
-       /*
-        * Creates a schema representation of the specified class type.
-        *
-        * @param eType The class type to get the schema of.
-        * @param ctx Serialize context used to prevent infinite loops.
-        * @param attrName The name of the current attribute.
-        * @return A schema representation of the specified class.
-        * @throws SerializeException If a problem occurred trying to convert 
the output.
-        */
-       @SuppressWarnings({ "unchecked", "rawtypes" })
-       private ObjectMap getSchema(HtmlSerializerSession session, ClassMeta<?> 
eType, String attrName, String[] pNames) throws Exception {
-
-               ObjectMap out = new ObjectMap();
-
-               ClassMeta<?> aType;                     // The actual type 
(will be null if recursion occurs)
-               ClassMeta<?> sType;                     // The serialized type
-
-               aType = session.push(attrName, eType, null);
-
-               sType = eType.getSerializedClassMeta();
-               String type = null;
-
-               if (sType.isEnum() || sType.isCharSequence() || sType.isChar())
-                       type = "string";
-               else if (sType.isNumber())
-                       type = "number";
-               else if (sType.isBoolean())
-                       type = "boolean";
-               else if (sType.isMapOrBean())
-                       type = "object";
-               else if (sType.isCollectionOrArray())
-                       type = "array";
-               else
-                       type = "any";
-
-               out.put("type", type);
-               out.put("class", eType.toString());
-               PojoSwap t = eType.getPojoSwap();
-               if (t != null)
-                       out.put("transform", t);
-
-               if (aType != null) {
-                       if (sType.isEnum())
-                               out.put("enum", 
getEnumStrings((Class<Enum<?>>)sType.getInnerClass()));
-                       else if (sType.isCollectionOrArray()) {
-                               ClassMeta componentType = 
sType.getElementType();
-                               if (sType.isCollection() && 
isParentClass(Set.class, sType.getInnerClass()))
-                                       out.put("uniqueItems", true);
-                               out.put("items", getSchema(session, 
componentType, "items", pNames));
-                       } else if (sType.isBean()) {
-                               ObjectMap properties = new ObjectMap();
-                               BeanMeta bm = 
session.getBeanMeta(sType.getInnerClass());
-                               if (pNames != null)
-                                       bm = new BeanMetaFiltered(bm, pNames);
-                               for (Iterator<BeanPropertyMeta> i = 
bm.getPropertyMetas().iterator(); i.hasNext();) {
-                                       BeanPropertyMeta p = i.next();
-                                       properties.put(p.getName(), 
getSchema(session, p.getClassMeta(), p.getName(), p.getProperties()));
-                               }
-                               out.put("properties", properties);
-                       }
-               }
-               session.pop();
-               return out;
-       }
-
-       @SuppressWarnings({ "unchecked", "rawtypes" })
-       private static List<String> getEnumStrings(Class<? extends Enum> c) {
-               List<String> l = new LinkedList<String>();
-               for (Object e : EnumSet.allOf(c))
-                       l.add(e.toString());
-               return l;
+       public HtmlDocSerializerSession createSession(SerializerSessionArgs 
args) {
+               return new HtmlDocSerializerSession(ctx, args);
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
new file mode 100644
index 0000000..27f020a
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
@@ -0,0 +1,124 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.html;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.util.*;
+import org.apache.juneau.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
+
+/**
+ * Context object that lives for the duration of a single serialization of 
{@link HtmlSchemaDocSerializer} and its subclasses.
+ *
+ * <p>
+ * See {@link SerializerContext} for details.
+ *
+ * <p>
+ * This class is NOT thread safe.  It is meant to be discarded after one-time 
use.
+ */
+public class HtmlSchemaDocSerializerSession extends HtmlDocSerializerSession {
+
+       /**
+        * Create a new session using properties specified in the context.
+        *
+        * @param ctx
+        *      The context creating this session object.
+        *      The context contains all the configuration settings for this 
object.
+        * @param args
+        *      Runtime arguments.
+        */
+       protected HtmlSchemaDocSerializerSession(HtmlDocSerializerContext ctx, 
SerializerSessionArgs args) {
+               super(ctx, args);
+       }
+
+       @Override /* SerializerSession */
+       protected void doSerialize(SerializerPipe out, Object o) throws 
Exception {
+               ObjectMap schema = getSchema(getClassMetaForObject(o), "root", 
null);
+               super.doSerialize(out, schema);
+       }
+
+       /*
+        * Creates a schema representation of the specified class type.
+        *
+        * @param eType The class type to get the schema of.
+        * @param ctx Serialize context used to prevent infinite loops.
+        * @param attrName The name of the current attribute.
+        * @return A schema representation of the specified class.
+        * @throws SerializeException If a problem occurred trying to convert 
the output.
+        */
+       @SuppressWarnings({ "unchecked", "rawtypes" })
+       private ObjectMap getSchema(ClassMeta<?> eType, String attrName, 
String[] pNames) throws Exception {
+
+               ObjectMap out = new ObjectMap();
+
+               ClassMeta<?> aType;                     // The actual type 
(will be null if recursion occurs)
+               ClassMeta<?> sType;                     // The serialized type
+
+               aType = push(attrName, eType, null);
+
+               sType = eType.getSerializedClassMeta();
+               String type = null;
+
+               if (sType.isEnum() || sType.isCharSequence() || sType.isChar())
+                       type = "string";
+               else if (sType.isNumber())
+                       type = "number";
+               else if (sType.isBoolean())
+                       type = "boolean";
+               else if (sType.isMapOrBean())
+                       type = "object";
+               else if (sType.isCollectionOrArray())
+                       type = "array";
+               else
+                       type = "any";
+
+               out.put("type", type);
+               out.put("class", eType.toString());
+               PojoSwap t = eType.getPojoSwap();
+               if (t != null)
+                       out.put("transform", t);
+
+               if (aType != null) {
+                       if (sType.isEnum())
+                               out.put("enum", 
getEnumStrings((Class<Enum<?>>)sType.getInnerClass()));
+                       else if (sType.isCollectionOrArray()) {
+                               ClassMeta componentType = 
sType.getElementType();
+                               if (sType.isCollection() && 
isParentClass(Set.class, sType.getInnerClass()))
+                                       out.put("uniqueItems", true);
+                               out.put("items", getSchema(componentType, 
"items", pNames));
+                       } else if (sType.isBean()) {
+                               ObjectMap properties = new ObjectMap();
+                               BeanMeta bm = 
getBeanMeta(sType.getInnerClass());
+                               if (pNames != null)
+                                       bm = new BeanMetaFiltered(bm, pNames);
+                               for (Iterator<BeanPropertyMeta> i = 
bm.getPropertyMetas().iterator(); i.hasNext();) {
+                                       BeanPropertyMeta p = i.next();
+                                       properties.put(p.getName(), 
getSchema(p.getClassMeta(), p.getName(), p.getProperties()));
+                               }
+                               out.put("properties", properties);
+                       }
+               }
+               pop();
+               return out;
+       }
+
+       @SuppressWarnings({ "unchecked", "rawtypes" })
+       private static List<String> getEnumStrings(Class<? extends Enum> c) {
+               List<String> l = new LinkedList<String>();
+               for (Object e : EnumSet.allOf(c))
+                       l.add(e.toString());
+               return l;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
index 47ba3e8..aa8b6d0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
@@ -12,21 +12,14 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.html;
 
-import static org.apache.juneau.html.HtmlSerializer.ContentResult.*;
 import static org.apache.juneau.serializer.SerializerContext.*;
 
-import java.io.*;
-import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
 import org.apache.juneau.xml.*;
-import org.apache.juneau.xml.annotation.*;
 
 /**
  * Serializes POJO models to HTML.
@@ -163,13 +156,7 @@ public class HtmlSerializer extends XmlSerializer {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public Sq(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(SERIALIZER_quoteChar, '\'');
+                       super(propertyStore.copy().append(SERIALIZER_quoteChar, 
'\''));
                }
        }
 
@@ -182,12 +169,7 @@ public class HtmlSerializer extends XmlSerializer {
                 * @param propertyStore The property store containing all the 
settings for this object.
                 */
                public SqReadable(PropertyStore propertyStore) {
-                       super(propertyStore);
-               }
-
-               @Override /* CoreObject */
-               protected ObjectMap getOverrideProperties() {
-                       return 
super.getOverrideProperties().append(SERIALIZER_quoteChar, 
'\'').append(SERIALIZER_useWhitespace, true);
+                       super(propertyStore.copy().append(SERIALIZER_quoteChar, 
'\'').append(SERIALIZER_useWhitespace, true));
                }
        }
 
@@ -210,601 +192,15 @@ public class HtmlSerializer extends XmlSerializer {
                return new HtmlSerializerBuilder(propertyStore);
        }
 
-       /**
-        * Main serialization routine.
-        *
-        * @param session The serialization context object.
-        * @param o The object being serialized.
-        * @param w The writer to serialize to.
-        * @return The same writer passed in.
-        * @throws IOException If a problem occurred trying to send output to 
the writer.
-        */
-       private HtmlWriter doSerialize(HtmlSerializerSession session, Object o, 
HtmlWriter w) throws Exception {
-               serializeAnything(session, w, o, 
session.getExpectedRootType(o), null, session.getInitialDepth()-1, null, true);
-               return w;
-       }
-
-       /**
-        * Serialize the specified object to the specified writer.
-        *
-        * @param session The context object that lives for the duration of 
this serialization.
-        * @param out The writer.
-        * @param o The object to serialize.
-        * @param eType The expected type of the object if this is a bean 
property.
-        * @param name
-        *      The attribute name of this object if this object was a field in 
a JSON object (i.e. key of a
-        *      {@link java.util.Map.Entry} or property name of a bean).
-        * @param indent The current indentation value.
-        * @param pMeta The bean property being serialized, or <jk>null</jk> if 
we're not serializing a bean property.
-        * @param isRoot <jk>true</jk> if this is the root element of the 
document.
-        * @return The type of content encountered.  Either simple (no 
whitespace) or normal (elements with whitespace).
-        * @throws Exception If a problem occurred trying to convert the output.
-        */
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       protected ContentResult serializeAnything(HtmlSerializerSession 
session, HtmlWriter out, Object o,
-                       ClassMeta<?> eType, String name, int indent, 
BeanPropertyMeta pMeta, boolean isRoot) throws Exception {
-
-               ClassMeta<?> aType = null;       // The actual type
-               ClassMeta<?> wType = null;     // The wrapped type (delegate)
-               ClassMeta<?> sType = object();   // The serialized type
-
-               if (eType == null)
-                       eType = object();
-
-               aType = session.push(name, o, eType);
-
-               // Handle recursion
-               if (aType == null) {
-                       o = null;
-                       aType = object();
-               }
-
-               session.indent += indent;
-
-               ContentResult cr = CR_NORMAL;
-
-               // Determine the type.
-               if (o == null || (aType.isChar() && ((Character)o).charValue() 
== 0)) {
-                       out.tag("null");
-                       cr = ContentResult.CR_SIMPLE;
-
-               } else {
-
-                       if (aType.isDelegate()) {
-                               wType = aType;
-                               aType = ((Delegate)o).getClassMeta();
-                       }
-
-                       sType = aType.getSerializedClassMeta();
-                       String typeName = null;
-                       if (session.isAddBeanTypeProperties() && ! 
eType.equals(aType))
-                               typeName = aType.getDictionaryName();
-
-                       // Swap if necessary
-                       PojoSwap swap = aType.getPojoSwap();
-                       if (swap != null) {
-                               o = swap.swap(session, o);
-
-                               // If the getSwapClass() method returns Object, 
we need to figure out
-                               // the actual type now.
-                               if (sType.isObject())
-                                       sType = 
session.getClassMetaForObject(o);
-                       }
-
-                       HtmlClassMeta html = 
sType.getExtendedMeta(HtmlClassMeta.class);
-                       HtmlRender render = (pMeta == null ? null : 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getRender());
-                       if (render == null)
-                               render = html.getRender();
-
-                       if (render != null) {
-                               Object o2 = render.getContent(session, o);
-                               if (o2 != o) {
-                                       session.indent -= indent;
-                                       session.pop();
-                                       out.nl(session.indent);
-                                       return serializeAnything(session, out, 
o2, null, typeName, indent, null, false);
-                               }
-                       }
-
-                       if (html.isAsXml() || (pMeta != null && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isAsXml())) {
-                               super.serializeAnything(session, out, o, null, 
null, null, false, XmlFormat.MIXED, false, false, null);
-
-                       } else if (html.isAsPlainText() || (pMeta != null && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isAsPlainText())) {
-                               out.write(o == null ? "null" : o.toString());
-                               cr = CR_SIMPLE;
-
-                       } else if (o == null || (sType.isChar() && 
((Character)o).charValue() == 0)) {
-                               out.tag("null");
-                               cr = CR_SIMPLE;
-
-                       } else if (sType.isNumber()) {
-                               if (eType.isNumber() && ! isRoot)
-                                       out.append(o);
-                               else
-                                       
out.sTag("number").append(o).eTag("number");
-                               cr = CR_SIMPLE;
-
-                       } else if (sType.isBoolean()) {
-                               if (eType.isBoolean() && ! isRoot)
-                                       out.append(o);
-                               else
-                                       
out.sTag("boolean").append(o).eTag("boolean");
-                               cr = CR_SIMPLE;
-
-                       } else if (sType.isMap() || (wType != null && 
wType.isMap())) {
-                               out.nlIf(! isRoot, indent+1);
-                               if (o instanceof BeanMap)
-                                       serializeBeanMap(session, out, 
(BeanMap)o, eType, pMeta);
-                               else
-                                       serializeMap(session, out, (Map)o, 
sType, eType.getKeyType(), eType.getValueType(), typeName, pMeta);
-
-                       } else if (sType.isBean()) {
-                               BeanMap m = session.toBeanMap(o);
-                               Class<?> c = o.getClass();
-                               if (c.isAnnotationPresent(HtmlLink.class)) {
-                                       HtmlLink h = 
o.getClass().getAnnotation(HtmlLink.class);
-                                       Object urlProp = 
m.get(h.hrefProperty());
-                                       Object nameProp = 
m.get(h.nameProperty());
-                                       out.oTag("a").attrUri("href", 
urlProp).append('>').text(nameProp).eTag("a");
-                                       cr = CR_SIMPLE;
-                               } else {
-                                       out.nlIf(! isRoot, indent+2);
-                                       serializeBeanMap(session, out, m, 
eType, pMeta);
-                               }
-
-                       } else if (sType.isCollection() || sType.isArray() || 
(wType != null && wType.isCollection())) {
-                               out.nlIf(! isRoot, indent+1);
-                               serializeCollection(session, out, o, sType, 
eType, name, pMeta);
-
-                       } else if (session.isUri(sType, pMeta, o)) {
-                               String label = session.getAnchorText(pMeta, o);
-                               out.oTag("a").attrUri("href", o).append('>');
-                               out.text(label);
-                               out.eTag("a");
-                               cr = CR_SIMPLE;
-
-                       } else {
-                               if (isRoot)
-                                       
out.sTag("string").text(session.toString(o)).eTag("string");
-                               else
-                                       out.text(session.toString(o));
-                               cr = CR_SIMPLE;
-                       }
-               }
-               session.pop();
-               session.indent -= indent;
-               return cr;
-       }
-
-       /**
-        * Identifies what the contents were of a serialized bean.
-        */
-       static enum ContentResult {
-               CR_SIMPLE,    // Simple content.  Shouldn't use whitespace.
-               CR_NORMAL     // Normal content.  Use whitespace.
-       }
-
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       private void serializeMap(HtmlSerializerSession session, HtmlWriter 
out, Map m, ClassMeta<?> sType,
-                       ClassMeta<?> eKeyType, ClassMeta<?> eValueType, String 
typeName, BeanPropertyMeta ppMeta) throws Exception {
-
-               ClassMeta<?> keyType = eKeyType == null ? session.string() : 
eKeyType;
-               ClassMeta<?> valueType = eValueType == null ? session.object() 
: eValueType;
-               ClassMeta<?> aType = session.getClassMetaForObject(m);       // 
The actual type
-
-               int i = session.getIndent();
-
-               out.oTag(i, "table");
-
-               if (typeName != null && ppMeta != null && ppMeta.getClassMeta() 
!= aType)
-                       out.attr(session.getBeanTypePropertyName(sType), 
typeName);
-
-               out.append(">").nl(i+1);
-               if (session.isAddKeyValueTableHeaders() && ! 
(aType.getExtendedMeta(HtmlClassMeta.class).isNoTableHeaders()
-                               || (ppMeta != null && 
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isNoTableHeaders()))) {
-                       out.sTag(i+1, "tr").nl(i+2);
-                       out.sTag(i+2, "th").append("key").eTag("th").nl(i+3);
-                       out.sTag(i+2, "th").append("value").eTag("th").nl(i+3);
-                       out.ie(i+1).eTag("tr").nl(i+2);
-               }
-               for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
-
-                       Object key = session.generalize(e.getKey(), keyType);
-                       Object value = null;
-                       try {
-                               value = e.getValue();
-                       } catch (StackOverflowError t) {
-                               throw t;
-                       } catch (Throwable t) {
-                               session.onError(t, "Could not call getValue() 
on property ''{0}'', {1}", e.getKey(), t.getLocalizedMessage());
-                       }
-
-                       String link = getLink(ppMeta);
-                       String style = getStyle(session, ppMeta, value);
-
-                       out.sTag(i+1, "tr").nl(i+2);
-                       out.oTag(i+2, "td");
-                       if (style != null)
-                               out.attr("style", style);
-                       out.cTag();
-                       if (link != null)
-                               out.oTag(i+3, "a").attrUri("href", 
link.replace("{#}", StringUtils.toString(value))).cTag();
-                       ContentResult cr = serializeAnything(session, out, key, 
keyType, null, 2, null, false);
-                       if (link != null)
-                               out.eTag("a");
-                       if (cr == CR_NORMAL)
-                               out.i(i+2);
-                       out.eTag("td").nl(i+2);
-                       out.sTag(i+2, "td");
-                       cr = serializeAnything(session, out, value, valueType, 
(key == null ? "_x0000_" : session.toString(key)), 2, null, false);
-                       if (cr == CR_NORMAL)
-                               out.ie(i+2);
-                       out.eTag("td").nl(i+2);
-                       out.ie(i+1).eTag("tr").nl(i+1);
-               }
-               out.ie(i).eTag("table").nl(i);
-       }
-
-       private void serializeBeanMap(HtmlSerializerSession session, HtmlWriter 
out, BeanMap<?> m, ClassMeta<?> eType,
-                       BeanPropertyMeta ppMeta) throws Exception {
-               int i = session.getIndent();
-
-               out.oTag(i, "table");
-
-               String typeName = m.getMeta().getDictionaryName();
-               if (typeName != null && eType != m.getClassMeta())
-                       
out.attr(session.getBeanTypePropertyName(m.getClassMeta()), typeName);
-
-               out.append('>').nl(i);
-               if (session.isAddKeyValueTableHeaders() && ! 
(m.getClassMeta().getExtendedMeta(HtmlClassMeta.class).isNoTableHeaders()
-                               || (ppMeta != null && 
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isNoTableHeaders()))) {
-                       out.sTag(i+1, "tr").nl(i+1);
-                       out.sTag(i+2, "th").append("key").eTag("th").nl(i+2);
-                       out.sTag(i+2, "th").append("value").eTag("th").nl(i+2);
-                       out.ie(i+1).eTag("tr").nl(i+1);
-               }
-
-               for (BeanPropertyValue p : m.getValues(session.isTrimNulls())) {
-                       BeanPropertyMeta pMeta = p.getMeta();
-                       ClassMeta<?> cMeta = p.getClassMeta();
-
-                       String key = p.getName();
-                       Object value = p.getValue();
-                       Throwable t = p.getThrown();
-                       if (t != null)
-                               session.onBeanGetterException(pMeta, t);
-
-                       if (session.canIgnoreValue(cMeta, key, value))
-                               continue;
-
-                       String link = cMeta.isCollectionOrArray() ? null : 
getLink(pMeta);
-
-                       out.sTag(i+1, "tr").nl(i+1);
-                       out.sTag(i+2, "td").text(key).eTag("td").nl(i+2);
-                       out.oTag(i+2, "td");
-                       String style = getStyle(session, pMeta, value);
-                       if (style != null)
-                               out.attr("style", style);
-                       out.cTag();
-
-                       try {
-                               if (link != null)
-                                       out.oTag(i+3, "a").attrUri("href", 
m.resolveVars(link)).cTag();
-                               ContentResult cr = serializeAnything(session, 
out, value, cMeta, key, 2, pMeta, false);
-                               if (cr == CR_NORMAL)
-                                       out.i(i+2);
-                               if (link != null)
-                                       out.eTag("a");
-                       } catch (SerializeException e) {
-                               throw e;
-                       } catch (Error e) {
-                               throw e;
-                       } catch (Throwable e) {
-                               e.printStackTrace();
-                               session.onBeanGetterException(pMeta, e);
-                       }
-                       out.eTag("td").nl(i+2);
-                       out.ie(i+1).eTag("tr").nl(i+1);
-               }
-               out.ie(i).eTag("table").nl(i);
-       }
-
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       private void serializeCollection(HtmlSerializerSession session, 
HtmlWriter out, Object in, ClassMeta<?> sType,
-                       ClassMeta<?> eType, String name, BeanPropertyMeta 
ppMeta) throws Exception {
-
-               ClassMeta<?> seType = sType.getElementType();
-               if (seType == null)
-                       seType = session.object();
-
-               Collection c = (sType.isCollection() ? (Collection)in : 
toList(sType.getInnerClass(), in));
-
-               int i = session.getIndent();
-               if (c.isEmpty()) {
-                       out.appendln(i, "<ul></ul>");
-                       return;
-               }
-
-               String type2 = null;
-               if (sType != eType)
-                       type2 = sType.getDictionaryName();
-               if (type2 == null)
-                       type2 = "array";
-
-               c = session.sort(c);
-
-               HtmlBeanPropertyMeta hbpMeta = (ppMeta == null ? null : 
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class));
-               String btpn = session.getBeanTypePropertyName(eType);
-
-               // Look at the objects to see how we're going to handle them.  
Check the first object to see how we're going to
-               // handle this.
-               // If it's a map or bean, then we'll create a table.
-               // Otherwise, we'll create a list.
-               Object[] th = getTableHeaders(session, c, hbpMeta);
-
-               if (th != null) {
-
-                       out.oTag(i, "table").attr(btpn, 
type2).append('>').nl(i+1);
-                       out.sTag(i+1, "tr").nl(i+2);
-                       for (Object key : th) {
-                               out.sTag(i+2, "th");
-                               out.text(session.convertToType(key, 
String.class));
-                               out.eTag("th").nl(i+2);
-                       }
-                       out.ie(i+1).eTag("tr").nl(i+1);
-
-                       for (Object o : c) {
-                               ClassMeta<?> cm = 
session.getClassMetaForObject(o);
-
-                               if (cm != null && cm.getPojoSwap() != null) {
-                                       PojoSwap f = cm.getPojoSwap();
-                                       o = f.swap(session, o);
-                                       cm = cm.getSerializedClassMeta();
-                               }
-
-                               out.oTag(i+1, "tr");
-                               String typeName = (cm == null ? null : 
cm.getDictionaryName());
-                               String typeProperty = 
session.getBeanTypePropertyName(cm);
-
-                               if (typeName != null && eType.getElementType() 
!= cm)
-                                       out.attr(typeProperty, typeName);
-                               out.cTag().nl(i+2);
-
-                               if (cm == null) {
-                                       serializeAnything(session, out, o, 
null, null, 1, null, false);
-
-                               } else if (cm.isMap() && ! (cm.isBeanMap())) {
-                                       Map m2 = session.sort((Map)o);
-
-                                       for (Object k : th) {
-                                               out.sTag(i+2, "td");
-                                               ContentResult cr = 
serializeAnything(session, out, m2.get(k), eType.getElementType(), 
session.toString(k), 2, null, false);
-                                               if (cr == CR_NORMAL)
-                                                       out.i(i+2);
-                                               out.eTag("td").nl(i+2);
-                                       }
-                               } else {
-                                       BeanMap m2 = null;
-                                       if (o instanceof BeanMap)
-                                               m2 = (BeanMap)o;
-                                       else
-                                               m2 = session.toBeanMap(o);
-
-                                       for (Object k : th) {
-                                               BeanMapEntry p = 
m2.getProperty(session.toString(k));
-                                               BeanPropertyMeta pMeta = 
p.getMeta();
-                                               String link = 
pMeta.getClassMeta().isCollectionOrArray() ? null : getLink(pMeta);
-                                               Object value = p.getValue();
-                                               String style = 
getStyle(session, pMeta, value);
-                                               out.oTag(i+2, "td");
-                                               if (style != null)
-                                                       out.attr("style", 
style);
-                                               out.cTag();
-                                               if (link != null)
-                                                       
out.oTag("a").attrUri("href", m2.resolveVars(link)).cTag();
-                                               ContentResult cr = 
serializeAnything(session, out, value, pMeta.getClassMeta(), 
p.getKey().toString(), 2, pMeta, false);
-                                               if (cr == CR_NORMAL)
-                                                       out.i(i+2);
-                                               if (link != null)
-                                                       out.eTag("a");
-                                               out.eTag("td").nl(i+2);
-                                       }
-                               }
-                               out.ie(i+1).eTag("tr").nl(i+1);
-                       }
-                       out.ie(i).eTag("table").nl(i);
-
-               } else {
-                       out.oTag(i, "ul");
-                       if (! type2.equals("array"))
-                               out.attr(btpn, type2);
-                       out.append('>').nl(i+1);
-                       for (Object o : c) {
-                               out.oTag(i+1, "li");
-                               String style = getStyle(session, ppMeta, o);
-                               String link = getLink(ppMeta);
-                               if (style != null)
-                                       out.attr("style", style);
-                               out.cTag();
-                               if (link != null)
-                                       out.oTag(i+2, "a").attrUri("href", 
link.replace("{#}", StringUtils.toString(o))).cTag();
-                               ContentResult cr = serializeAnything(session, 
out, o, eType.getElementType(), name, 1, null, false);
-                               if (link != null)
-                                       out.eTag("a");
-                               if (cr == CR_NORMAL)
-                                       out.ie(i+1);
-                               out.eTag("li").nl(i+1);
-                       }
-                       out.ie(i).eTag("ul").nl(i);
-               }
-       }
-
-       private static HtmlRender<?> getRender(HtmlSerializerSession session, 
BeanPropertyMeta pMeta, Object value) {
-               if (pMeta == null)
-                       return null;
-               HtmlBeanPropertyMeta hpMeta = 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);
-               HtmlRender<?> render = hpMeta.getRender();
-               if (render != null)
-                       return render;
-               ClassMeta<?> cMeta = session.getClassMetaForObject(value);
-               render = cMeta == null ? null : 
cMeta.getExtendedMeta(HtmlClassMeta.class).getRender();
-               return render;
-       }
-
-       @SuppressWarnings({"rawtypes","unchecked"})
-       private static String getStyle(HtmlSerializerSession session, 
BeanPropertyMeta pMeta, Object value) {
-               HtmlRender render = getRender(session, pMeta, value);
-               return render == null ? null : render.getStyle(session, value);
-       }
-
-       private static String getLink(BeanPropertyMeta pMeta) {
-               return pMeta == null ? null : 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getLink();
-       }
-
-       /*
-        * Returns the table column headers for the specified collection of 
objects.
-        * Returns null if collection should not be serialized as a 
2-dimensional table.
-        * 2-dimensional tables are used for collections of objects that all 
have the same set of property names.
-        */
-       @SuppressWarnings({ "rawtypes", "unchecked" })
-       private static Object[] getTableHeaders(SerializerSession session, 
Collection c, HtmlBeanPropertyMeta hbpMeta) throws Exception {
-               if (c.size() == 0)
-                       return null;
-               c = session.sort(c);
-               Object[] th;
-               Set<ClassMeta> prevC = new HashSet<ClassMeta>();
-               Object o1 = null;
-               for (Object o : c)
-                       if (o != null) {
-                               o1 = o;
-                               break;
-                       }
-               if (o1 == null)
-                       return null;
-               ClassMeta<?> cm = session.getClassMetaForObject(o1);
-               if (cm.getPojoSwap() != null) {
-                       PojoSwap f = cm.getPojoSwap();
-                       o1 = f.swap(session, o1);
-                       cm = cm.getSerializedClassMeta();
-               }
-               if (cm == null || ! cm.isMapOrBean())
-                       return null;
-               if (cm.getInnerClass().isAnnotationPresent(HtmlLink.class))
-                       return null;
-               HtmlClassMeta h = cm.getExtendedMeta(HtmlClassMeta.class);
-               if (h.isNoTables() || (hbpMeta != null && hbpMeta.isNoTables()))
-                       return null;
-               if (h.isNoTableHeaders() || (hbpMeta != null && 
hbpMeta.isNoTableHeaders()))
-                       return new Object[0];
-               if (session.canIgnoreValue(cm, null, o1))
-                       return null;
-               if (cm.isMap() && ! cm.isBeanMap()) {
-                       Set<Object> set = new LinkedHashSet<Object>();
-                       for (Object o : c) {
-                               if (! session.canIgnoreValue(cm, null, o)) {
-                                       if (! cm.isInstance(o))
-                                               return null;
-                                       Map m = session.sort((Map)o);
-                                       for (Map.Entry e : 
(Set<Map.Entry>)m.entrySet()) {
-                                               if (e.getValue() != null)
-                                                       set.add(e.getKey() == 
null ? null : e.getKey());
-                                       }
-                               }
-                       }
-                       th = set.toArray(new Object[set.size()]);
-               } else {
-                       Map<String,Boolean> m = new 
LinkedHashMap<String,Boolean>();
-                       for (Object o : c) {
-                               if (! session.canIgnoreValue(cm, null, o)) {
-                                       if (! cm.isInstance(o))
-                                               return null;
-                                       BeanMap<?> bm = (o instanceof BeanMap ? 
(BeanMap)o : session.toBeanMap(o));
-                                       for (Map.Entry<String,Object> e : 
bm.entrySet()) {
-                                               String key = e.getKey();
-                                               if (e.getValue() != null)
-                                                       m.put(key, true);
-                                               else if (! m.containsKey(key))
-                                                       m.put(key, false);
-                                       }
-                               }
-                       }
-                       for (Iterator<Boolean> i = m.values().iterator(); 
i.hasNext();)
-                               if (! i.next())
-                                       i.remove();
-                       th = m.keySet().toArray(new Object[m.size()]);
-               }
-               prevC.add(cm);
-               boolean isSortable = true;
-               for (Object o : th)
-                       isSortable &= (o instanceof Comparable);
-               Set<Object> s = (isSortable ? new TreeSet<Object>() : new 
LinkedHashSet<Object>());
-               s.addAll(Arrays.asList(th));
-
-               for (Object o : c) {
-                       if (o == null)
-                               continue;
-                       cm = session.getClassMetaForObject(o);
-                       if (cm != null && cm.getPojoSwap() != null) {
-                               PojoSwap f = cm.getPojoSwap();
-                               o = f.swap(session, o);
-                               cm = cm.getSerializedClassMeta();
-                       }
-                       if (prevC.contains(cm))
-                               continue;
-                       if (cm == null || ! (cm.isMap() || cm.isBean()))
-                               return null;
-                       if 
(cm.getInnerClass().isAnnotationPresent(HtmlLink.class))
-                               return null;
-                       if (session.canIgnoreValue(cm, null, o))
-                               return null;
-                       if (cm.isMap() && ! cm.isBeanMap()) {
-                               Map m = (Map)o;
-                               if (th.length != m.keySet().size())
-                                       return null;
-                               for (Object k : m.keySet())
-                                       if (! s.contains(k.toString()))
-                                               return null;
-                       } else {
-                               BeanMap<?> bm = (o instanceof BeanMap ? 
(BeanMap)o : session.toBeanMap(o));
-                               int l = 0;
-                               for (String k : bm.keySet()) {
-                                       if (! s.contains(k))
-                                               return null;
-                                       l++;
-                               }
-                               if (s.size() != l)
-                                       return null;
-                       }
-               }
-               return th;
-       }
-
-       /**
-        * Returns the schema serializer based on the settings of this 
serializer.
-        *
-        * @return The schema serializer.
-        */
        @Override /* XmlSerializer */
        public HtmlSerializer getSchemaSerializer() {
                if (schemaSerializer == null)
-                       schemaSerializer = new 
HtmlSchemaDocSerializer(propertyStore, getOverrideProperties());
+                       schemaSerializer = new 
HtmlSchemaDocSerializer(propertyStore);
                return schemaSerializer;
        }
 
-
-       
//--------------------------------------------------------------------------------
-       // Entry point methods
-       
//--------------------------------------------------------------------------------
-
-       @Override /* Serializer */
-       public HtmlSerializerSession createSession(ObjectMap op, Method 
javaMethod, Locale locale,
-                       TimeZone timeZone, MediaType mediaType, UriContext 
uriContext) {
-               return new HtmlSerializerSession(ctx, op, javaMethod, locale, 
timeZone, mediaType, uriContext);
-       }
-
        @Override /* Serializer */
-       protected void doSerialize(SerializerSession session, SerializerOutput 
out, Object o) throws Exception {
-               HtmlSerializerSession s = (HtmlSerializerSession)session;
-               doSerialize(s, o, s.getHtmlWriter(out));
+       public WriterSerializerSession createSession(SerializerSessionArgs 
args) {
+               return new HtmlSerializerSession(ctx, args);
        }
 }

Reply via email to