juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [03/12] incubator-juneau git commit: Allow serializer and parser sessions to be reused.
Date Fri, 28 Jul 2017 18:22:18 GMT
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index 6ceb906..9f872c0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -14,19 +14,15 @@ package org.apache.juneau.urlencoding;
 
 import static org.apache.juneau.serializer.SerializerContext.*;
 import static org.apache.juneau.uon.UonSerializerContext.*;
-import static org.apache.juneau.internal.ArrayUtils.*;
+import static org.apache.juneau.urlencoding.UrlEncodingContext.*;
 import static org.apache.juneau.internal.StringUtils.*;
 
 import java.io.*;
-import java.lang.reflect.*;
 import java.net.*;
-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.*;
 import org.apache.juneau.uon.*;
 
 /**
@@ -158,12 +154,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 		 * @param propertyStore The property store containing all the settings for this object.
 		 */
 		public Expanded(PropertyStore propertyStore) {
-			super(propertyStore);
-		}
-
-		@Override /* CoreObject */
-		protected ObjectMap getOverrideProperties() {
-			return super.getOverrideProperties().append(UrlEncodingContext.URLENC_expandedParams, true);
+			super(propertyStore.copy().append(URLENC_expandedParams, true));
 		}
 	}
 
@@ -178,12 +169,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 		 * @param propertyStore The property store containing all the settings for this object.
 		 */
 		public Readable(PropertyStore propertyStore) {
-			super(propertyStore);
-		}
-
-		@Override /* CoreObject */
-		protected ObjectMap getOverrideProperties() {
-			return super.getOverrideProperties().append(SERIALIZER_useWhitespace, true);
+			super(propertyStore.copy().append(SERIALIZER_useWhitespace, true));
 		}
 	}
 
@@ -198,12 +184,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 		 * @param propertyStore The property store containing all the settings for this object.
 		 */
 		public PlainText(PropertyStore propertyStore) {
-			super(propertyStore);
-		}
-
-		@Override /* CoreObject */
-		protected ObjectMap getOverrideProperties() {
-			return super.getOverrideProperties().append(UonSerializerContext.UON_paramFormat, "PLAINTEXT");
+			super(propertyStore.copy().append(UON_paramFormat, "PLAINTEXT"));
 		}
 	}
 
@@ -215,7 +196,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 	 * @param propertyStore The property store containing all the settings for this object.
 	 */
 	public UrlEncodingSerializer(PropertyStore propertyStore) {
-		super(propertyStore);
+		super(propertyStore.copy().append(UON_encodeChars, true));
 		this.ctx = createContext(UrlEncodingSerializerContext.class);
 	}
 
@@ -224,183 +205,6 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 		return new UrlEncodingSerializerBuilder(propertyStore);
 	}
 
-	@Override /* CoreObject */
-	protected ObjectMap getOverrideProperties() {
-		return super.getOverrideProperties().append(UON_encodeChars, true);
-	}
-
-	/**
-	 * Workhorse method. Determines the type of object, and then calls the appropriate type-specific serialization method.
-	 */
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	private SerializerWriter serializeAnything(UrlEncodingSerializerSession session, UonWriter out, Object o) throws Exception {
-
-		ClassMeta<?> aType;			// The actual type
-		ClassMeta<?> sType;			// The serialized type
-
-		aType = session.push("root", o, object());
-		session.indent--;
-		if (aType == null)
-			aType = object();
-
-		sType = aType.getSerializedClassMeta();
-		String typeName = session.getBeanTypeName(session.object(), aType, null);
-
-		// 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);
-		}
-
-		if (sType.isMap()) {
-			if (o instanceof BeanMap)
-				serializeBeanMap(session, out, (BeanMap)o, typeName);
-			else
-				serializeMap(session, out, (Map)o, sType);
-		} else if (sType.isBean()) {
-			serializeBeanMap(session, out, session.toBeanMap(o), typeName);
-		} else if (sType.isCollection() || sType.isArray()) {
-			Map m = sType.isCollection() ? getCollectionMap((Collection)o) : getCollectionMap(o);
-			serializeCollectionMap(session, out, m, session.getClassMeta(Map.class, Integer.class, Object.class));
-		} else {
-			// All other types can't be serialized as key/value pairs, so we create a
-			// mock key/value pair with a "_value" key.
-			out.append("_value=");
-			super.serializeAnything(session, out, o, null, null, null);
-		}
-
-		session.pop();
-		return out;
-	}
-
-	/**
-	 * Converts a Collection into an integer-indexed map.
-	 */
-	private static Map<Integer,Object> getCollectionMap(Collection<?> c) {
-		Map<Integer,Object> m = new TreeMap<Integer,Object>();
-		int i = 0;
-		for (Object o : c)
-			m.put(i++, o);
-		return m;
-	}
-
-	/**
-	 * Converts an array into an integer-indexed map.
-	 */
-	private static Map<Integer,Object> getCollectionMap(Object array) {
-		Map<Integer,Object> m = new TreeMap<Integer,Object>();
-		for (int i = 0; i < Array.getLength(array); i++)
-			m.put(i, Array.get(array, i));
-		return m;
-	}
-
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	private SerializerWriter serializeMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception {
-
-		m = session.sort(m);
-
-		ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
-
-		int depth = session.getIndent();
-		boolean addAmp = false;
-
-		for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
-			Object key = session.generalize(e.getKey(), keyType);
-			Object value = e.getValue();
-
-			if (session.shouldUseExpandedParams(value)) {
-				Iterator i = value instanceof Collection ? ((Collection)value).iterator() : iterator(value);
-				while (i.hasNext()) {
-					if (addAmp)
-						out.cr(depth).append('&');
-					out.appendObject(key, true).append('=');
-					super.serializeAnything(session, out, i.next(), null, (key == null ? null : key.toString()), null);
-					addAmp = true;
-				}
-			} else {
-				if (addAmp)
-					out.cr(depth).append('&');
-				out.appendObject(key, true).append('=');
-				super.serializeAnything(session, out, value, valueType, (key == null ? null : key.toString()), null);
-				addAmp = true;
-			}
-		}
-
-		return out;
-	}
-
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	private SerializerWriter serializeCollectionMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception {
-
-		ClassMeta<?> valueType = type.getValueType();
-
-		int depth = session.getIndent();
-		boolean addAmp = false;
-
-		for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
-			if (addAmp)
-				out.cr(depth).append('&');
-			out.append(e.getKey()).append('=');
-			super.serializeAnything(session, out, e.getValue(), valueType, null, null);
-			addAmp = true;
-		}
-
-		return out;
-	}
-
-	@SuppressWarnings({ "rawtypes" })
-	private SerializerWriter serializeBeanMap(UrlEncodingSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception {
-		int depth = session.getIndent();
-
-		boolean addAmp = false;
-
-		for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), typeName != null ? session.createBeanTypeNameProperty(m, typeName) : null)) {
-			BeanPropertyMeta pMeta = p.getMeta();
-			ClassMeta<?> cMeta = p.getClassMeta();
-
-			String key = p.getName();
-			Object value = p.getValue();
-			Throwable t = p.getThrown();
-			if (t != null)
-				session.onBeanGetterException(pMeta, t);
-
-			if (session.canIgnoreValue(cMeta, key, value))
-				continue;
-
-			if (value != null && session.shouldUseExpandedParams(pMeta)) {
-				// Transformed object array bean properties may be transformed resulting in ArrayLists,
-				// so we need to check type if we think it's an array.
-				Iterator i = (cMeta.isCollection() || value instanceof Collection) ? ((Collection)value).iterator() : iterator(value);
-				while (i.hasNext()) {
-					if (addAmp)
-						out.cr(depth).append('&');
-
-					out.appendObject(key, true).append('=');
-
-					super.serializeAnything(session, out, i.next(), cMeta.getElementType(), key, pMeta);
-
-					addAmp = true;
-				}
-			} else {
-				if (addAmp)
-					out.cr(depth).append('&');
-
-				out.appendObject(key, true).append('=');
-
-				super.serializeAnything(session, out, value, cMeta, key, pMeta);
-
-				addAmp = true;
-			}
-
-		}
-		return out;
-	}
-
 
 	//--------------------------------------------------------------------------------
 	// Methods for constructing individual parameter values.
@@ -438,9 +242,8 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 			}
 
 			StringWriter w = new StringWriter();
-			SerializerOutput out = new SerializerOutput(w);
-			UonSerializerSession s = new UrlEncodingSerializerSession(ctx, urlEncode, null, null, null, null, MediaType.UON, null);
-			super.doSerialize(s, out, o);
+			UonSerializerSession s = new UonSerializerSession(ctx, urlEncode, SerializerSessionArgs.DEFAULT);
+			s.serialize(w, o);
 			return w.toString();
 		} catch (Exception e) {
 			throw new RuntimeException(e);
@@ -453,15 +256,8 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 	//--------------------------------------------------------------------------------
 
 	@Override /* Serializer */
-	public UrlEncodingSerializerSession createSession(ObjectMap op, Method javaMethod, Locale locale,
-			TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
-		return new UrlEncodingSerializerSession(ctx, null, op, javaMethod, locale, timeZone, mediaType, uriContext);
-	}
-
-	@Override /* Serializer */
-	protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception {
-		UrlEncodingSerializerSession s = (UrlEncodingSerializerSession)session;
-		serializeAnything(s, s.getUonWriter(out), o);
+	public WriterSerializerSession createSession(SerializerSessionArgs args) {
+		return new UrlEncodingSerializerSession(ctx, null, args);
 	}
 
 	@Override /* PartSerializer */

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
index 6a0fb21..46e36d2 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
@@ -12,62 +12,56 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.urlencoding;
 
+import static org.apache.juneau.internal.ArrayUtils.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
 import org.apache.juneau.uon.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link UrlEncodingSerializer}.
  *
  * <p>
- * This class is NOT thread safe.  It is meant to be discarded after one-time use.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
+@SuppressWarnings({ "rawtypes", "unchecked" })
 public class UrlEncodingSerializerSession extends UonSerializerSession {
 
 	private final boolean expandedParams;
 
 	/**
-	 * Create a new session using properties specified in the context.
+	 * Constructor.
 	 *
 	 * @param ctx
 	 * 	The context creating this session object.
 	 * 	The context contains all the configuration settings for this object.
-	 * @param encode Overrides the {@link UonSerializerContext#UON_encodeChars} setting.
-	 * @param op
-	 * 	The override properties.
-	 * 	These override any context properties defined in the context.
-	 * @param javaMethod The java method that called this serializer, usually the method in a REST servlet.
-	 * @param locale
-	 * 	The session locale.
-	 * 	If <jk>null</jk>, then the locale defined on the context is used.
-	 * @param timeZone
-	 * 	The session timezone.
-	 * 	If <jk>null</jk>, then the timezone defined on the context is used.
-	 * @param mediaType The session media type (e.g. <js>"application/json"</js>).
-	 * @param uriContext
-	 * 	The URI context.
-	 * 	Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
+	 * @param encode Override the {@link UonSerializerContext#UON_encodeChars} setting.
+	 * @param args
+	 * 	Runtime arguments.
+	 * 	These specify session-level information such as locale and URI context.
+	 * 	It also include session-level properties that override the properties defined on the bean and
+	 * 	serializer contexts.
+	 * 	<br>If <jk>null</jk>, defaults to {@link SerializerSessionArgs#DEFAULT}.
 	 */
-	public UrlEncodingSerializerSession(UrlEncodingSerializerContext ctx, Boolean encode, ObjectMap op,
-			Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
-		super(ctx, encode, op, javaMethod, locale, timeZone, mediaType, uriContext);
-		if (op == null || op.isEmpty()) {
+	protected UrlEncodingSerializerSession(UrlEncodingSerializerContext ctx, Boolean encode, SerializerSessionArgs args) {
+		super(ctx, encode, args);
+		ObjectMap p = getProperties();
+		if (p.isEmpty()) {
 			expandedParams = ctx.expandedParams;
 		} else {
-			expandedParams = op.getBoolean(UrlEncodingContext.URLENC_expandedParams, false);
+			expandedParams = p.getBoolean(UrlEncodingContext.URLENC_expandedParams, false);
 		}
 	}
 
-	/**
+	/*
 	 * Returns <jk>true</jk> if the specified bean property should be expanded as multiple key-value pairs.
-	 *
-	 * @param pMeta The metadata on the bean property.
-	 * @return <jk>true</jk> if the specified bean property should be expanded as multiple key-value pairs.
 	 */
-	public final boolean shouldUseExpandedParams(BeanPropertyMeta pMeta) {
+	private boolean shouldUseExpandedParams(BeanPropertyMeta pMeta) {
 		ClassMeta<?> cm = pMeta.getClassMeta();
 		if (cm.isCollectionOrArray()) {
 			if (expandedParams)
@@ -78,13 +72,10 @@ public class UrlEncodingSerializerSession extends UonSerializerSession {
 		return false;
 	}
 
-	/**
+	/*
 	 * Returns <jk>true</jk> if the specified value should be represented as an expanded parameter list.
-	 *
-	 * @param value The value to check.
-	 * @return <jk>true</jk> if the specified value should be represented as an expanded parameter list.
 	 */
-	public final boolean shouldUseExpandedParams(Object value) {
+	private boolean shouldUseExpandedParams(Object value) {
 		if (value == null || ! expandedParams)
 			return false;
 		ClassMeta<?> cm = getClassMetaForObject(value).getSerializedClassMeta();
@@ -94,4 +85,173 @@ public class UrlEncodingSerializerSession extends UonSerializerSession {
 		}
 		return false;
 	}
+
+	@Override /* SerializerSession */
+	protected void doSerialize(SerializerPipe out, Object o) throws Exception {
+		serializeAnything(getUonWriter(out), o);
+	}
+
+	/*
+	 * Workhorse method. Determines the type of object, and then calls the appropriate type-specific serialization method.
+	 */
+	private SerializerWriter serializeAnything(UonWriter out, Object o) throws Exception {
+
+		ClassMeta<?> aType;			// The actual type
+		ClassMeta<?> sType;			// The serialized type
+
+		aType = push("root", o, object());
+		indent--;
+		if (aType == null)
+			aType = object();
+
+		sType = aType.getSerializedClassMeta();
+		String typeName = getBeanTypeName(object(), aType, null);
+
+		// Swap if necessary
+		PojoSwap swap = aType.getPojoSwap();
+		if (swap != null) {
+			o = swap.swap(this, o);
+
+			// If the getSwapClass() method returns Object, we need to figure out
+			// the actual type now.
+			if (sType.isObject())
+				sType = getClassMetaForObject(o);
+		}
+
+		if (sType.isMap()) {
+			if (o instanceof BeanMap)
+				serializeBeanMap(out, (BeanMap)o, typeName);
+			else
+				serializeMap(out, (Map)o, sType);
+		} else if (sType.isBean()) {
+			serializeBeanMap(out, toBeanMap(o), typeName);
+		} else if (sType.isCollection() || sType.isArray()) {
+			Map m = sType.isCollection() ? getCollectionMap((Collection)o) : getCollectionMap(o);
+			serializeCollectionMap(out, m, getClassMeta(Map.class, Integer.class, Object.class));
+		} else {
+			// All other types can't be serialized as key/value pairs, so we create a
+			// mock key/value pair with a "_value" key.
+			out.append("_value=");
+			super.serializeAnything(out, o, null, null, null);
+		}
+
+		pop();
+		return out;
+	}
+
+	/*
+	 * Converts a Collection into an integer-indexed map.
+	 */
+	private static Map<Integer,Object> getCollectionMap(Collection<?> c) {
+		Map<Integer,Object> m = new TreeMap<Integer,Object>();
+		int i = 0;
+		for (Object o : c)
+			m.put(i++, o);
+		return m;
+	}
+
+	/*
+	 * Converts an array into an integer-indexed map.
+	 */
+	private static Map<Integer,Object> getCollectionMap(Object array) {
+		Map<Integer,Object> m = new TreeMap<Integer,Object>();
+		for (int i = 0; i < Array.getLength(array); i++)
+			m.put(i, Array.get(array, i));
+		return m;
+	}
+
+	private SerializerWriter serializeMap(UonWriter out, Map m, ClassMeta<?> type) throws Exception {
+
+		m = sort(m);
+
+		ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
+
+		boolean addAmp = false;
+
+		for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
+			Object key = generalize(e.getKey(), keyType);
+			Object value = e.getValue();
+
+			if (shouldUseExpandedParams(value)) {
+				Iterator i = value instanceof Collection ? ((Collection)value).iterator() : iterator(value);
+				while (i.hasNext()) {
+					if (addAmp)
+						out.cr(indent).append('&');
+					out.appendObject(key, true).append('=');
+					super.serializeAnything(out, i.next(), null, (key == null ? null : key.toString()), null);
+					addAmp = true;
+				}
+			} else {
+				if (addAmp)
+					out.cr(indent).append('&');
+				out.appendObject(key, true).append('=');
+				super.serializeAnything(out, value, valueType, (key == null ? null : key.toString()), null);
+				addAmp = true;
+			}
+		}
+
+		return out;
+	}
+
+	private SerializerWriter serializeCollectionMap(UonWriter out, Map m, ClassMeta<?> type) throws Exception {
+
+		ClassMeta<?> valueType = type.getValueType();
+
+		boolean addAmp = false;
+
+		for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
+			if (addAmp)
+				out.cr(indent).append('&');
+			out.append(e.getKey()).append('=');
+			super.serializeAnything(out, e.getValue(), valueType, null, null);
+			addAmp = true;
+		}
+
+		return out;
+	}
+
+	private SerializerWriter serializeBeanMap(UonWriter out, BeanMap<?> m, String typeName) throws Exception {
+		boolean addAmp = false;
+
+		for (BeanPropertyValue p : m.getValues(isTrimNulls(), typeName != null ? createBeanTypeNameProperty(m, typeName) : null)) {
+			BeanPropertyMeta pMeta = p.getMeta();
+			ClassMeta<?> cMeta = p.getClassMeta();
+
+			String key = p.getName();
+			Object value = p.getValue();
+			Throwable t = p.getThrown();
+			if (t != null)
+				onBeanGetterException(pMeta, t);
+
+			if (canIgnoreValue(cMeta, key, value))
+				continue;
+
+			if (value != null && shouldUseExpandedParams(pMeta)) {
+				// Transformed object array bean properties may be transformed resulting in ArrayLists,
+				// so we need to check type if we think it's an array.
+				Iterator i = (cMeta.isCollection() || value instanceof Collection) ? ((Collection)value).iterator() : iterator(value);
+				while (i.hasNext()) {
+					if (addAmp)
+						out.cr(indent).append('&');
+
+					out.appendObject(key, true).append('=');
+
+					super.serializeAnything(out, i.next(), cMeta.getElementType(), key, pMeta);
+
+					addAmp = true;
+				}
+			} else {
+				if (addAmp)
+					out.cr(indent).append('&');
+
+				out.appendObject(key, true).append('=');
+
+				super.serializeAnything(out, value, cMeta, key, pMeta);
+
+				addAmp = true;
+			}
+
+		}
+		return out;
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java
index e7e4548..6e70c35 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java
@@ -46,12 +46,7 @@ public class XmlDocSerializer extends XmlSerializer {
 		 * @param propertyStore The property store containing all the settings for this object.
 		 */
 		public Ns(PropertyStore propertyStore) {
-			super(propertyStore);
-		}
-
-		@Override /* CoreObject */
-		protected ObjectMap getOverrideProperties() {
-			return super.getOverrideProperties().append(XML_enableNamespaces, true);
+			super(propertyStore.copy().append(XML_enableNamespaces, true));
 		}
 	}
 
@@ -64,19 +59,8 @@ public class XmlDocSerializer extends XmlSerializer {
 		super(propertyStore);
 	}
 
-	//--------------------------------------------------------------------------------
-	// Entry point methods
-	//--------------------------------------------------------------------------------
-
 	@Override /* Serializer */
-	protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception {
-		XmlSerializerSession s = (XmlSerializerSession)session;
-		XmlWriter w = s.getXmlWriter(out);
-		w.append("<?xml")
-			.attr("version", "1.0")
-			.attr("encoding", "UTF-8")
-			.appendln("?>");
-		w.flush();
-		super.doSerialize(s, out, o);
+	public WriterSerializerSession createSession(SerializerSessionArgs args) {
+		return new XmlDocSerializerSession(ctx, args);
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java
new file mode 100644
index 0000000..b889889
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java
@@ -0,0 +1,53 @@
+// ***************************************************************************************************************************
+// * 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.xml;
+
+import org.apache.juneau.serializer.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link XmlDocSerializer}.
+ *
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
+ */
+public class XmlDocSerializerSession extends XmlSerializerSession {
+
+	/**
+	 * Create a new session using properties specified in the context.
+	 *
+	 * @param ctx
+	 * 	The context creating this session object.
+	 * 	The context contains all the configuration settings for this object.
+	 * @param args
+	 * 	Runtime arguments.
+	 * 	These specify session-level information such as locale and URI context.
+	 * 	It also include session-level properties that override the properties defined on the bean and
+	 * 	serializer contexts.
+	 * 	<br>If <jk>null</jk>, defaults to {@link SerializerSessionArgs#DEFAULT}.
+	 */
+	protected XmlDocSerializerSession(XmlSerializerContext ctx, SerializerSessionArgs args) {
+		super(ctx, args);
+	}
+
+	@Override /* SerializerSession */
+	protected void doSerialize(SerializerPipe out, Object o) throws Exception {
+		XmlWriter w = getXmlWriter(out);
+		w.append("<?xml")
+			.attr("version", "1.0")
+			.attr("encoding", "UTF-8")
+			.appendln("?>");
+		w.flush();
+		super.doSerialize(out, o);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java
index aed0b63..cd81507 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java
@@ -12,22 +12,9 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.xml;
 
-import static javax.xml.stream.XMLStreamConstants.*;
-import static org.apache.juneau.internal.StringUtils.*;
-import static org.apache.juneau.xml.annotation.XmlFormat.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import javax.xml.stream.*;
-import javax.xml.stream.Location;
-
 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.annotation.*;
 
 /**
  * Parses text generated by the {@link XmlSerializer} class back into a POJO model.
@@ -48,15 +35,12 @@ import org.apache.juneau.xml.annotation.*;
  * 	<li>{@link BeanContext}
  * </ul>
  */
-@SuppressWarnings({ "rawtypes", "unchecked" })
 @Consumes("text/xml,application/xml")
 public class XmlParser extends ReaderParser {
 
 	/** Default parser, all default settings.*/
 	public static final XmlParser DEFAULT = new XmlParser(PropertyStore.create());
 
-	private static final int UNKNOWN=0, OBJECT=1, ARRAY=2, STRING=3, NUMBER=4, BOOLEAN=5, NULL=6;
-
 
 	private final XmlParserContext ctx;
 
@@ -75,456 +59,8 @@ public class XmlParser extends ReaderParser {
 		return new XmlParserBuilder(propertyStore);
 	}
 
-	/**
-	 * Workhorse method.
-	 *
-	 * @param session The current parser session.
-	 * @param eType The expected type of object.
-	 * @param currAttr The current bean property name.
-	 * @param r The reader.
-	 * @param outer The outer object.
-	 * @param isRoot If <jk>true</jk>, then we're serializing a root element in the document.
-	 * @param pMeta The bean property metadata.
-	 * @return The parsed object.
-	 * @throws Exception
-	 */
-	protected <T> T parseAnything(XmlParserSession session, ClassMeta<T> eType, String currAttr, 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);
-
-		String wrapperAttr = (isRoot && session.isPreserveRootElement()) ? r.getName().getLocalPart() : null;
-		String typeAttr = r.getAttributeValue(null, session.getBeanTypePropertyName(eType));
-		int jsonType = getJsonType(typeAttr);
-		String elementName = session.getElementName(r);
-		if (jsonType == 0) {
-			if (elementName == null || elementName.equals(currAttr))
-				jsonType = UNKNOWN;
-			else {
-				typeAttr = elementName;
-				jsonType = getJsonType(elementName);
-			}
-		}
-
-		ClassMeta tcm = session.getClassMeta(typeAttr, pMeta, eType);
-		if (tcm == null && elementName != null && ! elementName.equals(currAttr))
-			tcm = session.getClassMeta(elementName, pMeta, eType);
-		if (tcm != null)
-			sType = eType = tcm;
-
-		Object o = null;
-
-		if (jsonType == NULL) {
-			r.nextTag();	// Discard end tag
-			return null;
-		}
-
-		if (sType.isObject()) {
-			if (jsonType == OBJECT) {
-				ObjectMap m = new ObjectMap(session);
-				parseIntoMap(session, r, m, string(), object(), pMeta);
-				if (wrapperAttr != null)
-					m = new ObjectMap(session).append(wrapperAttr, m);
-				o = session.cast(m, pMeta, eType);
-			} else if (jsonType == ARRAY)
-				o = parseIntoCollection(session, r, new ObjectList(session), null, pMeta);
-			else if (jsonType == STRING) {
-				o = session.getElementText(r);
-				if (sType.isChar())
-					o = o.toString().charAt(0);
-			}
-			else if (jsonType == NUMBER)
-				o = parseNumber(session.getElementText(r), null);
-			else if (jsonType == BOOLEAN)
-				o = Boolean.parseBoolean(session.getElementText(r));
-			else if (jsonType == UNKNOWN)
-				o = getUnknown(session, r);
-		} else if (sType.isBoolean()) {
-			o = Boolean.parseBoolean(session.getElementText(r));
-		} else if (sType.isCharSequence()) {
-			o = session.getElementText(r);
-		} else if (sType.isChar()) {
-			String s = session.getElementText(r);
-			o = s.length() == 0 ? 0 : s.charAt(0);
-		} else if (sType.isMap()) {
-			Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(session));
-			o = parseIntoMap(session, r, m, sType.getKeyType(), sType.getValueType(), pMeta);
-			if (wrapperAttr != null)
-				o = new ObjectMap(session).append(wrapperAttr, m);
-		} else if (sType.isCollection()) {
-			Collection l = (sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance(outer) : new ObjectList(session));
-			o = parseIntoCollection(session, r, l, sType, pMeta);
-		} else if (sType.isNumber()) {
-			o = parseNumber(session.getElementText(r), (Class<? extends Number>)sType.getInnerClass());
-		} else if (sType.canCreateNewBean(outer)) {
-			if (sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED) {
-				String fieldName = r.getLocalName();
-				BeanMap<?> m = session.newBeanMap(outer, sType.getInnerClass());
-				BeanPropertyMeta bpm = m.getMeta().getExtendedMeta(XmlBeanMeta.class).getPropertyMeta(fieldName);
-				ClassMeta<?> cm = m.getMeta().getClassMeta();
-				Object value = parseAnything(session, cm, currAttr, r, m.getBean(false), false, null);
-				setName(cm, value, currAttr);
-				bpm.set(m, currAttr, value);
-				o = m.getBean();
-			} else {
-				BeanMap m = session.newBeanMap(outer, sType.getInnerClass());
-				o = parseIntoBean(session, r, m).getBean();
-			}
-		} else if (sType.isArray() || sType.isArgs()) {
-			ArrayList l = (ArrayList)parseIntoCollection(session, r, new ArrayList(), sType, pMeta);
-			o = session.toArray(sType, l);
-		} else if (sType.canCreateNewInstanceFromString(outer)) {
-			o = sType.newInstanceFromString(outer, session.getElementText(r));
-		} else if (sType.canCreateNewInstanceFromNumber(outer)) {
-			o = sType.newInstanceFromNumber(session, outer, parseNumber(session.getElementText(r), sType.getNewInstanceFromNumberClass()));
-		} else {
-			throw new ParseException(session,
-				"Class ''{0}'' could not be instantiated.  Reason: ''{1}'', property: ''{2}''",
-				sType.getInnerClass().getName(), sType.getNotABeanReason(), pMeta == null ? null : pMeta.getName());
-		}
-
-		if (transform != null && o != null)
-			o = transform.unswap(session, o, eType);
-
-		if (outer != null)
-			setParent(eType, o, outer);
-
-		return (T)o;
-	}
-
-	private <K,V> Map<K,V> parseIntoMap(XmlParserSession session, XMLStreamReader r, Map<K,V> m, ClassMeta<K> keyType,
-			ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws Exception {
-		int depth = 0;
-		for (int i = 0; i < r.getAttributeCount(); i++) {
-			String a = r.getAttributeLocalName(i);
-			// TODO - Need better handling of namespaces here.
-			if (! (a.equals(session.getBeanTypePropertyName(null)))) {
-				K key = session.trim(convertAttrToType(session, m, a, keyType));
-				V value = session.trim(convertAttrToType(session, m, r.getAttributeValue(i), valueType));
-				setName(valueType, value, key);
-				m.put(key, value);
-			}
-		}
-		do {
-			int event = r.nextTag();
-			String currAttr;
-			if (event == START_ELEMENT) {
-				depth++;
-				currAttr = session.getElementName(r);
-				K key = convertAttrToType(session, m, currAttr, keyType);
-				V value = parseAnything(session, valueType, currAttr, r, m, false, pMeta);
-				setName(valueType, value, currAttr);
-				if (valueType.isObject() && m.containsKey(key)) {
-					Object o = m.get(key);
-					if (o instanceof List)
-						((List)o).add(value);
-					else
-						m.put(key, (V)new ObjectList(o, value).setBeanSession(session));
-				} else {
-					m.put(key, value);
-				}
-			} else if (event == END_ELEMENT) {
-				depth--;
-				return m;
-			}
-		} while (depth > 0);
-		return m;
-	}
-
-	private <E> Collection<E> parseIntoCollection(XmlParserSession session, XMLStreamReader r, Collection<E> l,
-			ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception {
-		int depth = 0;
-		int argIndex = 0;
-		do {
-			int event = r.nextTag();
-			if (event == START_ELEMENT) {
-				depth++;
-				ClassMeta<?> elementType = type == null ? object() : type.isArgs() ? type.getArg(argIndex++) : type.getElementType();
-				E value = (E)parseAnything(session, elementType, null, r, l, false, pMeta);
-				l.add(value);
-			} else if (event == END_ELEMENT) {
-				depth--;
-				return l;
-			}
-		} while (depth > 0);
-		return l;
-	}
-
-	private static int getJsonType(String s) {
-		if (s == null)
-			return UNKNOWN;
-		char c = s.charAt(0);
-		switch(c) {
-			case 'o': return (s.equals("object") ? OBJECT : UNKNOWN);
-			case 'a': return (s.equals("array") ? ARRAY : UNKNOWN);
-			case 's': return (s.equals("string") ? STRING : UNKNOWN);
-			case 'b': return (s.equals("boolean") ? BOOLEAN : UNKNOWN);
-			case 'n': {
-				c = s.charAt(2);
-				switch(c) {
-					case 'm': return (s.equals("number") ? NUMBER : UNKNOWN);
-					case 'l': return (s.equals("null") ? NULL : UNKNOWN);
-				}
-				//return NUMBER;
-			}
-		}
-		return UNKNOWN;
-	}
-
-	private <T> BeanMap<T> parseIntoBean(XmlParserSession session, XMLStreamReader r, BeanMap<T> m) throws Exception {
-		BeanMeta<?> bMeta = m.getMeta();
-		XmlBeanMeta xmlMeta = bMeta.getExtendedMeta(XmlBeanMeta.class);
-
-		for (int i = 0; i < r.getAttributeCount(); i++) {
-			String key = session.getAttributeName(r, i);
-			String val = r.getAttributeValue(i);
-			BeanPropertyMeta bpm = xmlMeta.getPropertyMeta(key);
-			if (bpm == null) {
-				if (xmlMeta.getAttrsProperty() != null) {
-					xmlMeta.getAttrsProperty().add(m, key, key, val);
-				} else {
-					Location l = r.getLocation();
-					session.onUnknownProperty(key, m, l.getLineNumber(), l.getColumnNumber());
-				}
-			} else {
-				bpm.set(m, key, val);
-			}
-		}
-
-		BeanPropertyMeta cp = xmlMeta.getContentProperty();
-		XmlFormat cpf = xmlMeta.getContentFormat();
-		boolean trim = cp == null || ! cpf.isOneOf(MIXED_PWS, TEXT_PWS);
-		ClassMeta<?> cpcm = (cp == null ? session.object() : cp.getClassMeta());
-		StringBuilder sb = null;
-		BeanRegistry breg = cp == null ? null : cp.getBeanRegistry();
-		LinkedList<Object> l = null;
-
-		int depth = 0;
-		do {
-			int event = r.next();
-			String currAttr;
-			// We only care about text in MIXED mode.
-			// Ignore if in ELEMENTS mode.
-			if (event == CHARACTERS) {
-				if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) {
-					if (cpcm.isCollectionOrArray()) {
-						if (l == null)
-							l = new LinkedList<Object>();
-						l.add(session.getText(r, false));
-					} else {
-						cp.set(m, null, session.getText(r, trim));
-					}
-				} else if (cpf != ELEMENTS) {
-					String s = session.getText(r, trim);
-					if (s != null) {
-						if (sb == null)
-							sb = session.getStringBuilder();
-						sb.append(s);
-					}
-				} else {
-					// Do nothing...we're in ELEMENTS mode.
-				}
-			} else if (event == START_ELEMENT) {
-				if (cp != null && cpf.isOneOf(TEXT, TEXT_PWS)) {
-					String s = session.parseText(r);
-					if (s != null) {
-						if (sb == null)
-							sb = session.getStringBuilder();
-						sb.append(s);
-					}
-					depth--;
-				} else if (cpf == XMLTEXT) {
-					if (sb == null)
-						sb = session.getStringBuilder();
-					sb.append(session.getElementAsString(r));
-					depth++;
-				} else if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) {
-					if (session.isWhitespaceElement(r) && (breg == null || ! breg.hasName(r.getLocalName()))) {
-						if (cpcm.isCollectionOrArray()) {
-							if (l == null)
-								l = new LinkedList<Object>();
-							l.add(session.parseWhitespaceElement(r));
-						} else {
-							cp.set(m, null, session.parseWhitespaceElement(r));
-						}
-					} else {
-						if (cpcm.isCollectionOrArray()) {
-							if (l == null)
-								l = new LinkedList<Object>();
-							l.add(parseAnything(session, cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp));
-						} else {
-							cp.set(m, null, parseAnything(session, cpcm, cp.getName(), r, m.getBean(false), false, cp));
-						}
-					}
-				} else if (cp != null && cpf == ELEMENTS) {
-					cp.add(m, null, parseAnything(session, cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp));
-				} else {
-					currAttr = session.getElementName(r);
-					BeanPropertyMeta pMeta = xmlMeta.getPropertyMeta(currAttr);
-					if (pMeta == null) {
-						Location loc = r.getLocation();
-						session.onUnknownProperty(currAttr, m, loc.getLineNumber(), loc.getColumnNumber());
-						skipCurrentTag(r);
-					} else {
-						session.setCurrentProperty(pMeta);
-						XmlFormat xf = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
-						if (xf == COLLAPSED) {
-							ClassMeta<?> et = pMeta.getClassMeta().getElementType();
-							Object value = parseAnything(session, et, currAttr, r, m.getBean(false), false, pMeta);
-							setName(et, value, currAttr);
-							pMeta.add(m, currAttr, value);
-						} else if (xf == ATTR)  {
-							pMeta.set(m, currAttr, session.getAttributeValue(r, 0));
-							r.nextTag();
-						} else {
-							ClassMeta<?> cm = pMeta.getClassMeta();
-							Object value = parseAnything(session, cm, currAttr, r, m.getBean(false), false, pMeta);
-							setName(cm, value, currAttr);
-							pMeta.set(m, currAttr, value);
-						}
-						session.setCurrentProperty(null);
-					}
-				}
-			} else if (event == END_ELEMENT) {
-				if (depth > 0) {
-					if (cpf == XMLTEXT) {
-						if (sb == null)
-							sb = session.getStringBuilder();
-						sb.append(session.getElementAsString(r));
-					}
-					else
-						throw new ParseException("End element found where one was not expected.  {0}", XmlUtils.toReadableEvent(r));
-				}
-				depth--;
-			} else {
-				throw new ParseException("Unexpected event type: {0}", XmlUtils.toReadableEvent(r));
-			}
-		} while (depth >= 0);
-
-		if (sb != null && cp != null)
-			cp.set(m, null, sb.toString());
-		else if (l != null && cp != null)
-			cp.set(m, null, XmlUtils.collapseTextNodes(l));
-
-		session.returnStringBuilder(sb);
-		return m;
-	}
-
-	private static void skipCurrentTag(XMLStreamReader r) throws XMLStreamException {
-		int depth = 1;
-		do {
-			int event = r.next();
-			if (event == START_ELEMENT)
-				depth++;
-			else if (event == END_ELEMENT)
-				depth--;
-		} while (depth > 0);
-	}
-
-	private Object getUnknown(XmlParserSession session, XMLStreamReader r) throws Exception {
-		if (r.getEventType() != XMLStreamConstants.START_ELEMENT) {
-			throw new XmlParseException(r.getLocation(), "Parser must be on START_ELEMENT to read next text.");
-		}
-		ObjectMap m = null;
-
-		// If this element has attributes, then it's always an ObjectMap.
-		if (r.getAttributeCount() > 0) {
-			m = new ObjectMap(session);
-			for (int i = 0; i < r.getAttributeCount(); i++) {
-				String key = session.getAttributeName(r, i);
-				String val = r.getAttributeValue(i);
-				if (! key.equals(session.getBeanTypePropertyName(null)))
-					m.put(key, val);
-			}
-		}
-		int eventType = r.next();
-		StringBuilder sb = session.getStringBuilder();
-		while (eventType != XMLStreamConstants.END_ELEMENT) {
-			if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
-				sb.append(r.getText());
-			} else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) {
-				// skipping
-			} else if (eventType == XMLStreamConstants.END_DOCUMENT) {
-				throw new XmlParseException(r.getLocation(), "Unexpected end of document when reading element text content");
-			} else if (eventType == XMLStreamConstants.START_ELEMENT) {
-				// Oops...this has an element in it.
-				// Parse it as a map.
-				if (m == null)
-					m = new ObjectMap(session);
-				int depth = 0;
-				do {
-					int event = (eventType == -1 ? r.nextTag() : eventType);
-					String currAttr;
-					if (event == START_ELEMENT) {
-						depth++;
-						currAttr = session.getElementName(r);
-						String key = convertAttrToType(session, null, currAttr, string());
-						Object value = parseAnything(session, object(), currAttr, r, null, false, null);
-						if (m.containsKey(key)) {
-							Object o = m.get(key);
-							if (o instanceof ObjectList)
-								((ObjectList)o).add(value);
-							else
-								m.put(key, new ObjectList(o, value).setBeanSession(session));
-						} else {
-							m.put(key, value);
-						}
-
-					} else if (event == END_ELEMENT) {
-						depth--;
-						break;
-					}
-					eventType = -1;
-				} while (depth > 0);
-				break;
-			} else {
-				throw new XmlParseException(r.getLocation(), "Unexpected event type ''{0}''", eventType);
-			}
-			eventType = r.next();
-		}
-		String s = sb.toString();
-		session.returnStringBuilder(sb);
-		s = session.decodeString(s);
-		if (m != null) {
-			if (! s.isEmpty())
-				m.put("contents", s);
-			return m;
-		}
-		return s;
-	}
-
-
-	//--------------------------------------------------------------------------------
-	// Entry point methods
-	//--------------------------------------------------------------------------------
-
 	@Override /* Parser */
-	public XmlParserSession createSession(Object input, ObjectMap op, Method javaMethod, Object outer, Locale locale,
-			TimeZone timeZone, MediaType mediaType) {
-		return new XmlParserSession(ctx, op, input, javaMethod, outer, locale, timeZone, mediaType);
-	}
-
-	@Override /* Parser */
-	protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception {
-		XmlParserSession s = (XmlParserSession)session;
-		return parseAnything(s, type, null, 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 {
-		XmlParserSession s = (XmlParserSession)session;
-		ClassMeta cm = session.getClassMeta(m.getClass(), keyType, valueType);
-		return parseIntoMap(s, m, cm.getKeyType(), cm.getValueType());
-	}
-
-	@Override /* ReaderParser */
-	protected <E> Collection<E> doParseIntoCollection(ParserSession session, Collection<E> c, Type elementType) throws Exception {
-		XmlParserSession s = (XmlParserSession)session;
-		ClassMeta cm = session.getClassMeta(c.getClass(), elementType);
-		return parseIntoCollection(s,c, cm.getElementType());
+	public ReaderParserSession createSession(ParserSessionArgs args) {
+		return new XmlParserSession(ctx, args);
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java
index 3dd0d13..1f41d56 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java
@@ -14,9 +14,9 @@ package org.apache.juneau.xml;
 
 import static javax.xml.stream.XMLStreamConstants.*;
 import static org.apache.juneau.xml.XmlParserContext.*;
-import static org.apache.juneau.internal.IOUtils.*;
+import static org.apache.juneau.xml.annotation.XmlFormat.*;
+import static org.apache.juneau.internal.StringUtils.*;
 
-import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
@@ -24,17 +24,22 @@ import javax.xml.stream.*;
 import javax.xml.stream.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.parser.*;
+import org.apache.juneau.transform.*;
 import org.apache.juneau.xml.annotation.*;
 
 /**
  * Session object that lives for the duration of a single use of {@link XmlParser}.
  *
  * <p>
- * This class is NOT thread safe.  It is meant to be discarded after one-time use.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused against multiple inputs.
  */
-public class XmlParserSession extends ParserSession {
+@SuppressWarnings({ "unchecked", "rawtypes" })
+public class XmlParserSession extends ReaderParserSession {
+
+	private static final int UNKNOWN=0, OBJECT=1, ARRAY=2, STRING=3, NUMBER=4, BOOLEAN=5, NULL=6;
+
 
 	private final boolean
 		validating,
@@ -42,8 +47,7 @@ public class XmlParserSession extends ParserSession {
 	private final XMLReporter reporter;
 	private final XMLResolver resolver;
 	private final XMLEventAllocator eventAllocator;
-	private XMLStreamReader xmlStreamReader;
-	private final StringBuilder sb = new StringBuilder();  // Reusable string builder used in this class.
+	private final StringBuilder rsb = new StringBuilder();  // Reusable string builder used in this class.
 
 	/**
 	 * Create a new session using properties specified in the context.
@@ -51,89 +55,36 @@ public class XmlParserSession extends ParserSession {
 	 * @param ctx
 	 * 	The context creating this session object.
 	 * 	The context contains all the configuration settings for this object.
-	 * @param input
-	 * 	The input.
-	 * 	Can be any of the following types:
-	 * 	<ul>
-	 * 		<li><jk>null</jk>
-	 * 		<li>{@link Reader}
-	 * 		<li>{@link CharSequence}
-	 * 		<li>{@link InputStream} containing UTF-8 encoded text.
-	 * 		<li>{@link File} containing system encoded text.
-	 * 	</ul>
-	 * @param op
-	 * 	The override properties.
-	 * 	These override any context properties defined in the context.
-	 * @param javaMethod The java method that called this parser, usually the method in a REST servlet.
-	 * @param outer The outer object for instantiating top-level non-static inner classes.
-	 * @param locale
-	 * 	The session locale.
-	 * 	If <jk>null</jk>, then the locale defined on the context is used.
-	 * @param timeZone
-	 * 	The session timezone.
-	 * 	If <jk>null</jk>, then the timezone defined on the context is used.
-	 * @param mediaType The session media type (e.g. <js>"application/json"</js>).
+	 * @param args
+	 * 	Runtime session arguments.
 	 */
-	public XmlParserSession(XmlParserContext ctx, ObjectMap op, Object input, Method javaMethod, Object outer,
-			Locale locale, TimeZone timeZone, MediaType mediaType) {
-		super(ctx, op, input, javaMethod, outer, locale, timeZone, mediaType);
-		if (op == null || op.isEmpty()) {
+	protected XmlParserSession(XmlParserContext ctx, ParserSessionArgs args) {
+		super(ctx, args);
+		ObjectMap p = getProperties();
+		if (p.isEmpty()) {
 			validating = ctx.validating;
 			reporter = ctx.reporter;
 			resolver = ctx.resolver;
 			eventAllocator = ctx.eventAllocator;
 			preserveRootElement = ctx.preserveRootElement;
 		} else {
-			validating = op.getBoolean(XML_validating, ctx.validating);
-			reporter = (XMLReporter)op.get(XML_reporter, ctx.reporter);
-			resolver = (XMLResolver)op.get(XML_resolver, ctx.resolver);
-			eventAllocator = (XMLEventAllocator)op.get(XML_eventAllocator, ctx.eventAllocator);
-			preserveRootElement = op.getBoolean(XML_preserveRootElement, ctx.preserveRootElement);
+			validating = p.getBoolean(XML_validating, ctx.validating);
+			reporter = (XMLReporter)p.get(XML_reporter, ctx.reporter);
+			resolver = (XMLResolver)p.get(XML_resolver, ctx.resolver);
+			eventAllocator = (XMLEventAllocator)p.get(XML_eventAllocator, ctx.eventAllocator);
+			preserveRootElement = p.getBoolean(XML_preserveRootElement, ctx.preserveRootElement);
 		}
 	}
 
 	/**
-	 * Returns the {@link XmlParserContext#XML_preserveRootElement} setting value for this session.
-	 *
-	 * @return The {@link XmlParserContext#XML_preserveRootElement} setting value for this session.
-	 */
-	public final boolean isPreserveRootElement() {
-		return preserveRootElement;
-	}
-
-	/**
 	 * Wrap the specified reader in a STAX reader based on settings in this context.
 	 *
+	 * @param pipe The parser input.
 	 * @return The new STAX reader.
 	 * @throws Exception If problem occurred trying to create reader.
 	 */
-	public final XMLStreamReader getXmlStreamReader() throws Exception {
-		if (xmlStreamReader != null)
-			return xmlStreamReader;
-
-		try {
-			Reader r = getBufferedReader(getReader());
-			XMLInputFactory factory = XMLInputFactory.newInstance();
-			factory.setProperty(XMLInputFactory.IS_VALIDATING, validating);
-			factory.setProperty(XMLInputFactory.IS_COALESCING, true);
-			factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true);  // This usually has no effect anyway.
-			if (factory.isPropertySupported(XMLInputFactory.REPORTER) && reporter != null)
-				factory.setProperty(XMLInputFactory.REPORTER, reporter);
-			if (factory.isPropertySupported(XMLInputFactory.RESOLVER) && resolver != null)
-				factory.setProperty(XMLInputFactory.RESOLVER, resolver);
-			if (factory.isPropertySupported(XMLInputFactory.ALLOCATOR) && eventAllocator != null)
-				factory.setProperty(XMLInputFactory.ALLOCATOR, eventAllocator);
-			xmlStreamReader = factory.createXMLStreamReader(r);
-			xmlStreamReader.nextTag();
-		} catch (Error e) {
-			close();
-			throw new ParseException(e.getLocalizedMessage());
-		} catch (XMLStreamException e) {
-			close();
-			throw new ParseException(e);
-		}
-
-		return xmlStreamReader;
+	protected final XmlReader getXmlReader(ParserPipe pipe) throws Exception {
+		return new XmlReader(pipe, validating, reporter, resolver, eventAllocator);
 	}
 
 	/**
@@ -145,57 +96,37 @@ public class XmlParserSession extends ParserSession {
 	 * @param s The string to be decoded.
 	 * @return The decoded string.
 	 */
-	public final String decodeString(String s) {
+	protected final String decodeString(String s) {
 		if (s == null)
 			return null;
-		sb.setLength(0);
-		s = XmlUtils.decode(s, sb);
+		rsb.setLength(0);
+		s = XmlUtils.decode(s, rsb);
 		if (isTrimStrings())
 			s = s.trim();
 		return s;
 	}
 
-	/**
+	/*
 	 * Returns the name of the current XML element.
-	 *
-	 * <p>
 	 * Any <js>'_x####_'</js> sequences in the string will be decoded.
-	 *
-	 * @param r The reader to read from.
-	 * @return The decoded element name.
-	 * @throws XMLStreamException
 	 */
-	public final String getElementName(XMLStreamReader r) throws XMLStreamException {
+	private String getElementName(XmlReader r) {
 		return decodeString(r.getLocalName());
 	}
 
-	/**
+	/*
 	 * Returns the name of the specified attribute on the current XML element.
-	 *
-	 * <p>
 	 * Any <js>'_x####_'</js> sequences in the string will be decoded.
-	 *
-	 * @param r The reader to read from.
-	 * @param i The attribute index.
-	 * @return The decoded attribute name.
-	 * @throws XMLStreamException
 	 */
-	public final String getAttributeName(XMLStreamReader r, int i) throws XMLStreamException {
+	private String getAttributeName(XmlReader r, int i) {
 		return decodeString(r.getAttributeLocalName(i));
 	}
 
-	/**
+	/*
 	 * Returns the value of the specified attribute on the current XML element.
-	 *
-	 * <p>
 	 * Any <js>'_x####_'</js> sequences in the string will be decoded.
-	 *
-	 * @param r The reader to read from.
-	 * @param i The attribute index.
-	 * @return The decoded attribute value.
-	 * @throws XMLStreamException
 	 */
-	public final String getAttributeValue(XMLStreamReader r, int i) throws XMLStreamException {
+	private String getAttributeValue(XmlReader r, int i) {
 		return decodeString(r.getAttributeValue(i));
 	}
 
@@ -212,28 +143,16 @@ public class XmlParserSession extends ParserSession {
 	 * @return The decoded text.  <jk>null</jk> if the text consists of the sequence <js>'_x0000_'</js>.
 	 * @throws Exception
 	 */
-	public String getElementText(XMLStreamReader r) throws Exception {
-		String s = r.getElementText().trim();
-		return decodeString(s);
+	protected String getElementText(XmlReader r) throws Exception {
+		return decodeString(r.getElementText().trim());
 	}
 
-	/**
+	/*
 	 * Returns the content of the current CHARACTERS node.
-	 *
-	 * <p>
 	 * Any <js>'_x####_'</js> sequences in the string will be decoded.
-	 *
-	 * <p>
 	 * Leading and trailing whitespace (unencoded) will be trimmed from the result.
-	 *
-	 * @param r The reader to read the element text from.
-	 * @param trim
-	 * 	If <jk>true</jk>, trim the contents of the text node BEFORE decoding escape sequences.
-	 * 	Typically <jk>true</jk> for {@link XmlFormat#MIXED_PWS} and {@link XmlFormat#TEXT_PWS}.
-	 * @return The decoded text.  <jk>null</jk> if the text consists of the sequence <js>'_x0000_'</js>.
-	 * @throws XMLStreamException
 	 */
-	public String getText(XMLStreamReader r, boolean trim) throws XMLStreamException {
+	private String getText(XmlReader r, boolean trim) {
 		String s = r.getText();
 		if (trim)
 			s = s.trim();
@@ -242,52 +161,41 @@ public class XmlParserSession extends ParserSession {
 		return decodeString(s);
 	}
 
-	/**
+	/*
 	 * Shortcut for calling <code>getText(r, <jk>true</jk>);</code>.
-	 *
-	 * @param r The reader to read the element text from.
-	 * @return The decoded text.  <jk>null</jk> if the text consists of the sequence <js>'_x0000_'</js>.
-	 * @throws XMLStreamException
 	 */
-	public String getText(XMLStreamReader r) throws XMLStreamException {
+	private String getText(XmlReader r) {
 		return getText(r, true);
 	}
 
-	/**
+	/*
 	 * Takes the element being read from the XML stream reader and reconstructs it as XML.
-	 *
-	 * <p>
 	 * Used when reconstructing bean properties of type {@link XmlFormat#XMLTEXT}.
-	 *
-	 * @param r The XML stream reader to read the current event from.
-	 * @return The event as XML.
-	 * @throws RuntimeException if the event is not a start or end tag.
 	 */
-	public final String getElementAsString(XMLStreamReader r) {
+	private String getElementAsString(XmlReader r) {
 		int t = r.getEventType();
 		if (t > 2)
 			throw new FormattedRuntimeException("Invalid event type on stream reader for elementToString() method: ''{0}''", XmlUtils.toReadableEvent(r));
-		sb.setLength(0);
-		sb.append("<").append(t == 1 ? "" : "/").append(r.getLocalName());
+		rsb.setLength(0);
+		rsb.append("<").append(t == 1 ? "" : "/").append(r.getLocalName());
 		if (t == 1)
 			for (int i = 0; i < r.getAttributeCount(); i++)
-				sb.append(' ').append(r.getAttributeName(i)).append('=').append('\'').append(r.getAttributeValue(i)).append('\'');
-		sb.append('>');
-		return sb.toString();
+				rsb.append(' ').append(r.getAttributeName(i)).append('=').append('\'').append(r.getAttributeValue(i)).append('\'');
+		rsb.append('>');
+		return rsb.toString();
 	}
 
 	/**
 	 * Parses the current element as text.
 	 *
-	 * <p>
-	 * Note that this is different than {@link #getText(XMLStreamReader)} since it assumes that we're pointing to a
-	 * whitespace element.
-	 *
 	 * @param r
 	 * @return The parsed text.
 	 * @throws Exception
 	 */
-	public String parseText(XMLStreamReader r) throws Exception {
+	protected String parseText(XmlReader r) throws Exception {
+		// Note that this is different than {@link #getText(XmlReader)} since it assumes that we're pointing to a
+		// whitespace element.
+
 		StringBuilder sb2 = getStringBuilder();
 
 		int depth = 0;
@@ -321,7 +229,7 @@ public class XmlParserSession extends ParserSession {
 	 * @param r The XML stream reader to read the current event from.
 	 * @return <jk>true</jk> if the current element is a whitespace element.
 	 */
-	public boolean isWhitespaceElement(XMLStreamReader r) {
+	protected boolean isWhitespaceElement(XmlReader r) {
 		return false;
 	}
 
@@ -337,24 +245,449 @@ public class XmlParserSession extends ParserSession {
 	 * @throws XMLStreamException
 	 * @throws Exception
 	 */
-	public String parseWhitespaceElement(XMLStreamReader r) throws Exception {
+	protected String parseWhitespaceElement(XmlReader r) throws Exception {
 		return null;
 	}
 
+	@Override /* ParserSession */
+	protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception {
+		return parseAnything(type, null, 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 {
+		ClassMeta cm = getClassMeta(m.getClass(), keyType, valueType);
+		return parseIntoMap(pipe, m, cm.getKeyType(), cm.getValueType());
+	}
+
+	@Override /* ReaderParserSession */
+	protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, Collection<E> c, Type elementType) throws Exception {
+		ClassMeta cm = getClassMeta(c.getClass(), elementType);
+		return parseIntoCollection(pipe, c, cm.getElementType());
+	}
+
 	/**
-	 * Silently closes the XML stream.
+	 * Workhorse method.
+	 *
+	 * @param eType The expected type of object.
+	 * @param currAttr The current bean property name.
+	 * @param r The reader.
+	 * @param outer The outer object.
+	 * @param isRoot If <jk>true</jk>, then we're serializing a root element in the document.
+	 * @param pMeta The bean property metadata.
+	 * @return The parsed object.
+	 * @throws Exception
 	 */
-	@Override /* ParserContext */
-	public boolean close() {
-		if (super.close()) {
-			try {
-				if (xmlStreamReader != null)
-					xmlStreamReader.close();
-			} catch (XMLStreamException e) {
-				// Ignore.
+	protected <T> T parseAnything(ClassMeta<T> eType, String currAttr, 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);
+
+		String wrapperAttr = (isRoot && preserveRootElement) ? r.getName().getLocalPart() : null;
+		String typeAttr = r.getAttributeValue(null, getBeanTypePropertyName(eType));
+		int jsonType = getJsonType(typeAttr);
+		String elementName = getElementName(r);
+		if (jsonType == 0) {
+			if (elementName == null || elementName.equals(currAttr))
+				jsonType = UNKNOWN;
+			else {
+				typeAttr = elementName;
+				jsonType = getJsonType(elementName);
 			}
-			return true;
 		}
-		return false;
+
+		ClassMeta tcm = getClassMeta(typeAttr, pMeta, eType);
+		if (tcm == null && elementName != null && ! elementName.equals(currAttr))
+			tcm = getClassMeta(elementName, pMeta, eType);
+		if (tcm != null)
+			sType = eType = tcm;
+
+		Object o = null;
+
+		if (jsonType == NULL) {
+			r.nextTag();	// Discard end tag
+			return null;
+		}
+
+		if (sType.isObject()) {
+			if (jsonType == OBJECT) {
+				ObjectMap m = new ObjectMap(this);
+				parseIntoMap(r, m, string(), object(), pMeta);
+				if (wrapperAttr != null)
+					m = new ObjectMap(this).append(wrapperAttr, m);
+				o = cast(m, pMeta, eType);
+			} else if (jsonType == ARRAY)
+				o = parseIntoCollection(r, new ObjectList(this), null, pMeta);
+			else if (jsonType == STRING) {
+				o = getElementText(r);
+				if (sType.isChar())
+					o = o.toString().charAt(0);
+			}
+			else if (jsonType == NUMBER)
+				o = parseNumber(getElementText(r), null);
+			else if (jsonType == BOOLEAN)
+				o = Boolean.parseBoolean(getElementText(r));
+			else if (jsonType == UNKNOWN)
+				o = getUnknown(r);
+		} else if (sType.isBoolean()) {
+			o = Boolean.parseBoolean(getElementText(r));
+		} else if (sType.isCharSequence()) {
+			o = getElementText(r);
+		} else if (sType.isChar()) {
+			String s = getElementText(r);
+			o = s.length() == 0 ? 0 : s.charAt(0);
+		} else if (sType.isMap()) {
+			Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(this));
+			o = parseIntoMap(r, m, sType.getKeyType(), sType.getValueType(), pMeta);
+			if (wrapperAttr != null)
+				o = new ObjectMap(this).append(wrapperAttr, m);
+		} else if (sType.isCollection()) {
+			Collection l = (sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance(outer) : new ObjectList(this));
+			o = parseIntoCollection(r, l, sType, pMeta);
+		} else if (sType.isNumber()) {
+			o = parseNumber(getElementText(r), (Class<? extends Number>)sType.getInnerClass());
+		} else if (sType.canCreateNewBean(outer)) {
+			if (sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED) {
+				String fieldName = r.getLocalName();
+				BeanMap<?> m = newBeanMap(outer, sType.getInnerClass());
+				BeanPropertyMeta bpm = m.getMeta().getExtendedMeta(XmlBeanMeta.class).getPropertyMeta(fieldName);
+				ClassMeta<?> cm = m.getMeta().getClassMeta();
+				Object value = parseAnything(cm, currAttr, r, m.getBean(false), false, null);
+				setName(cm, value, currAttr);
+				bpm.set(m, currAttr, value);
+				o = m.getBean();
+			} else {
+				BeanMap m = newBeanMap(outer, sType.getInnerClass());
+				o = parseIntoBean(r, m).getBean();
+			}
+		} else if (sType.isArray() || sType.isArgs()) {
+			ArrayList l = (ArrayList)parseIntoCollection(r, new ArrayList(), sType, pMeta);
+			o = toArray(sType, l);
+		} else if (sType.canCreateNewInstanceFromString(outer)) {
+			o = sType.newInstanceFromString(outer, getElementText(r));
+		} else if (sType.canCreateNewInstanceFromNumber(outer)) {
+			o = sType.newInstanceFromNumber(this, outer, parseNumber(getElementText(r), sType.getNewInstanceFromNumberClass()));
+		} else {
+			throw new ParseException(loc(r),
+				"Class ''{0}'' could not be instantiated.  Reason: ''{1}'', property: ''{2}''",
+				sType.getInnerClass().getName(), sType.getNotABeanReason(), pMeta == null ? null : pMeta.getName());
+		}
+
+		if (transform != null && o != null)
+			o = transform.unswap(this, o, eType);
+
+		if (outer != null)
+			setParent(eType, o, outer);
+
+		return (T)o;
+	}
+
+	private <K,V> Map<K,V> parseIntoMap(XmlReader r, Map<K,V> m, ClassMeta<K> keyType,
+			ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws Exception {
+		int depth = 0;
+		for (int i = 0; i < r.getAttributeCount(); i++) {
+			String a = r.getAttributeLocalName(i);
+			// TODO - Need better handling of namespaces here.
+			if (! (a.equals(getBeanTypePropertyName(null)))) {
+				K key = trim(convertAttrToType(m, a, keyType));
+				V value = trim(convertAttrToType(m, r.getAttributeValue(i), valueType));
+				setName(valueType, value, key);
+				m.put(key, value);
+			}
+		}
+		do {
+			int event = r.nextTag();
+			String currAttr;
+			if (event == START_ELEMENT) {
+				depth++;
+				currAttr = getElementName(r);
+				K key = convertAttrToType(m, currAttr, keyType);
+				V value = parseAnything(valueType, currAttr, r, m, false, pMeta);
+				setName(valueType, value, currAttr);
+				if (valueType.isObject() && m.containsKey(key)) {
+					Object o = m.get(key);
+					if (o instanceof List)
+						((List)o).add(value);
+					else
+						m.put(key, (V)new ObjectList(o, value).setBeanSession(this));
+				} else {
+					m.put(key, value);
+				}
+			} else if (event == END_ELEMENT) {
+				depth--;
+				return m;
+			}
+		} while (depth > 0);
+		return m;
+	}
+
+	private <E> Collection<E> parseIntoCollection(XmlReader r, Collection<E> l,
+			ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception {
+		int depth = 0;
+		int argIndex = 0;
+		do {
+			int event = r.nextTag();
+			if (event == START_ELEMENT) {
+				depth++;
+				ClassMeta<?> elementType = type == null ? object() : type.isArgs() ? type.getArg(argIndex++) : type.getElementType();
+				E value = (E)parseAnything(elementType, null, r, l, false, pMeta);
+				l.add(value);
+			} else if (event == END_ELEMENT) {
+				depth--;
+				return l;
+			}
+		} while (depth > 0);
+		return l;
+	}
+
+	private static int getJsonType(String s) {
+		if (s == null)
+			return UNKNOWN;
+		char c = s.charAt(0);
+		switch(c) {
+			case 'o': return (s.equals("object") ? OBJECT : UNKNOWN);
+			case 'a': return (s.equals("array") ? ARRAY : UNKNOWN);
+			case 's': return (s.equals("string") ? STRING : UNKNOWN);
+			case 'b': return (s.equals("boolean") ? BOOLEAN : UNKNOWN);
+			case 'n': {
+				c = s.charAt(2);
+				switch(c) {
+					case 'm': return (s.equals("number") ? NUMBER : UNKNOWN);
+					case 'l': return (s.equals("null") ? NULL : UNKNOWN);
+				}
+				//return NUMBER;
+			}
+		}
+		return UNKNOWN;
+	}
+
+	private <T> BeanMap<T> parseIntoBean(XmlReader r, BeanMap<T> m) throws Exception {
+		BeanMeta<?> bMeta = m.getMeta();
+		XmlBeanMeta xmlMeta = bMeta.getExtendedMeta(XmlBeanMeta.class);
+
+		for (int i = 0; i < r.getAttributeCount(); i++) {
+			String key = getAttributeName(r, i);
+			String val = r.getAttributeValue(i);
+			BeanPropertyMeta bpm = xmlMeta.getPropertyMeta(key);
+			if (bpm == null) {
+				if (xmlMeta.getAttrsProperty() != null) {
+					xmlMeta.getAttrsProperty().add(m, key, key, val);
+				} else {
+					Location l = r.getLocation();
+					onUnknownProperty(r.getPipe(), key, m, l.getLineNumber(), l.getColumnNumber());
+				}
+			} else {
+				bpm.set(m, key, val);
+			}
+		}
+
+		BeanPropertyMeta cp = xmlMeta.getContentProperty();
+		XmlFormat cpf = xmlMeta.getContentFormat();
+		boolean trim = cp == null || ! cpf.isOneOf(MIXED_PWS, TEXT_PWS);
+		ClassMeta<?> cpcm = (cp == null ? object() : cp.getClassMeta());
+		StringBuilder sb = null;
+		BeanRegistry breg = cp == null ? null : cp.getBeanRegistry();
+		LinkedList<Object> l = null;
+
+		int depth = 0;
+		do {
+			int event = r.next();
+			String currAttr;
+			// We only care about text in MIXED mode.
+			// Ignore if in ELEMENTS mode.
+			if (event == CHARACTERS) {
+				if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) {
+					if (cpcm.isCollectionOrArray()) {
+						if (l == null)
+							l = new LinkedList<Object>();
+						l.add(getText(r, false));
+					} else {
+						cp.set(m, null, getText(r, trim));
+					}
+				} else if (cpf != ELEMENTS) {
+					String s = getText(r, trim);
+					if (s != null) {
+						if (sb == null)
+							sb = getStringBuilder();
+						sb.append(s);
+					}
+				} else {
+					// Do nothing...we're in ELEMENTS mode.
+				}
+			} else if (event == START_ELEMENT) {
+				if (cp != null && cpf.isOneOf(TEXT, TEXT_PWS)) {
+					String s = parseText(r);
+					if (s != null) {
+						if (sb == null)
+							sb = getStringBuilder();
+						sb.append(s);
+					}
+					depth--;
+				} else if (cpf == XMLTEXT) {
+					if (sb == null)
+						sb = getStringBuilder();
+					sb.append(getElementAsString(r));
+					depth++;
+				} else if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) {
+					if (isWhitespaceElement(r) && (breg == null || ! breg.hasName(r.getLocalName()))) {
+						if (cpcm.isCollectionOrArray()) {
+							if (l == null)
+								l = new LinkedList<Object>();
+							l.add(parseWhitespaceElement(r));
+						} else {
+							cp.set(m, null, parseWhitespaceElement(r));
+						}
+					} else {
+						if (cpcm.isCollectionOrArray()) {
+							if (l == null)
+								l = new LinkedList<Object>();
+							l.add(parseAnything(cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp));
+						} else {
+							cp.set(m, null, parseAnything(cpcm, cp.getName(), r, m.getBean(false), false, cp));
+						}
+					}
+				} else if (cp != null && cpf == ELEMENTS) {
+					cp.add(m, null, parseAnything(cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp));
+				} else {
+					currAttr = getElementName(r);
+					BeanPropertyMeta pMeta = xmlMeta.getPropertyMeta(currAttr);
+					if (pMeta == null) {
+						Location loc = r.getLocation();
+						onUnknownProperty(r.getPipe(), currAttr, m, loc.getLineNumber(), loc.getColumnNumber());
+						skipCurrentTag(r);
+					} else {
+						setCurrentProperty(pMeta);
+						XmlFormat xf = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
+						if (xf == COLLAPSED) {
+							ClassMeta<?> et = pMeta.getClassMeta().getElementType();
+							Object value = parseAnything(et, currAttr, r, m.getBean(false), false, pMeta);
+							setName(et, value, currAttr);
+							pMeta.add(m, currAttr, value);
+						} else if (xf == ATTR)  {
+							pMeta.set(m, currAttr, getAttributeValue(r, 0));
+							r.nextTag();
+						} else {
+							ClassMeta<?> cm = pMeta.getClassMeta();
+							Object value = parseAnything(cm, currAttr, r, m.getBean(false), false, pMeta);
+							setName(cm, value, currAttr);
+							pMeta.set(m, currAttr, value);
+						}
+						setCurrentProperty(null);
+					}
+				}
+			} else if (event == END_ELEMENT) {
+				if (depth > 0) {
+					if (cpf == XMLTEXT) {
+						if (sb == null)
+							sb = getStringBuilder();
+						sb.append(getElementAsString(r));
+					}
+					else
+						throw new ParseException("End element found where one was not expected.  {0}", XmlUtils.toReadableEvent(r));
+				}
+				depth--;
+			} else {
+				throw new ParseException("Unexpected event type: {0}", XmlUtils.toReadableEvent(r));
+			}
+		} while (depth >= 0);
+
+		if (sb != null && cp != null)
+			cp.set(m, null, sb.toString());
+		else if (l != null && cp != null)
+			cp.set(m, null, XmlUtils.collapseTextNodes(l));
+
+		returnStringBuilder(sb);
+		return m;
+	}
+
+	private static void skipCurrentTag(XmlReader r) throws XMLStreamException {
+		int depth = 1;
+		do {
+			int event = r.next();
+			if (event == START_ELEMENT)
+				depth++;
+			else if (event == END_ELEMENT)
+				depth--;
+		} while (depth > 0);
+	}
+
+	private Object getUnknown(XmlReader r) throws Exception {
+		if (r.getEventType() != START_ELEMENT) {
+			throw new XmlParseException(r.getLocation(), "Parser must be on START_ELEMENT to read next text.");
+		}
+		ObjectMap m = null;
+
+		// If this element has attributes, then it's always an ObjectMap.
+		if (r.getAttributeCount() > 0) {
+			m = new ObjectMap(this);
+			for (int i = 0; i < r.getAttributeCount(); i++) {
+				String key = getAttributeName(r, i);
+				String val = r.getAttributeValue(i);
+				if (! key.equals(getBeanTypePropertyName(null)))
+					m.put(key, val);
+			}
+		}
+		int eventType = r.next();
+		StringBuilder sb = getStringBuilder();
+		while (eventType != END_ELEMENT) {
+			if (eventType == CHARACTERS || eventType == CDATA || eventType == SPACE || eventType == ENTITY_REFERENCE) {
+				sb.append(r.getText());
+			} else if (eventType == PROCESSING_INSTRUCTION || eventType == COMMENT) {
+				// skipping
+			} else if (eventType == END_DOCUMENT) {
+				throw new XmlParseException(r.getLocation(), "Unexpected end of document when reading element text content");
+			} else if (eventType == START_ELEMENT) {
+				// Oops...this has an element in it.
+				// Parse it as a map.
+				if (m == null)
+					m = new ObjectMap(this);
+				int depth = 0;
+				do {
+					int event = (eventType == -1 ? r.nextTag() : eventType);
+					String currAttr;
+					if (event == START_ELEMENT) {
+						depth++;
+						currAttr = getElementName(r);
+						String key = convertAttrToType(null, currAttr, string());
+						Object value = parseAnything(object(), currAttr, r, null, false, null);
+						if (m.containsKey(key)) {
+							Object o = m.get(key);
+							if (o instanceof ObjectList)
+								((ObjectList)o).add(value);
+							else
+								m.put(key, new ObjectList(o, value).setBeanSession(this));
+						} else {
+							m.put(key, value);
+						}
+
+					} else if (event == END_ELEMENT) {
+						depth--;
+						break;
+					}
+					eventType = -1;
+				} while (depth > 0);
+				break;
+			} else {
+				throw new XmlParseException(r.getLocation(), "Unexpected event type ''{0}''", eventType);
+			}
+			eventType = r.next();
+		}
+		String s = sb.toString();
+		returnStringBuilder(sb);
+		s = decodeString(s);
+		if (m != null) {
+			if (! s.isEmpty())
+				m.put("contents", s);
+			return m;
+		}
+		return s;
+	}
+
+	private ObjectMap loc(XmlReader r) {
+		return getLastLocation().append("line", r.getLocation().getLineNumber()).append("column", r.getLocation().getColumnNumber());
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java
new file mode 100644
index 0000000..50c0e5e
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java
@@ -0,0 +1,301 @@
+// ***************************************************************************************************************************
+// * 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.xml;
+
+import java.io.*;
+
+import javax.xml.namespace.*;
+import javax.xml.stream.*;
+import javax.xml.stream.util.*;
+
+import org.apache.juneau.parser.*;
+
+/**
+ * Wrapper class around a {@link XMLStreamReader}.
+ *
+ * <p>
+ * The purpose is to encapsulate the reader with the {@link ParserPipe} object so that it can be retrieved for
+ * debugging purposes.
+ */
+public final class XmlReader implements XMLStreamReader {
+
+	private final ParserPipe pipe;
+	private final XMLStreamReader sr;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param pipe The parser input.
+	 * @param validating The value for the {@link XMLInputFactory#IS_VALIDATING} setting.
+	 * @param reporter The value for the {@link XMLInputFactory#REPORTER} setting.
+	 * @param resolver The value for the {@link XMLInputFactory#RESOLVER} setting.
+	 * @param eventAllocator The value for the {@link XMLInputFactory#ALLOCATOR} setting.
+	 * @throws Exception
+	 */
+	protected XmlReader(ParserPipe pipe, boolean validating, XMLReporter reporter, XMLResolver resolver, XMLEventAllocator eventAllocator) throws Exception {
+		this.pipe = pipe;
+		try {
+			Reader r = pipe.getBufferedReader();
+			XMLInputFactory factory = XMLInputFactory.newInstance();
+			factory.setProperty(XMLInputFactory.IS_VALIDATING, validating);
+			factory.setProperty(XMLInputFactory.IS_COALESCING, true);
+			factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true);  // This usually has no effect anyway.
+			if (factory.isPropertySupported(XMLInputFactory.REPORTER) && reporter != null)
+				factory.setProperty(XMLInputFactory.REPORTER, reporter);
+			if (factory.isPropertySupported(XMLInputFactory.RESOLVER) && resolver != null)
+				factory.setProperty(XMLInputFactory.RESOLVER, resolver);
+			if (factory.isPropertySupported(XMLInputFactory.ALLOCATOR) && eventAllocator != null)
+				factory.setProperty(XMLInputFactory.ALLOCATOR, eventAllocator);
+			sr = factory.createXMLStreamReader(r);
+			sr.nextTag();
+		} catch (Error e) {
+			throw new ParseException(e.getLocalizedMessage());
+		} catch (XMLStreamException e) {
+			throw new ParseException(e);
+		}
+	}
+
+	/**
+	 * Returns the pipe passed into the constructor.
+	 *
+	 * @return The pipe passed into the constructor.
+	 */
+	public ParserPipe getPipe() {
+		return pipe;
+	}
+
+	@Override /* XMLStreamReader */
+	public void close() throws XMLStreamException {
+		sr.close();
+	}
+
+	@Override /* XMLStreamReader */
+	public int getAttributeCount() {
+		return sr.getAttributeCount();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getAttributeLocalName(int index) {
+		return sr.getAttributeLocalName(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public QName getAttributeName(int index) {
+		return sr.getAttributeName(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getAttributeNamespace(int index) {
+		return sr.getAttributeNamespace(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getAttributePrefix(int index) {
+		return sr.getAttributePrefix(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getAttributeType(int index) {
+		return sr.getAttributeType(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getAttributeValue(int index) {
+		return sr.getAttributeValue(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getAttributeValue(String namespaceURI, String localName) {
+		return sr.getAttributeValue(namespaceURI, localName);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getCharacterEncodingScheme() {
+		return sr.getCharacterEncodingScheme();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getElementText() throws XMLStreamException {
+		return sr.getElementText();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getEncoding() {
+		return sr.getEncoding();
+	}
+
+	@Override /* XMLStreamReader */
+	public int getEventType() {
+		return sr.getEventType();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getLocalName() {
+		return sr.getLocalName();
+	}
+
+	@Override /* XMLStreamReader */
+	public Location getLocation() {
+		return sr.getLocation();
+	}
+
+	@Override /* XMLStreamReader */
+	public QName getName() {
+		return sr.getName();
+	}
+
+	@Override /* XMLStreamReader */
+	public NamespaceContext getNamespaceContext() {
+		return sr.getNamespaceContext();
+	}
+
+	@Override /* XMLStreamReader */
+	public int getNamespaceCount() {
+		return sr.getNamespaceCount();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getNamespacePrefix(int index) {
+		return sr.getNamespacePrefix(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getNamespaceURI() {
+		return sr.getNamespaceURI();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getNamespaceURI(String prefix) {
+		return sr.getNamespaceURI(prefix);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getNamespaceURI(int index) {
+		return sr.getNamespaceURI(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getPIData() {
+		return sr.getPIData();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getPITarget() {
+		return sr.getPITarget();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getPrefix() {
+		return sr.getPrefix();
+	}
+
+	@Override /* XMLStreamReader */
+	public Object getProperty(String name) throws IllegalArgumentException {
+		return sr.getProperty(name);
+	}
+
+	@Override /* XMLStreamReader */
+	public String getText() {
+		return sr.getText();
+	}
+
+	@Override /* XMLStreamReader */
+	public char[] getTextCharacters() {
+		return sr.getTextCharacters();
+	}
+
+	@Override /* XMLStreamReader */
+	public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
+		return sr.getTextCharacters(sourceStart, target, targetStart, length);
+	}
+
+	@Override /* XMLStreamReader */
+	public int getTextLength() {
+		return sr.getTextLength();
+	}
+
+	@Override /* XMLStreamReader */
+	public int getTextStart() {
+		return sr.getTextStart();
+	}
+
+	@Override /* XMLStreamReader */
+	public String getVersion() {
+		return sr.getVersion();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean hasName() {
+		return sr.hasName();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean hasNext() throws XMLStreamException {
+		return sr.hasNext();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean hasText() {
+		return sr.hasText();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean isAttributeSpecified(int index) {
+		return sr.isAttributeSpecified(index);
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean isCharacters() {
+		return sr.isCharacters();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean isEndElement() {
+		return sr.isEndElement();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean isStandalone() {
+		return sr.isStandalone();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean isStartElement() {
+		return sr.isStartElement();
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean isWhiteSpace() {
+		return sr.isWhiteSpace();
+	}
+
+	@Override /* XMLStreamReader */
+	public int next() throws XMLStreamException {
+		return sr.next();
+	}
+
+	@Override /* XMLStreamReader */
+	public int nextTag() throws XMLStreamException {
+		return sr.nextTag();
+	}
+
+	@Override /* XMLStreamReader */
+	public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
+		sr.require(type, namespaceURI, localName);
+	}
+
+	@Override /* XMLStreamReader */
+	public boolean standaloneSet() {
+		return sr.standaloneSet();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java
index 34cbab0..4c1e89e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java
@@ -42,18 +42,11 @@ public class XmlSchemaDocSerializer extends XmlSchemaSerializer {
 	 * @param propertyStore The property store containing all the settings for this object.
 	 */
 	public XmlSchemaDocSerializer(PropertyStore propertyStore) {
-		super(propertyStore, null);
+		super(propertyStore);
 	}
 
 	@Override /* Serializer */
-	protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception {
-		XmlSerializerSession s = (XmlSerializerSession)session;
-		XmlWriter w = s.getXmlWriter(out);
-		w.append("<?xml")
-			.attr("version", "1.0")
-			.attr("encoding", "UTF-8")
-			.appendln("?>");
-		w.flush();
-		super.doSerialize(s, out, o);
+	public WriterSerializerSession createSession(SerializerSessionArgs args) {
+		return new XmlSchemaSerializerSession(ctx, args);
 	}
 }


Mime
View raw message