You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/07/28 18:22:17 UTC

[02/12] incubator-juneau git commit: Allow serializer and parser sessions to be reused.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializerSession.java
new file mode 100644
index 0000000..23429a4
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializerSession.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 XmlSchemaDocSerializer}.
+ *
+ * <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 XmlSchemaDocSerializerSession extends XmlSchemaSerializerSession {
+
+	/**
+	 * 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 XmlSchemaDocSerializerSession(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/XmlSchemaSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
index c1af712..26ba629 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
@@ -12,26 +12,9 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.xml;
 
-import static org.apache.juneau.xml.annotation.XmlFormat.*;
-import static org.apache.juneau.internal.ArrayUtils.*;
-
-
-import java.io.*;
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.regex.*;
-
-import javax.xml.*;
-import javax.xml.transform.stream.*;
-import javax.xml.validation.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.http.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.xml.annotation.*;
-import org.w3c.dom.bootstrap.*;
-import org.w3c.dom.ls.*;
 
 /**
  * Serializes POJO metadata to HTTP responses as XML.
@@ -58,540 +41,17 @@ import org.w3c.dom.ls.*;
 @Produces(value="text/xml+schema",contentType="text/xml")
 public class XmlSchemaSerializer extends XmlSerializer {
 
-	private final XmlSerializerContext ctx;
-
 	/**
 	 * Constructor.
 	 *
 	 * @param propertyStore Initialize with the specified config property store.
 	 */
 	public XmlSchemaSerializer(PropertyStore propertyStore) {
-		this(propertyStore, null);
-	}
-
-	/**
-	 * Constructor
-	 *
-	 * @param propertyStore The property store containing all the settings for this object.
-	 * @param overrideProperties A set of overridden settings, typically defined by the class itself.
-	 */
-	public XmlSchemaSerializer(PropertyStore propertyStore, Map<String,Object> overrideProperties) {
-		super(propertyStore);
-		this.ctx = this.propertyStore.create(overrideProperties).getContext(XmlSerializerContext.class);
-	}
-
-	@Override /* XmlSerializer */
-	protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception {
-		XmlSerializerSession s = (XmlSerializerSession)session;
-
-		if (s.isEnableNamespaces() && s.isAutoDetectNamespaces())
-			findNsfMappings(s, o);
-
-		Namespace xs = s.getXsNamespace();
-		Namespace[] allNs = append(new Namespace[]{s.getDefaultNamespace()}, s.getNamespaces());
-
-		Schemas schemas = new Schemas(s, xs, s.getDefaultNamespace(), allNs);
-		schemas.process(s, o);
-		schemas.serializeTo(out.getWriter());
-	}
-
-	/**
-	 * Returns an XML-Schema validator based on the output returned by {@link #doSerialize(SerializerSession, SerializerOutput, Object)};
-	 *
-	 * @param session
-	 * 	The serializer session object return by {@link #createSession(ObjectMap, Method, Locale, TimeZone,
-	 * 	MediaType, UriContext)}.
-	 * 	Can be <jk>null</jk>.
-	 * @param out The target writer.
-	 * @param o The object to serialize.
-	 * @return The new validator.
-	 * @throws Exception If a problem was detected in the XML-Schema output produced by this serializer.
-	 */
-	public Validator getValidator(SerializerSession session, SerializerOutput out, Object o) throws Exception {
-		doSerialize(session, out, o);
-		String xmlSchema = out.getWriter().toString();
-
-		// create a SchemaFactory capable of understanding WXS schemas
-		SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-
-		if (xmlSchema.indexOf('\u0000') != -1) {
-
-			// Break it up into a map of namespaceURI->schema document
-			final Map<String,String> schemas = new HashMap<String,String>();
-			String[] ss = xmlSchema.split("\u0000");
-			xmlSchema = ss[0];
-			for (String s : ss) {
-				Matcher m = pTargetNs.matcher(s);
-				if (m.find())
-					schemas.put(m.group(1), s);
-			}
-
-			// Create a custom resolver
-			factory.setResourceResolver(
-				new LSResourceResolver() {
-
-					@Override /* LSResourceResolver */
-					public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
-
-						String schema = schemas.get(namespaceURI);
-						if (schema == null)
-							throw new FormattedRuntimeException("No schema found for namespaceURI ''{0}''", namespaceURI);
-
-						try {
-							DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
-							DOMImplementationLS domImplementationLS = (DOMImplementationLS)registry.getDOMImplementation("LS 3.0");
-							LSInput in = domImplementationLS.createLSInput();
-							in.setCharacterStream(new StringReader(schema));
-							in.setSystemId(systemId);
-							return in;
-
-						} catch (Exception e) {
-							throw new RuntimeException(e);
-						}
-					}
-				}
-			);
-		}
-		return factory.newSchema(new StreamSource(new StringReader(xmlSchema))).newValidator();
-	}
-
-	private static Pattern pTargetNs = Pattern.compile("targetNamespace=['\"]([^'\"]+)['\"]");
-
-
-	/* An instance of a global element, global attribute, or XML type to be serialized. */
-	private static class QueueEntry {
-		Namespace ns;
-		String name;
-		ClassMeta<?> cm;
-		QueueEntry(Namespace ns, String name, ClassMeta<?> cm) {
-			this.ns = ns;
-			this.name = name;
-			this.cm = cm;
-		}
-	}
-
-	/* An encapsulation of all schemas present in the metamodel of the serialized object. */
-	private class Schemas extends LinkedHashMap<Namespace,Schema> {
-
-		private static final long serialVersionUID = 1L;
-
-		private Namespace defaultNs;
-		private LinkedList<QueueEntry>
-			elementQueue = new LinkedList<QueueEntry>(),
-			attributeQueue = new LinkedList<QueueEntry>(),
-			typeQueue = new LinkedList<QueueEntry>();
-
-		private Schemas(XmlSerializerSession session, Namespace xs, Namespace defaultNs, Namespace[] allNs) throws IOException {
-			this.defaultNs = defaultNs;
-			for (Namespace ns : allNs)
-				put(ns, new Schema(session, this, xs, ns, defaultNs, allNs));
-		}
-
-		private Schema getSchema(Namespace ns) {
-			if (ns == null)
-				ns = defaultNs;
-			Schema s = get(ns);
-			if (s == null)
-				throw new FormattedRuntimeException("No schema defined for namespace ''{0}''", ns);
-			return s;
-		}
-
-		private void process(SerializerSession session, Object o) throws IOException {
-			ClassMeta<?> cm = session.getClassMetaForObject(o);
-			Namespace ns = defaultNs;
-			if (cm == null)
-				queueElement(ns, "null", object());
-			else {
-				XmlClassMeta xmlMeta = cm.getExtendedMeta(XmlClassMeta.class);
-				if (cm.getDictionaryName() != null && xmlMeta.getNamespace() != null)
-					ns = xmlMeta.getNamespace();
-				queueElement(ns, cm.getDictionaryName(), cm);
-			}
-			processQueue();
-		}
-
-
-		private void processQueue() throws IOException {
-			boolean b;
-			do {
-				b = false;
-				while (! elementQueue.isEmpty()) {
-					QueueEntry q = elementQueue.removeFirst();
-					b |= getSchema(q.ns).processElement(q.name, q.cm);
-				}
-				while (! typeQueue.isEmpty()) {
-					QueueEntry q = typeQueue.removeFirst();
-					b |= getSchema(q.ns).processType(q.name, q.cm);
-				}
-				while (! attributeQueue.isEmpty()) {
-					QueueEntry q = attributeQueue.removeFirst();
-					b |= getSchema(q.ns).processAttribute(q.name, q.cm);
-				}
-			} while (b);
-		}
-
-		private void queueElement(Namespace ns, String name, ClassMeta<?> cm) {
-			elementQueue.add(new QueueEntry(ns, name, cm));
-		}
-
-		private void queueType(Namespace ns, String name, ClassMeta<?> cm) {
-			if (name == null)
-				name = XmlUtils.encodeElementName(cm);
-			typeQueue.add(new QueueEntry(ns, name, cm));
-		}
-
-		private void queueAttribute(Namespace ns, String name, ClassMeta<?> cm) {
-			attributeQueue.add(new QueueEntry(ns, name, cm));
-		}
-
-		private void serializeTo(Writer w) throws IOException {
-			boolean b = false;
-			for (Schema s : values()) {
-				if (b)
-					w.append('\u0000');
-				w.append(s.toString());
-				b = true;
-			}
-		}
-	}
-
-	/* An encapsulation of a single schema. */
-	private class Schema {
-		private StringWriter sw = new StringWriter();
-		private XmlWriter w;
-		private XmlSerializerSession session;
-		private Namespace defaultNs, targetNs;
-		private Schemas schemas;
-		private Set<String>
-			processedTypes = new HashSet<String>(),
-			processedAttributes = new HashSet<String>(),
-			processedElements = new HashSet<String>();
-
-		public Schema(XmlSerializerSession session, Schemas schemas, Namespace xs, Namespace targetNs, Namespace defaultNs, Namespace[] allNs) throws IOException {
-			this.schemas = schemas;
-			this.defaultNs = defaultNs;
-			this.targetNs = targetNs;
-			this.session = session;
-			w = new XmlWriter(sw, session.isUseWhitespace(), session.getMaxIndent(), session.isTrimStrings(), session.getQuoteChar(), null, true, null);
-			int i = session.getIndent();
-			w.oTag(i, "schema");
-			w.attr("xmlns", xs.getUri());
-			w.attr("targetNamespace", targetNs.getUri());
-			w.attr("elementFormDefault", "qualified");
-			if (targetNs != defaultNs)
-				w.attr("attributeFormDefault", "qualified");
-			for (Namespace ns2 : allNs)
-				w.attr("xmlns", ns2.name, ns2.uri);
-			w.append('>').nl(i);
-			for (Namespace ns : allNs) {
-				if (ns != targetNs) {
-					w.oTag(i+1, "import")
-						.attr("namespace", ns.getUri())
-						.attr("schemaLocation", ns.getName()+".xsd")
-						.append("/>").nl(i+1);
-				}
-			}
-		}
-
-		private boolean processElement(String name, ClassMeta<?> cm) throws IOException {
-			if (processedElements.contains(name))
-				return false;
-			processedElements.add(name);
-
-			ClassMeta<?> ft = cm.getSerializedClassMeta();
-			int i = session.getIndent() + 1;
-			if (name == null)
-				name = getElementName(ft);
-			Namespace ns = first(ft.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
-			String type = getXmlType(ns, ft);
-
-			w.oTag(i, "element")
-				.attr("name", XmlUtils.encodeElementName(name))
-				.attr("type", type)
-				.append('/').append('>').nl(i);
-
-			schemas.queueType(ns, null, ft);
-			schemas.processQueue();
-			return true;
-		}
-
-		private boolean processAttribute(String name, ClassMeta<?> cm) throws IOException {
-			if (processedAttributes.contains(name))
-				return false;
-			processedAttributes.add(name);
-
-			int i = session.getIndent() + 1;
-			String type = getXmlAttrType(cm);
-
-			w.oTag(i, "attribute")
-				.attr("name", name)
-				.attr("type", type)
-				.append('/').append('>').nl(i);
-
-			return true;
-		}
-
-		private boolean processType(String name, ClassMeta<?> cm) throws IOException {
-			if (processedTypes.contains(name))
-				return false;
-			processedTypes.add(name);
-
-			int i = session.getIndent() + 1;
-
-			cm = cm.getSerializedClassMeta();
-			XmlBeanMeta xbm = cm.isBean() ? cm.getBeanMeta().getExtendedMeta(XmlBeanMeta.class) : null;
-
-			w.oTag(i, "complexType")
-				.attr("name", name);
-
-			// This element can have mixed content if:
-			// 	1) It's a generic Object (so it can theoretically be anything)
-			//		2) The bean has a property defined with @XmlFormat.CONTENT.
-			if ((xbm != null && (xbm.getContentFormat() != null && xbm.getContentFormat().isOneOf(TEXT,TEXT_PWS,MIXED,MIXED_PWS,XMLTEXT))) || ! cm.isMapOrBean())
-				w.attr("mixed", "true");
-
-			w.cTag().nl(i);
-
-			if (! (cm.isMapOrBean() || cm.isCollectionOrArray() || (cm.isAbstract() && ! cm.isNumber()) || cm.isObject())) {
-				w.oTag(i+1, "attribute").attr("name", session.getBeanTypePropertyName(cm)).attr("type", "string").ceTag().nl(i+1);
-
-			} else {
-
-				//----- Bean -----
-				if (cm.isBean()) {
-					BeanMeta<?> bm = cm.getBeanMeta();
-
-					boolean hasChildElements = false;
-
-					for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
-						XmlFormat pMetaFormat = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
-						if (pMetaFormat != XmlFormat.ATTR)
-							hasChildElements = true;
-					}
-
-					XmlBeanMeta xbm2 = bm.getExtendedMeta(XmlBeanMeta.class);
-					if (xbm2.getContentProperty() != null && xbm2.getContentFormat() == ELEMENTS) {
-						w.sTag(i+1, "sequence").nl(i+1);
-						w.oTag(i+2, "any")
-							.attr("processContents", "skip")
-							.attr("minOccurs", 0)
-							.ceTag().nl(i+2);
-						w.eTag(i+1, "sequence").nl(i+1);
-
-					} else if (hasChildElements) {
-
-						boolean hasOtherNsElement = false;
-						boolean hasCollapsed = false;
-
-						for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
-							XmlBeanPropertyMeta xmlMeta = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
-							if (xmlMeta.getXmlFormat() != ATTR) {
-								if (xmlMeta.getNamespace() != null) {
-									ClassMeta<?> ct2 = pMeta.getClassMeta();
-									Namespace cNs = first(xmlMeta.getNamespace(), ct2.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
-									// Child element is in another namespace.
-									schemas.queueElement(cNs, pMeta.getName(), ct2);
-									hasOtherNsElement = true;
-								}
-								if (xmlMeta.getXmlFormat() == COLLAPSED)
-									hasCollapsed = true;
-							}
-						}
-
-						if (hasOtherNsElement || hasCollapsed) {
-							// If this bean has any child elements in another namespace,
-							// we need to add an <any> element.
-							w.oTag(i+1, "choice").attr("maxOccurs", "unbounded").cTag().nl(i+1);
-							w.oTag(i+2, "any")
-								.attr("processContents", "skip")
-								.attr("minOccurs", 0)
-								.ceTag().nl(i+2);
-							w.eTag(i+1, "choice").nl(i+1);
-
-						} else {
-							w.sTag(i+1, "all").nl(i+1);
-							for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
-								XmlBeanPropertyMeta xmlMeta = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
-								if (xmlMeta.getXmlFormat() != ATTR) {
-									boolean isCollapsed = xmlMeta.getXmlFormat() == COLLAPSED;
-									ClassMeta<?> ct2 = pMeta.getClassMeta();
-									String childName = pMeta.getName();
-									if (isCollapsed) {
-										if (xmlMeta.getChildName() != null)
-											childName = xmlMeta.getChildName();
-										ct2 = pMeta.getClassMeta().getElementType();
-									}
-									Namespace cNs = first(xmlMeta.getNamespace(), ct2.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
-									if (xmlMeta.getNamespace() == null) {
-										w.oTag(i+2, "element")
-											.attr("name", XmlUtils.encodeElementName(childName), false)
-											.attr("type", getXmlType(cNs, ct2))
-											.attr("minOccurs", 0);
-
-										w.ceTag().nl(i+2);
-									} else {
-										// Child element is in another namespace.
-										schemas.queueElement(cNs, pMeta.getName(), ct2);
-										hasOtherNsElement = true;
-									}
-
-								}
-							}
-							w.eTag(i+1, "all").nl(i+1);
-						}
-
-					}
-
-					for (BeanPropertyMeta pMeta : bm.getExtendedMeta(XmlBeanMeta.class).getAttrProperties().values()) {
-						Namespace pNs = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
-						if (pNs == null)
-							pNs = defaultNs;
-
-						// If the bean attribute has a different namespace than the bean, then it needs to
-						// be added as a top-level entry in the appropriate schema file.
-						if (pNs != targetNs) {
-							schemas.queueAttribute(pNs, pMeta.getName(), pMeta.getClassMeta());
-							w.oTag(i+1, "attribute")
-								//.attr("name", pMeta.getName(), true)
-								.attr("ref", pNs.getName() + ':' + pMeta.getName())
-								.ceTag().nl(i+1);
-						}
-
-						// Otherwise, it's just a plain attribute of this bean.
-						else {
-							w.oTag(i+1, "attribute")
-								.attr("name", pMeta.getName(), true)
-								.attr("type", getXmlAttrType(pMeta.getClassMeta()))
-								.ceTag().nl(i+1);
-						}
-					}
-
-				//----- Collection -----
-				} else if (cm.isCollectionOrArray()) {
-					ClassMeta<?> elementType = cm.getElementType();
-					if (elementType.isObject()) {
-						w.sTag(i+1, "sequence").nl(i+1);
-						w.oTag(i+2, "any")
-							.attr("processContents", "skip")
-							.attr("maxOccurs", "unbounded")
-							.attr("minOccurs", "0")
-							.ceTag().nl(i+2);
-						w.eTag(i+1, "sequence").nl(i+1);
-					} else {
-						Namespace cNs = first(elementType.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
-						schemas.queueType(cNs, null, elementType);
-						w.sTag(i+1, "sequence").nl(i+1);
-						w.oTag(i+2, "any")
-							.attr("processContents", "skip")
-							.attr("maxOccurs", "unbounded")
-							.attr("minOccurs", "0")
-							.ceTag().nl(i+2);
-						w.eTag(i+1, "sequence").nl(i+1);
-					}
-
-				//----- Map -----
-				} else if (cm.isMap() || cm.isAbstract() || cm.isObject()) {
-					w.sTag(i+1, "sequence").nl(i+1);
-					w.oTag(i+2, "any")
-						.attr("processContents", "skip")
-						.attr("maxOccurs", "unbounded")
-						.attr("minOccurs", "0")
-						.ceTag().nl(i+2);
-					w.eTag(i+1, "sequence").nl(i+1);
-				}
-
-				w.oTag(i+1, "attribute")
-					.attr("name", session.getBeanTypePropertyName(null))
-					.attr("type", "string")
-					.ceTag().nl(i+1);
-			}
-
-			w.eTag(i, "complexType").nl(i);
-			schemas.processQueue();
-
-			return true;
-		}
-
-		private String getElementName(ClassMeta<?> cm) {
-			cm = cm.getSerializedClassMeta();
-			String name = cm.getDictionaryName();
-
-			if (name == null) {
-				if (cm.isBoolean())
-					name = "boolean";
-				else if (cm.isNumber())
-					name = "number";
-				else if (cm.isCollectionOrArray())
-					name = "array";
-				else if (! (cm.isMapOrBean() || cm.isCollectionOrArray() || cm.isObject() || cm.isAbstract()))
-					name = "string";
-				else
-					name = "object";
-			}
-			return name;
-		}
-
-		@Override /* Object */
-		public String toString() {
-			try {
-				int i = session.getIndent();
-				w.eTag(i, "schema").nl(i);
-			} catch (IOException e) {
-				throw new RuntimeException(e); // Shouldn't happen.
-			}
-			return sw.toString();
-		}
-
-		private String getXmlType(Namespace currentNs, ClassMeta<?> cm) {
-			String name = null;
-			cm = cm.getSerializedClassMeta();
-			if (currentNs == targetNs) {
-				if (cm.isPrimitive()) {
-					if (cm.isBoolean())
-						name = "boolean";
-					else if (cm.isNumber()) {
-						if (cm.isDecimal())
-							name = "decimal";
-						else
-							name = "integer";
-					}
-				}
-			}
-			if (name == null) {
-				name = XmlUtils.encodeElementName(cm);
-				schemas.queueType(currentNs, name, cm);
-				return currentNs.getName() + ":" + name;
-			}
-
-			return name;
-		}
-	}
-
-	private static <T> T first(T...tt) {
-		for (T t : tt)
-			if (t != null)
-				return t;
-		return null;
-	}
-
-
-	private static String getXmlAttrType(ClassMeta<?> cm) {
-		if (cm.isBoolean())
-			return "boolean";
-		if (cm.isNumber()) {
-			if (cm.isDecimal())
-				return "decimal";
-			return "integer";
-		}
-		return "string";
+		super(propertyStore.copy().append(XmlSerializerContext.XML_enableNamespaces, true));
 	}
 
 	@Override /* Serializer */
-	public XmlSerializerSession createSession(ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
-		// This serializer must always have namespaces enabled.
-		if (op == null)
-			op = new ObjectMap();
-		op.put(XmlSerializerContext.XML_enableNamespaces, true);
-		return new XmlSerializerSession(ctx, op, javaMethod, locale, timeZone, mediaType, uriContext);
+	public WriterSerializerSession createSession(SerializerSessionArgs args) {
+		return new XmlSchemaSerializerSession(ctx, args);
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializerSession.java
new file mode 100644
index 0000000..f3b9120
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializerSession.java
@@ -0,0 +1,551 @@
+// ***************************************************************************************************************************
+// * 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 static org.apache.juneau.internal.ArrayUtils.*;
+import static org.apache.juneau.xml.annotation.XmlFormat.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.xml.*;
+import javax.xml.transform.stream.*;
+import javax.xml.validation.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.xml.annotation.*;
+import org.w3c.dom.bootstrap.*;
+import org.w3c.dom.ls.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link XmlSchemaSerializer}.
+ *
+ * <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 XmlSchemaSerializerSession 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 XmlSchemaSerializerSession(XmlSerializerContext ctx, SerializerSessionArgs args) {
+		super(ctx, args);
+	}
+
+	@Override /* SerializerSession */
+	protected void doSerialize(SerializerPipe out, Object o) throws Exception {
+		if (enableNamespaces && autoDetectNamespaces)
+			findNsfMappings(o);
+
+		Namespace xs = xsNamespace;
+		Namespace[] allNs = append(new Namespace[]{defaultNamespace}, namespaces);
+
+		Schemas schemas = new Schemas(xs, defaultNamespace, allNs);
+		schemas.process(o);
+		schemas.serializeTo(out.getWriter());
+	}
+
+	/**
+	 * Returns an XML-Schema validator based on the output returned by {@link #doSerialize(SerializerPipe, Object)};
+	 *
+	 * @param out The target writer.
+	 * @param o The object to serialize.
+	 * @return The new validator.
+	 * @throws Exception If a problem was detected in the XML-Schema output produced by this serializer.
+	 */
+	public Validator getValidator(SerializerPipe out, Object o) throws Exception {
+		doSerialize(out, o);
+		String xmlSchema = out.getWriter().toString();
+
+		// create a SchemaFactory capable of understanding WXS schemas
+		SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+		if (xmlSchema.indexOf('\u0000') != -1) {
+
+			// Break it up into a map of namespaceURI->schema document
+			final Map<String,String> schemas = new HashMap<String,String>();
+			String[] ss = xmlSchema.split("\u0000");
+			xmlSchema = ss[0];
+			for (String s : ss) {
+				Matcher m = pTargetNs.matcher(s);
+				if (m.find())
+					schemas.put(m.group(1), s);
+			}
+
+			// Create a custom resolver
+			factory.setResourceResolver(
+				new LSResourceResolver() {
+
+					@Override /* LSResourceResolver */
+					public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
+
+						String schema = schemas.get(namespaceURI);
+						if (schema == null)
+							throw new FormattedRuntimeException("No schema found for namespaceURI ''{0}''", namespaceURI);
+
+						try {
+							DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
+							DOMImplementationLS domImplementationLS = (DOMImplementationLS)registry.getDOMImplementation("LS 3.0");
+							LSInput in = domImplementationLS.createLSInput();
+							in.setCharacterStream(new StringReader(schema));
+							in.setSystemId(systemId);
+							return in;
+
+						} catch (Exception e) {
+							throw new RuntimeException(e);
+						}
+					}
+				}
+			);
+		}
+		return factory.newSchema(new StreamSource(new StringReader(xmlSchema))).newValidator();
+	}
+
+	private static Pattern pTargetNs = Pattern.compile("targetNamespace=['\"]([^'\"]+)['\"]");
+
+
+	/* An instance of a global element, global attribute, or XML type to be serialized. */
+	private static class QueueEntry {
+		Namespace ns;
+		String name;
+		ClassMeta<?> cm;
+		QueueEntry(Namespace ns, String name, ClassMeta<?> cm) {
+			this.ns = ns;
+			this.name = name;
+			this.cm = cm;
+		}
+	}
+
+	/* An encapsulation of all schemas present in the metamodel of the serialized object. */
+	private class Schemas extends LinkedHashMap<Namespace,Schema> {
+
+		private static final long serialVersionUID = 1L;
+
+		private Namespace defaultNs;
+		private LinkedList<QueueEntry>
+			elementQueue = new LinkedList<QueueEntry>(),
+			attributeQueue = new LinkedList<QueueEntry>(),
+			typeQueue = new LinkedList<QueueEntry>();
+
+		private Schemas(Namespace xs, Namespace defaultNs, Namespace[] allNs) throws IOException {
+			this.defaultNs = defaultNs;
+			for (Namespace ns : allNs)
+				put(ns, new Schema(this, xs, ns, defaultNs, allNs));
+		}
+
+		private Schema getSchema(Namespace ns) {
+			if (ns == null)
+				ns = defaultNs;
+			Schema s = get(ns);
+			if (s == null)
+				throw new FormattedRuntimeException("No schema defined for namespace ''{0}''", ns);
+			return s;
+		}
+
+		private void process(Object o) throws IOException {
+			ClassMeta<?> cm = getClassMetaForObject(o);
+			Namespace ns = defaultNs;
+			if (cm == null)
+				queueElement(ns, "null", object());
+			else {
+				XmlClassMeta xmlMeta = cm.getExtendedMeta(XmlClassMeta.class);
+				if (cm.getDictionaryName() != null && xmlMeta.getNamespace() != null)
+					ns = xmlMeta.getNamespace();
+				queueElement(ns, cm.getDictionaryName(), cm);
+			}
+			processQueue();
+		}
+
+
+		private void processQueue() throws IOException {
+			boolean b;
+			do {
+				b = false;
+				while (! elementQueue.isEmpty()) {
+					QueueEntry q = elementQueue.removeFirst();
+					b |= getSchema(q.ns).processElement(q.name, q.cm);
+				}
+				while (! typeQueue.isEmpty()) {
+					QueueEntry q = typeQueue.removeFirst();
+					b |= getSchema(q.ns).processType(q.name, q.cm);
+				}
+				while (! attributeQueue.isEmpty()) {
+					QueueEntry q = attributeQueue.removeFirst();
+					b |= getSchema(q.ns).processAttribute(q.name, q.cm);
+				}
+			} while (b);
+		}
+
+		private void queueElement(Namespace ns, String name, ClassMeta<?> cm) {
+			elementQueue.add(new QueueEntry(ns, name, cm));
+		}
+
+		private void queueType(Namespace ns, String name, ClassMeta<?> cm) {
+			if (name == null)
+				name = XmlUtils.encodeElementName(cm);
+			typeQueue.add(new QueueEntry(ns, name, cm));
+		}
+
+		private void queueAttribute(Namespace ns, String name, ClassMeta<?> cm) {
+			attributeQueue.add(new QueueEntry(ns, name, cm));
+		}
+
+		private void serializeTo(Writer w) throws IOException {
+			boolean b = false;
+			for (Schema s : values()) {
+				if (b)
+					w.append('\u0000');
+				w.append(s.toString());
+				b = true;
+			}
+		}
+	}
+
+	/* An encapsulation of a single schema. */
+	private class Schema {
+		private StringWriter sw = new StringWriter();
+		private XmlWriter w;
+		private Namespace defaultNs, targetNs;
+		private Schemas schemas;
+		private Set<String>
+			processedTypes = new HashSet<String>(),
+			processedAttributes = new HashSet<String>(),
+			processedElements = new HashSet<String>();
+
+		public Schema(Schemas schemas, Namespace xs, Namespace targetNs, Namespace defaultNs, Namespace[] allNs) throws IOException {
+			this.schemas = schemas;
+			this.defaultNs = defaultNs;
+			this.targetNs = targetNs;
+			w = new XmlWriter(sw, isUseWhitespace(), getMaxIndent(), isTrimStrings(), getQuoteChar(), null, true, null);
+			int i = indent;
+			w.oTag(i, "schema");
+			w.attr("xmlns", xs.getUri());
+			w.attr("targetNamespace", targetNs.getUri());
+			w.attr("elementFormDefault", "qualified");
+			if (targetNs != defaultNs)
+				w.attr("attributeFormDefault", "qualified");
+			for (Namespace ns2 : allNs)
+				w.attr("xmlns", ns2.name, ns2.uri);
+			w.append('>').nl(i);
+			for (Namespace ns : allNs) {
+				if (ns != targetNs) {
+					w.oTag(i+1, "import")
+						.attr("namespace", ns.getUri())
+						.attr("schemaLocation", ns.getName()+".xsd")
+						.append("/>").nl(i+1);
+				}
+			}
+		}
+
+		private boolean processElement(String name, ClassMeta<?> cm) throws IOException {
+			if (processedElements.contains(name))
+				return false;
+			processedElements.add(name);
+
+			ClassMeta<?> ft = cm.getSerializedClassMeta();
+			if (name == null)
+				name = getElementName(ft);
+			Namespace ns = first(ft.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+			String type = getXmlType(ns, ft);
+
+			w.oTag(indent+1, "element")
+				.attr("name", XmlUtils.encodeElementName(name))
+				.attr("type", type)
+				.append('/').append('>').nl(indent+1);
+
+			schemas.queueType(ns, null, ft);
+			schemas.processQueue();
+			return true;
+		}
+
+		private boolean processAttribute(String name, ClassMeta<?> cm) throws IOException {
+			if (processedAttributes.contains(name))
+				return false;
+			processedAttributes.add(name);
+
+			String type = getXmlAttrType(cm);
+
+			w.oTag(indent+1, "attribute")
+				.attr("name", name)
+				.attr("type", type)
+				.append('/').append('>').nl(indent+1);
+
+			return true;
+		}
+
+		private boolean processType(String name, ClassMeta<?> cm) throws IOException {
+			if (processedTypes.contains(name))
+				return false;
+			processedTypes.add(name);
+
+			int i = indent + 1;
+
+			cm = cm.getSerializedClassMeta();
+			XmlBeanMeta xbm = cm.isBean() ? cm.getBeanMeta().getExtendedMeta(XmlBeanMeta.class) : null;
+
+			w.oTag(i, "complexType")
+				.attr("name", name);
+
+			// This element can have mixed content if:
+			// 	1) It's a generic Object (so it can theoretically be anything)
+			//		2) The bean has a property defined with @XmlFormat.CONTENT.
+			if ((xbm != null && (xbm.getContentFormat() != null && xbm.getContentFormat().isOneOf(TEXT,TEXT_PWS,MIXED,MIXED_PWS,XMLTEXT))) || ! cm.isMapOrBean())
+				w.attr("mixed", "true");
+
+			w.cTag().nl(i);
+
+			if (! (cm.isMapOrBean() || cm.isCollectionOrArray() || (cm.isAbstract() && ! cm.isNumber()) || cm.isObject())) {
+				w.oTag(i+1, "attribute").attr("name", getBeanTypePropertyName(cm)).attr("type", "string").ceTag().nl(i+1);
+
+			} else {
+
+				//----- Bean -----
+				if (cm.isBean()) {
+					BeanMeta<?> bm = cm.getBeanMeta();
+
+					boolean hasChildElements = false;
+
+					for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
+						XmlFormat pMetaFormat = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
+						if (pMetaFormat != XmlFormat.ATTR)
+							hasChildElements = true;
+					}
+
+					XmlBeanMeta xbm2 = bm.getExtendedMeta(XmlBeanMeta.class);
+					if (xbm2.getContentProperty() != null && xbm2.getContentFormat() == ELEMENTS) {
+						w.sTag(i+1, "sequence").nl(i+1);
+						w.oTag(i+2, "any")
+							.attr("processContents", "skip")
+							.attr("minOccurs", 0)
+							.ceTag().nl(i+2);
+						w.eTag(i+1, "sequence").nl(i+1);
+
+					} else if (hasChildElements) {
+
+						boolean hasOtherNsElement = false;
+						boolean hasCollapsed = false;
+
+						for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
+							XmlBeanPropertyMeta xmlMeta = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+							if (xmlMeta.getXmlFormat() != ATTR) {
+								if (xmlMeta.getNamespace() != null) {
+									ClassMeta<?> ct2 = pMeta.getClassMeta();
+									Namespace cNs = first(xmlMeta.getNamespace(), ct2.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+									// Child element is in another namespace.
+									schemas.queueElement(cNs, pMeta.getName(), ct2);
+									hasOtherNsElement = true;
+								}
+								if (xmlMeta.getXmlFormat() == COLLAPSED)
+									hasCollapsed = true;
+							}
+						}
+
+						if (hasOtherNsElement || hasCollapsed) {
+							// If this bean has any child elements in another namespace,
+							// we need to add an <any> element.
+							w.oTag(i+1, "choice").attr("maxOccurs", "unbounded").cTag().nl(i+1);
+							w.oTag(i+2, "any")
+								.attr("processContents", "skip")
+								.attr("minOccurs", 0)
+								.ceTag().nl(i+2);
+							w.eTag(i+1, "choice").nl(i+1);
+
+						} else {
+							w.sTag(i+1, "all").nl(i+1);
+							for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
+								XmlBeanPropertyMeta xmlMeta = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+								if (xmlMeta.getXmlFormat() != ATTR) {
+									boolean isCollapsed = xmlMeta.getXmlFormat() == COLLAPSED;
+									ClassMeta<?> ct2 = pMeta.getClassMeta();
+									String childName = pMeta.getName();
+									if (isCollapsed) {
+										if (xmlMeta.getChildName() != null)
+											childName = xmlMeta.getChildName();
+										ct2 = pMeta.getClassMeta().getElementType();
+									}
+									Namespace cNs = first(xmlMeta.getNamespace(), ct2.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+									if (xmlMeta.getNamespace() == null) {
+										w.oTag(i+2, "element")
+											.attr("name", XmlUtils.encodeElementName(childName), false)
+											.attr("type", getXmlType(cNs, ct2))
+											.attr("minOccurs", 0);
+
+										w.ceTag().nl(i+2);
+									} else {
+										// Child element is in another namespace.
+										schemas.queueElement(cNs, pMeta.getName(), ct2);
+										hasOtherNsElement = true;
+									}
+
+								}
+							}
+							w.eTag(i+1, "all").nl(i+1);
+						}
+
+					}
+
+					for (BeanPropertyMeta pMeta : bm.getExtendedMeta(XmlBeanMeta.class).getAttrProperties().values()) {
+						Namespace pNs = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+						if (pNs == null)
+							pNs = defaultNs;
+
+						// If the bean attribute has a different namespace than the bean, then it needs to
+						// be added as a top-level entry in the appropriate schema file.
+						if (pNs != targetNs) {
+							schemas.queueAttribute(pNs, pMeta.getName(), pMeta.getClassMeta());
+							w.oTag(i+1, "attribute")
+								//.attr("name", pMeta.getName(), true)
+								.attr("ref", pNs.getName() + ':' + pMeta.getName())
+								.ceTag().nl(i+1);
+						}
+
+						// Otherwise, it's just a plain attribute of this bean.
+						else {
+							w.oTag(i+1, "attribute")
+								.attr("name", pMeta.getName(), true)
+								.attr("type", getXmlAttrType(pMeta.getClassMeta()))
+								.ceTag().nl(i+1);
+						}
+					}
+
+				//----- Collection -----
+				} else if (cm.isCollectionOrArray()) {
+					ClassMeta<?> elementType = cm.getElementType();
+					if (elementType.isObject()) {
+						w.sTag(i+1, "sequence").nl(i+1);
+						w.oTag(i+2, "any")
+							.attr("processContents", "skip")
+							.attr("maxOccurs", "unbounded")
+							.attr("minOccurs", "0")
+							.ceTag().nl(i+2);
+						w.eTag(i+1, "sequence").nl(i+1);
+					} else {
+						Namespace cNs = first(elementType.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+						schemas.queueType(cNs, null, elementType);
+						w.sTag(i+1, "sequence").nl(i+1);
+						w.oTag(i+2, "any")
+							.attr("processContents", "skip")
+							.attr("maxOccurs", "unbounded")
+							.attr("minOccurs", "0")
+							.ceTag().nl(i+2);
+						w.eTag(i+1, "sequence").nl(i+1);
+					}
+
+				//----- Map -----
+				} else if (cm.isMap() || cm.isAbstract() || cm.isObject()) {
+					w.sTag(i+1, "sequence").nl(i+1);
+					w.oTag(i+2, "any")
+						.attr("processContents", "skip")
+						.attr("maxOccurs", "unbounded")
+						.attr("minOccurs", "0")
+						.ceTag().nl(i+2);
+					w.eTag(i+1, "sequence").nl(i+1);
+				}
+
+				w.oTag(i+1, "attribute")
+					.attr("name", getBeanTypePropertyName(null))
+					.attr("type", "string")
+					.ceTag().nl(i+1);
+			}
+
+			w.eTag(i, "complexType").nl(i);
+			schemas.processQueue();
+
+			return true;
+		}
+
+		private String getElementName(ClassMeta<?> cm) {
+			cm = cm.getSerializedClassMeta();
+			String name = cm.getDictionaryName();
+
+			if (name == null) {
+				if (cm.isBoolean())
+					name = "boolean";
+				else if (cm.isNumber())
+					name = "number";
+				else if (cm.isCollectionOrArray())
+					name = "array";
+				else if (! (cm.isMapOrBean() || cm.isCollectionOrArray() || cm.isObject() || cm.isAbstract()))
+					name = "string";
+				else
+					name = "object";
+			}
+			return name;
+		}
+
+		@Override /* Object */
+		public String toString() {
+			try {
+				w.eTag(indent, "schema").nl(indent);
+			} catch (IOException e) {
+				throw new RuntimeException(e); // Shouldn't happen.
+			}
+			return sw.toString();
+		}
+
+		private String getXmlType(Namespace currentNs, ClassMeta<?> cm) {
+			String name = null;
+			cm = cm.getSerializedClassMeta();
+			if (currentNs == targetNs) {
+				if (cm.isPrimitive()) {
+					if (cm.isBoolean())
+						name = "boolean";
+					else if (cm.isNumber()) {
+						if (cm.isDecimal())
+							name = "decimal";
+						else
+							name = "integer";
+					}
+				}
+			}
+			if (name == null) {
+				name = XmlUtils.encodeElementName(cm);
+				schemas.queueType(currentNs, name, cm);
+				return currentNs.getName() + ":" + name;
+			}
+
+			return name;
+		}
+	}
+
+	private static <T> T first(T...tt) {
+		for (T t : tt)
+			if (t != null)
+				return t;
+		return null;
+	}
+
+	private static String getXmlAttrType(ClassMeta<?> cm) {
+		if (cm.isBoolean())
+			return "boolean";
+		if (cm.isNumber()) {
+			if (cm.isDecimal())
+				return "decimal";
+			return "integer";
+		}
+		return "string";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index b50dfae..e836a67 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -13,21 +13,12 @@
 package org.apache.juneau.xml;
 
 import static org.apache.juneau.serializer.SerializerContext.*;
-import static org.apache.juneau.xml.XmlSerializer.ContentResult.*;
-import static org.apache.juneau.xml.XmlSerializer.JsonType.*;
 import static org.apache.juneau.xml.XmlSerializerContext.*;
-import static org.apache.juneau.xml.annotation.XmlFormat.*;
-
-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.json.*;
 import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
-import org.apache.juneau.xml.annotation.*;
 
 /**
  * Serializes POJO models to XML.
@@ -130,7 +121,6 @@ import org.apache.juneau.xml.annotation.*;
  * 	<li>{@link SqReadable} - Default serializer, single quotes, whitespace added.
  * </ul>
  */
-@SuppressWarnings({ "rawtypes", "unchecked" })
 @Produces("text/xml")
 public class XmlSerializer extends WriterSerializer {
 
@@ -162,12 +152,7 @@ public class XmlSerializer extends WriterSerializer {
 		 * @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, '\''));
 		}
 	}
 
@@ -180,12 +165,7 @@ public class XmlSerializer extends WriterSerializer {
 		 * @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));
 		}
 	}
 
@@ -199,12 +179,7 @@ public class XmlSerializer extends WriterSerializer {
 		 * @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));
 		}
 	}
 
@@ -217,12 +192,7 @@ public class XmlSerializer extends WriterSerializer {
 		 * @param propertyStore The property store containing all the settings for this object.
 		 */
 		public NsSq(PropertyStore propertyStore) {
-			super(propertyStore);
-		}
-
-		@Override /* CoreObject */
-		protected ObjectMap getOverrideProperties() {
-			return super.getOverrideProperties().append(XML_enableNamespaces, true).append(SERIALIZER_quoteChar, '\'');
+			super(propertyStore.copy().append(XML_enableNamespaces, true).append(SERIALIZER_quoteChar, '\''));
 		}
 	}
 
@@ -235,18 +205,13 @@ public class XmlSerializer extends WriterSerializer {
 		 * @param propertyStore The property store containing all the settings for this object.
 		 */
 		public NsSqReadable(PropertyStore propertyStore) {
-			super(propertyStore);
-		}
-
-		@Override /* CoreObject */
-		protected ObjectMap getOverrideProperties() {
-			return super.getOverrideProperties().append(XML_enableNamespaces, true).append(SERIALIZER_quoteChar, '\'')
-				.append(SERIALIZER_useWhitespace, true);
+			super(propertyStore.copy().append(XML_enableNamespaces, true).append(SERIALIZER_quoteChar, '\'')
+				.append(SERIALIZER_useWhitespace, true));
 		}
 	}
 
 
-	private final XmlSerializerContext ctx;
+	final XmlSerializerContext ctx;
 	private volatile XmlSchemaSerializer schemaSerializer;
 
 	/**
@@ -264,536 +229,6 @@ public class XmlSerializer extends WriterSerializer {
 		return new XmlSerializerBuilder(propertyStore);
 	}
 
-	/**
-	 * Recursively searches for the XML namespaces on the specified POJO and adds them to the serializer context object.
-	 *
-	 * @param session The context that exists for the duration of a single serialization.
-	 * @param o The POJO to check.
-	 * @throws SerializeException
-	 */
-	protected void findNsfMappings(XmlSerializerSession session, Object o) throws SerializeException {
-		ClassMeta<?> aType = null;						// The actual type
-		aType = session.push(null, o, null);
-
-		if (aType != null) {
-			Namespace ns = aType.getExtendedMeta(XmlClassMeta.class).getNamespace();
-			if (ns != null) {
-				if (ns.uri != null)
-					session.addNamespace(ns);
-				else
-					ns = null;
-			}
-		}
-
-		// Handle recursion
-		if (aType != null && ! aType.isPrimitive()) {
-
-			BeanMap<?> bm = null;
-			if (aType.isBeanMap()) {
-				bm = (BeanMap)o;
-			} else if (aType.isBean()) {
-				bm = session.toBeanMap(o);
-			} else if (aType.isDelegate()) {
-				ClassMeta<?> innerType = ((Delegate)o).getClassMeta();
-				Namespace ns = innerType.getExtendedMeta(XmlClassMeta.class).getNamespace();
-				if (ns != null) {
-					if (ns.uri != null)
-						session.addNamespace(ns);
-					else
-						ns = null;
-				}
-
-				if (innerType.isBean()) {
-					for (BeanPropertyMeta bpm : innerType.getBeanMeta().getPropertyMetas()) {
-						ns = bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
-						if (ns != null && ns.uri != null)
-							session.addNamespace(ns);
-					}
-
-				} else if (innerType.isMap()) {
-					for (Object o2 : ((Map)o).values())
-						findNsfMappings(session, o2);
-				} else if (innerType.isCollection()) {
-					for (Object o2 : ((Collection)o))
-						findNsfMappings(session, o2);
-				}
-
-			} else if (aType.isMap()) {
-				for (Object o2 : ((Map)o).values())
-					findNsfMappings(session, o2);
-			} else if (aType.isCollection()) {
-				for (Object o2 : ((Collection)o))
-					findNsfMappings(session, o2);
-			} else if (aType.isArray() && ! aType.getElementType().isPrimitive()) {
-				for (Object o2 : ((Object[])o))
-					findNsfMappings(session, o2);
-			}
-			if (bm != null) {
-				for (BeanPropertyValue p : bm.getValues(session.isTrimNulls())) {
-
-					Namespace ns = p.getMeta().getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
-					if (ns != null && ns.uri != null)
-						session.addNamespace(ns);
-
-					try {
-						findNsfMappings(session, p.getValue());
-					} catch (Throwable x) {
-						// Ignore
-					}
-				}
-			}
-		}
-
-		session.pop();
-	}
-
-	/**
-	 * Workhorse method.
-	 *
-	 * @param session The serializer context.
-	 * @param out The writer to send the output to.
-	 * @param o The object to serialize.
-	 * @param eType The expected type if this is a bean property value being serialized.
-	 * @param elementName The root element name.
-	 * @param elementNamespace The namespace of the element.
-	 * @param addNamespaceUris Flag indicating that namespace URIs need to be added.
-	 * @param format The format to serialize the output to.
-	 * @param isMixed We're serializing mixed content, so don't use whitespace.
-	 * @param preserveWhitespace
-	 * 	<jk>true</jk> if we're serializing {@link XmlFormat#MIXED_PWS} or {@link XmlFormat#TEXT_PWS}.
-	 * @param pMeta The bean property metadata if this is a bean property being serialized.
-	 * @return The same writer passed in so that calls to the writer can be chained.
-	 * @throws Exception If a problem occurred trying to convert the output.
-	 */
-	protected XmlWriter serializeAnything(
-			XmlSerializerSession session,
-			XmlWriter out,
-			Object o,
-			ClassMeta eType,
-			String elementName,
-			Namespace elementNamespace,
-			boolean addNamespaceUris,
-			XmlFormat format,
-			boolean isMixed,
-			boolean preserveWhitespace,
-			BeanPropertyMeta pMeta) throws Exception {
-
-		JsonType type = null;              // The type string (e.g. <type> or <x x='type'>
-		int indent = isMixed ? 0 : session.indent;       // Current indentation
-		ClassMeta<?> aType = null;     // The actual type
-		ClassMeta<?> wType = null;     // The wrapped type (delegate)
-		ClassMeta<?> sType = object(); // The serialized type
-
-		aType = session.push(elementName, o, eType);
-
-		if (eType == null)
-			eType = object();
-
-		// Handle recursion
-		if (aType == null) {
-			o = null;
-			aType = object();
-		}
-
-		if (o != null) {
-
-			if (aType.isDelegate()) {
-				wType = aType;
-				eType = aType = ((Delegate)o).getClassMeta();
-			}
-
-			sType = aType.getSerializedClassMeta();
-
-			// Swap if necessary
-			PojoSwap swap = aType.getPojoSwap();
-			if (swap != null) {
-				o = swap.swap(session, o);
-
-				// If the getSwapClass() method returns Object, we need to figure out
-				// the actual type now.
-				if (sType.isObject())
-					sType = session.getClassMetaForObject(o);
-			}
-		} else {
-			sType = eType.getSerializedClassMeta();
-		}
-
-		// Does the actual type match the expected type?
-		boolean isExpectedType = true;
-		if (o == null || ! eType.same(aType)) {
-			if (eType.isNumber())
-				isExpectedType = aType.isNumber();
-			else if (eType.isMap())
-				isExpectedType = aType.isMap();
-			else if (eType.isCollectionOrArray())
-				isExpectedType = aType.isCollectionOrArray();
-			else
-				isExpectedType = false;
-		}
-
-		String resolvedDictionaryName = isExpectedType ? null : aType.getDictionaryName();
-
-		// Note that the dictionary name may be specified on the actual type or the serialized type.
-		// HTML templates will have them defined on the serialized type.
-		String dictionaryName = aType.getDictionaryName();
-		if (dictionaryName == null)
-			dictionaryName = sType.getDictionaryName();
-
-		// char '\0' is interpreted as null.
-		if (o != null && sType.isChar() && ((Character)o).charValue() == 0)
-			o = null;
-
-		boolean isCollapsed = false;		// If 'true', this is a collection and we're not rendering the outer element.
-
-		// Get the JSON type string.
-		if (o == null) {
-			type = NULL;
-		} else if (sType.isCharSequence() || sType.isChar()) {
-			type = STRING;
-		} else if (sType.isNumber()) {
-			type = NUMBER;
-		} else if (sType.isBoolean()) {
-			type = BOOLEAN;
-		} else if (sType.isMapOrBean()) {
-			isCollapsed = sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED;
-			type = OBJECT;
-		} else if (sType.isCollectionOrArray()) {
-			isCollapsed = (format == COLLAPSED && ! addNamespaceUris);
-			type = ARRAY;
-		} else {
-			type = STRING;
-		}
-
-		if (format.isOneOf(MIXED,MIXED_PWS,TEXT,TEXT_PWS,XMLTEXT) && type.isOneOf(NULL,STRING,NUMBER,BOOLEAN))
-			isCollapsed = true;
-
-		// Is there a name associated with this bean?
-		if (elementName == null && dictionaryName != null) {
-			elementName = dictionaryName;
-			isExpectedType = true;
-		}
-
-		if (session.isEnableNamespaces()) {
-			if (elementNamespace == null)
-				elementNamespace = sType.getExtendedMeta(XmlClassMeta.class).getNamespace();
-			if (elementNamespace == null)
-				elementNamespace = aType.getExtendedMeta(XmlClassMeta.class).getNamespace();
-			if (elementNamespace != null && elementNamespace.uri == null)
-				elementNamespace = null;
-			if (elementNamespace == null)
-				elementNamespace = session.getDefaultNamespace();
-		} else {
-			elementNamespace = null;
-		}
-
-		// Do we need a carriage return after the start tag?
-		boolean cr = o != null && (sType.isMapOrBean() || sType.isCollectionOrArray()) && ! isMixed;
-
-		String en = elementName;
-		if (en == null) {
-			en = type.toString();
-			type = null;
-		}
-		boolean encodeEn = elementName != null;
-		String ns = (elementNamespace == null ? null : elementNamespace.name);
-		String dns = null, elementNs = null;
-		if (session.isEnableNamespaces()) {
-			dns = elementName == null && session.getDefaultNamespace() != null ? session.getDefaultNamespace().name : null;
-			elementNs = elementName == null ? dns : ns;
-			if (elementName == null)
-				elementNamespace = null;
-		}
-
-		// Render the start tag.
-		if (! isCollapsed) {
-			out.oTag(indent, elementNs, en, encodeEn);
-			if (addNamespaceUris) {
-				out.attr((String)null, "xmlns", session.getDefaultNamespace().getUri());
-
-				for (Namespace n : session.getNamespaces())
-					out.attr("xmlns", n.getName(), n.getUri());
-			}
-			if (! isExpectedType) {
-				if (resolvedDictionaryName != null)
-					out.attr(dns, session.getBeanTypePropertyName(eType), resolvedDictionaryName);
-				else if (type != null && type != STRING)
-					out.attr(dns, session.getBeanTypePropertyName(eType), type);
-			}
-			if (o == null) {
-				if ((sType.isBoolean() || sType.isNumber()) && ! sType.isNullable())
-					o = sType.getPrimitiveDefault();
-			}
-
-			if (o != null && ! (sType.isMapOrBean()))
-				out.append('>');
-
-			if (cr && ! (sType.isMapOrBean()))
-				out.nl(indent+1);
-		}
-
-		ContentResult rc = CR_ELEMENTS;
-
-		// Render the tag contents.
-		if (o != null) {
-			if (sType.isUri() || (pMeta != null && pMeta.isUri())) {
-				out.textUri(o);
-			} else if (sType.isCharSequence() || sType.isChar()) {
-				if (format == XMLTEXT)
-					out.append(o);
-				else
-					out.text(o, preserveWhitespace);
-			} else if (sType.isNumber() || sType.isBoolean()) {
-				out.append(o);
-			} else if (sType.isMap() || (wType != null && wType.isMap())) {
-				if (o instanceof BeanMap)
-					rc = serializeBeanMap(session, out, (BeanMap)o, elementNamespace, isCollapsed, isMixed);
-				else
-					rc = serializeMap(session, out, (Map)o, sType, eType.getKeyType(), eType.getValueType(), isMixed);
-			} else if (sType.isBean()) {
-				rc = serializeBeanMap(session, out, session.toBeanMap(o), elementNamespace, isCollapsed, isMixed);
-			} else if (sType.isCollection() || (wType != null && wType.isCollection())) {
-				if (isCollapsed)
-					session.indent--;
-				serializeCollection(session, out, o, sType, eType, pMeta, isMixed);
-				if (isCollapsed)
-					session.indent++;
-			} else if (sType.isArray()) {
-				if (isCollapsed)
-					session.indent--;
-				serializeCollection(session, out, o, sType, eType, pMeta, isMixed);
-				if (isCollapsed)
-					session.indent++;
-			} else {
-				if (format == XMLTEXT)
-					out.append(session.toString(o));
-				else
-					out.text(session.toString(o));
-			}
-		}
-
-		session.pop();
-
-		// Render the end tag.
-		if (! isCollapsed) {
-			if (rc == CR_EMPTY) {
-				if (session.isHtmlMode())
-					out.append('>').eTag(elementNs, en, encodeEn);
-				else
-					out.append('/').append('>');
-			} else if (rc == CR_VOID || o == null) {
-				out.append('/').append('>');
-			}
-			else
-				out.ie(cr && rc != CR_MIXED ? indent : 0).eTag(elementNs, en, encodeEn);
-			if (! isMixed)
-				out.nl(indent);
-		}
-
-		return out;
-	}
-
-	private ContentResult serializeMap(XmlSerializerSession session, XmlWriter out, Map m, ClassMeta<?> sType,
-			ClassMeta<?> eKeyType, ClassMeta<?> eValueType, boolean isMixed) throws Exception {
-
-		m = session.sort(m);
-
-		ClassMeta<?> keyType = eKeyType == null ? sType.getKeyType() : eKeyType;
-		ClassMeta<?> valueType = eValueType == null ? sType.getValueType() : eValueType;
-
-		boolean hasChildren = false;
-		for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
-			Map.Entry e = (Map.Entry)i.next();
-
-			Object k = e.getKey();
-			if (k == null) {
-				k = "\u0000";
-			} else {
-				k = session.generalize(k, keyType);
-				if (session.isTrimStrings() && k instanceof String)
-					k = k.toString().trim();
-			}
-
-			Object value = e.getValue();
-
-			if (! hasChildren) {
-				hasChildren = true;
-				out.append('>').nlIf(! isMixed, session.getIndent());
-			}
-			serializeAnything(session, out, value, valueType, session.toString(k), null, false, XmlFormat.DEFAULT, isMixed, false, null);
-		}
-		return hasChildren ? CR_ELEMENTS : CR_EMPTY;
-	}
-
-	private ContentResult serializeBeanMap(XmlSerializerSession session, XmlWriter out, BeanMap<?> m,
-			Namespace elementNs, boolean isCollapsed, boolean isMixed) throws Exception {
-		boolean hasChildren = false;
-		BeanMeta<?> bm = m.getMeta();
-
-		List<BeanPropertyValue> lp = m.getValues(session.isTrimNulls());
-
-		XmlBeanMeta xbm = bm.getExtendedMeta(XmlBeanMeta.class);
-
-		Set<String>
-			attrs = xbm.getAttrPropertyNames(),
-			elements = xbm.getElementPropertyNames(),
-			collapsedElements = xbm.getCollapsedPropertyNames();
-		String
-			attrsProperty = xbm.getAttrsPropertyName(),
-			contentProperty = xbm.getContentPropertyName();
-
-		XmlFormat cf = null;
-
-		Object content = null;
-		ClassMeta<?> contentType = null;
-		for (BeanPropertyValue p : lp) {
-			String n = p.getName();
-			if (attrs.contains(n) || attrs.contains("*") || n.equals(attrsProperty)) {
-				BeanPropertyMeta pMeta = p.getMeta();
-				ClassMeta<?> cMeta = p.getClassMeta();
-
-				String key = p.getName();
-				Object value = p.getValue();
-				Throwable t = p.getThrown();
-				if (t != null)
-					session.onBeanGetterException(pMeta, t);
-
-				if (session.canIgnoreValue(cMeta, key, value))
-					continue;
-
-				Namespace ns = (session.isEnableNamespaces() && pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() != elementNs ? pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() : null);
-
-				if (pMeta.isUri()  ) {
-					out.attrUri(ns, key, value);
-				} else if (n.equals(attrsProperty)) {
-					if (value instanceof BeanMap) {
-						BeanMap<?> bm2 = (BeanMap)value;
-						for (BeanPropertyValue p2 : bm2.getValues(true)) {
-							String key2 = p2.getName();
-							Object value2 = p2.getValue();
-							Throwable t2 = p2.getThrown();
-							if (t2 != null)
-								session.onBeanGetterException(pMeta, t);
-							out.attr(ns, key2, value2);
-						}
-					} else /* Map */ {
-						Map m2 = (Map)value;
-						for (Map.Entry e : (Set<Map.Entry>)(m2.entrySet())) {
-							out.attr(ns, session.toString(e.getKey()), e.getValue());
-						}
-					}
-				} else {
-					out.attr(ns, key, value);
-				}
-			}
-		}
-
-		boolean
-			hasContent = false,
-			preserveWhitespace = false,
-			isVoidElement = xbm.getContentFormat() == VOID;
-
-		for (BeanPropertyValue p : lp) {
-			BeanPropertyMeta pMeta = p.getMeta();
-			ClassMeta<?> cMeta = p.getClassMeta();
-
-			String n = p.getName();
-			if (n.equals(contentProperty)) {
-				content = p.getValue();
-				contentType = p.getClassMeta();
-				hasContent = true;
-				cf = xbm.getContentFormat();
-				if (cf.isOneOf(MIXED,MIXED_PWS,TEXT,TEXT_PWS,XMLTEXT))
-					isMixed = true;
-				if (cf.isOneOf(MIXED_PWS, TEXT_PWS))
-					preserveWhitespace = true;
-				if (contentType.isCollection() && ((Collection)content).isEmpty())
-					hasContent = false;
-				else if (contentType.isArray() && Array.getLength(content) == 0)
-					hasContent = false;
-			} else if (elements.contains(n) || collapsedElements.contains(n) || elements.contains("*") || collapsedElements.contains("*") ) {
-				String key = p.getName();
-				Object value = p.getValue();
-				Throwable t = p.getThrown();
-				if (t != null)
-					session.onBeanGetterException(pMeta, t);
-
-				if (session.canIgnoreValue(cMeta, key, value))
-					continue;
-
-				if (! hasChildren) {
-					hasChildren = true;
-					out.appendIf(! isCollapsed, '>').nlIf(! isMixed, session.getIndent());
-				}
-
-				XmlBeanPropertyMeta xbpm = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
-				serializeAnything(session, out, value, cMeta, key, xbpm.getNamespace(), false, xbpm.getXmlFormat(), isMixed, false, pMeta);
-			}
-		}
-		if (! hasContent)
-			return (hasChildren ? CR_ELEMENTS : isVoidElement ? CR_VOID : CR_EMPTY);
-		out.append('>').nlIf(! isMixed, session.getIndent());
-
-		// Serialize XML content.
-		if (content != null) {
-			if (contentType == null) {
-			} else if (contentType.isCollection()) {
-				Collection c = (Collection)content;
-				for (Iterator i = c.iterator(); i.hasNext();) {
-					Object value = i.next();
-					serializeAnything(session, out, value, contentType.getElementType(), null, null, false, cf, isMixed, preserveWhitespace, null);
-				}
-			} else if (contentType.isArray()) {
-				Collection c = toList(Object[].class, content);
-				for (Iterator i = c.iterator(); i.hasNext();) {
-					Object value = i.next();
-					serializeAnything(session, out, value, contentType.getElementType(), null, null, false, cf, isMixed, preserveWhitespace, null);
-				}
-			} else {
-				serializeAnything(session, out, content, contentType, null, null, false, cf, isMixed, preserveWhitespace, null);
-			}
-		} else {
-			if (! session.isTrimNulls()) {
-				if (! isMixed)
-					out.i(session.indent);
-				out.text(content);
-				if (! isMixed)
-					out.nl(session.indent);
-			}
-		}
-		return isMixed ? CR_MIXED : CR_ELEMENTS;
-	}
-
-	private XmlWriter serializeCollection(XmlSerializerSession session, XmlWriter out, Object in, ClassMeta<?> sType,
-			ClassMeta<?> eType, BeanPropertyMeta ppMeta, boolean isMixed) throws Exception {
-
-		ClassMeta<?> seType = sType.getElementType();
-		if (seType == null)
-			seType = session.object();
-		ClassMeta<?> eeType = eType.getElementType();
-
-		Collection c = (sType.isCollection() ? (Collection)in : toList(sType.getInnerClass(), in));
-
-		c = session.sort(c);
-
-		String type2 = null;
-		if (sType != eType)
-			type2 = sType.getDictionaryName();
-
-		String eName = type2;
-		Namespace eNs = null;
-
-		if (ppMeta != null) {
-			XmlBeanPropertyMeta xbpm = ppMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
-			eName = xbpm.getChildName();
-			eNs = xbpm.getNamespace();
-		}
-
-		for (Iterator i = c.iterator(); i.hasNext();) {
-			Object value = i.next();
-			serializeAnything(session, out, value, eeType, eName, eNs, false, XmlFormat.DEFAULT, isMixed, false, null);
-		}
-		return out;
-	}
 
 	/**
 	 * Returns the schema serializer based on the settings of this serializer.
@@ -801,57 +236,12 @@ public class XmlSerializer extends WriterSerializer {
 	 */
 	public XmlSerializer getSchemaSerializer() {
 		if (schemaSerializer == null)
-			schemaSerializer = new XmlSchemaSerializer(propertyStore, getOverrideProperties());
+			schemaSerializer = new XmlSchemaSerializer(propertyStore);
 		return schemaSerializer;
 	}
 
-	static enum JsonType {
-		STRING("string"),BOOLEAN("boolean"),NUMBER("number"),ARRAY("array"),OBJECT("object"),NULL("null");
-
-		private final String value;
-		private JsonType(String value) {
-			this.value = value;
-		}
-
-		@Override
-		public String toString() {
-			return value;
-		}
-
-		boolean isOneOf(JsonType...types) {
-			for (JsonType type : types)
-				if (type == this)
-					return true;
-			return false;
-		}
-	}
-
-	/**
-	 * Identifies what the contents were of a serialized bean.
-	 */
-	static enum ContentResult {
-		CR_VOID,      // No content...append "/>" to the start tag.
-		CR_EMPTY,     // No content...append "/>" to the start tag if XML, "/></end>" if HTML.
-		CR_MIXED,     // Mixed content...don't add whitespace.
-		CR_ELEMENTS   // Elements...use normal whitespace rules.
-	}
-
-
-	//--------------------------------------------------------------------------------
-	// Entry point methods
-	//--------------------------------------------------------------------------------
-
-	@Override /* Serializer */
-	protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception {
-		XmlSerializerSession s = (XmlSerializerSession)session;
-		if (s.isEnableNamespaces() && s.isAutoDetectNamespaces())
-			findNsfMappings(s, o);
-		serializeAnything(s, s.getXmlWriter(out), o, s.getExpectedRootType(o), null, null, s.isEnableNamespaces() && s.isAddNamespaceUrlsToRoot(), XmlFormat.DEFAULT, false, false, null);
-	}
-
 	@Override /* Serializer */
-	public XmlSerializerSession createSession(ObjectMap op, Method javaMethod, Locale locale,
-			TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
-		return new XmlSerializerSession(ctx, op, javaMethod, locale, timeZone, mediaType, uriContext);
+	public WriterSerializerSession createSession(SerializerSessionArgs args) {
+		return new XmlSerializerSession(ctx, args);
 	}
 }