http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/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
new file mode 100644
index 0000000..5c567e8
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java
@@ -0,0 +1,64 @@
+/***************************************************************************************************************************
+ * 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.xml.XmlSerializerContext.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Serializes POJOs to HTTP responses as XML.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Accept</code> types: <code>text/xml</code>
+ * <p>
+ *     Produces <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     Same as {@link XmlSerializer}, except prepends <code><xt>&lt;?xml</xt> 
<xa>version</xa>=<xs>'1.0'</xs> 
<xa>encoding</xa>=<xs>'UTF-8'</xs><xt>?&gt;</xt></code> to the response
+ *     to make it a valid XML document.
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+public class XmlDocSerializer extends XmlSerializer {
+
+       /** Default serializer without namespaces. */
+       @Produces(value="text/xml+simple",contentType="text/xml")
+       public static class Simple extends XmlDocSerializer {
+               /** Constructor */
+               public Simple() {
+                       setProperty(XML_enableNamespaces, false);
+               }
+       }
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       @Override /* Serializer */
+       protected void doSerialize(SerializerSession session, Object o) throws 
Exception {
+               XmlSerializerSession s = (XmlSerializerSession)session;
+               XmlWriter w = s.getWriter();
+               w.append("<?xml")
+                       .attr("version", "1.0")
+                       .attr("encoding", "UTF-8")
+                       .appendln("?>");
+               super.doSerialize(s, o);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/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
new file mode 100644
index 0000000..0ed36b9
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java
@@ -0,0 +1,523 @@
+/***************************************************************************************************************************
+ * 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 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 org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+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.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     See the {@link XmlSerializer} class for a description of 
Juneau-generated XML.
+ *
+ *
+ * <h6 class='topic'>Configurable properties</h6>
+ * <p>
+ *     This class has the following properties associated with it:
+ * <ul>
+ *     <li>{@link XmlParserContext}
+ *     <li>{@link BeanContext}
+ * </ul>
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+@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().lock();
+
+       private static final int UNKNOWN=0, OBJECT=1, ARRAY=2, STRING=3, 
NUMBER=4, BOOLEAN=5, NULL=6;
+
+
+       private <T> T parseAnything(XmlParserSession session, ClassMeta<T> nt, 
String currAttr, XMLStreamReader r, Object outer, boolean isRoot) throws 
Exception {
+
+               BeanContext bc = session.getBeanContext();
+               if (nt == null)
+                       nt = (ClassMeta<T>)object();
+               PojoTransform<T,Object> transform = 
(PojoTransform<T,Object>)nt.getPojoTransform();
+               ClassMeta<?> ft = nt.getTransformedClassMeta();
+               session.setCurrentClass(ft);
+
+               String wrapperAttr = (isRoot && 
session.isPreserveRootElement()) ? r.getName().getLocalPart() : null;
+               String typeAttr = r.getAttributeValue(null, "type");
+               int jsonType = getJsonType(typeAttr);
+               String b = r.getAttributeValue(session.getXsiNs(), "nil");
+               if (b == null)
+                       b = r.getAttributeValue(null, "nil");
+               boolean isNull = b != null && b.equals("true");
+               if (jsonType == 0) {
+                       String elementName = 
session.decodeString(r.getLocalName());
+                       if (elementName == null || elementName.equals(currAttr))
+                               jsonType = UNKNOWN;
+                       else
+                               jsonType = getJsonType(elementName);
+               }
+               if (! ft.canCreateNewInstance(outer)) {
+                       String c = r.getAttributeValue(null, "_class");
+                       if (c != null) {
+                               ft = nt = 
(ClassMeta<T>)bc.getClassMetaFromString(c);
+                       }
+               }
+               Object o = null;
+
+               if (jsonType == NULL) {
+                       r.nextTag();    // Discard end tag
+                       return null;
+               }
+               if (isNull) {
+                       while (true) {
+                               int e = r.next();
+                               if (e == END_ELEMENT)
+                                       return null;
+                       }
+               }
+
+               if (ft.isObject()) {
+                       if (jsonType == OBJECT) {
+                               ObjectMap m = new ObjectMap(bc);
+                               parseIntoMap(session, r, m, string(), object());
+                               if (wrapperAttr != null)
+                                       m = new 
ObjectMap(bc).append(wrapperAttr, m);
+                               o = m.cast();
+                       } else if (jsonType == ARRAY)
+                               o = parseIntoCollection(session, r, new 
ObjectList(bc), object());
+                       else if (jsonType == STRING) {
+                               o = session.decodeString(r.getElementText());
+                               if (ft.isChar())
+                                       o = o.toString().charAt(0);
+                       }
+                       else if (jsonType == NUMBER)
+                               o = 
parseNumber(session.decodeLiteral(r.getElementText()), null);
+                       else if (jsonType == BOOLEAN)
+                               o = 
Boolean.parseBoolean(session.decodeLiteral(r.getElementText()));
+                       else if (jsonType == UNKNOWN)
+                               o = getUnknown(session, r);
+               } else if (ft.isBoolean()) {
+                       o = 
Boolean.parseBoolean(session.decodeLiteral(r.getElementText()));
+               } else if (ft.isCharSequence()) {
+                       o = session.decodeString(r.getElementText());
+               } else if (ft.isChar()) {
+                       o = session.decodeString(r.getElementText()).charAt(0);
+               } else if (ft.isMap()) {
+                       Map m = (ft.canCreateNewInstance(outer) ? 
(Map)ft.newInstance(outer) : new ObjectMap(bc));
+                       o = parseIntoMap(session, r, m, ft.getKeyType(), 
ft.getValueType());
+                       if (wrapperAttr != null)
+                               o = new ObjectMap(bc).append(wrapperAttr, m);
+               } else if (ft.isCollection()) {
+                       Collection l = (ft.canCreateNewInstance(outer) ? 
(Collection)ft.newInstance(outer) : new ObjectList(bc));
+                       o = parseIntoCollection(session, r, l, 
ft.getElementType());
+               } else if (ft.isNumber()) {
+                       o = 
parseNumber(session.decodeLiteral(r.getElementText()), (Class<? extends 
Number>)ft.getInnerClass());
+               } else if (ft.canCreateNewInstanceFromObjectMap(outer)) {
+                       ObjectMap m = new ObjectMap(bc);
+                       parseIntoMap(session, r, m, string(), object());
+                       o = ft.newInstanceFromObjectMap(outer, m);
+               } else if (ft.canCreateNewBean(outer)) {
+                       if (ft.getXmlMeta().getFormat() == XmlFormat.COLLAPSED) 
{
+                               String fieldName = r.getLocalName();
+                               BeanMap m = bc.newBeanMap(outer, 
ft.getInnerClass());
+                               BeanPropertyMeta bpm = 
m.getMeta().getXmlMeta().getPropertyMeta(fieldName);
+                               ClassMeta<?> cm = m.getMeta().getClassMeta();
+                               Object value = parseAnything(session, cm, 
currAttr, r, m.getBean(false), false);
+                               setName(cm, value, currAttr);
+                               bpm.set(m, value);
+                               o = m.getBean();
+                       } else {
+                               BeanMap m = bc.newBeanMap(outer, 
ft.getInnerClass());
+                               o = parseIntoBean(session, r, m).getBean();
+                       }
+               } else if (ft.isArray()) {
+                       ArrayList l = (ArrayList)parseIntoCollection(session, 
r, new ArrayList(), ft.getElementType());
+                       o = bc.toArray(ft, l);
+               } else if (ft.canCreateNewInstanceFromString(outer)) {
+                       o = ft.newInstanceFromString(outer, 
session.decodeString(r.getElementText()));
+               } else if (ft.canCreateNewInstanceFromNumber(outer)) {
+                       o = ft.newInstanceFromNumber(outer, 
parseNumber(session.decodeLiteral(r.getElementText()), 
ft.getNewInstanceFromNumberClass()));
+               } else {
+                       throw new ParseException(session, "Class ''{0}'' could 
not be instantiated.  Reason: ''{1}''", ft.getInnerClass().getName(), 
ft.getNotABeanReason());
+               }
+
+               if (transform != null && o != null)
+                       o = transform.normalize(o, nt);
+
+               if (outer != null)
+                       setParent(nt, 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) 
throws Exception {
+               BeanContext bc = session.getBeanContext();
+               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("type"))) {
+                               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.decodeString(r.getLocalName());
+                               K key = convertAttrToType(session, m, currAttr, 
keyType);
+                               V value = parseAnything(session, valueType, 
currAttr, r, m, false);
+                               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).setBeanContext(bc));
+                               } 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<E> elementType) throws Exception {
+               int depth = 0;
+               do {
+                       int event = r.nextTag();
+                       if (event == START_ELEMENT) {
+                               depth++;
+                               E value = parseAnything(session, elementType, 
null, r, l, false);
+                               l.add(value);
+                       } else if (event == END_ELEMENT) {
+                               depth--;
+                               return l;
+                       }
+               } while (depth > 0);
+               return l;
+       }
+
+       private Object[] doParseArgs(XmlParserSession session, XMLStreamReader 
r, ClassMeta<?>[] argTypes) throws Exception {
+               int depth = 0;
+               Object[] o = new Object[argTypes.length];
+               int i = 0;
+               do {
+                       int event = r.nextTag();
+                       if (event == START_ELEMENT) {
+                               depth++;
+                               o[i] = parseAnything(session, argTypes[i], 
null, r, null, false);
+                               i++;
+                       } else if (event == END_ELEMENT) {
+                               depth--;
+                               return o;
+                       }
+               } while (depth > 0);
+               return o;
+       }
+
+       private 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.getXmlMeta();
+
+               for (int i = 0; i < r.getAttributeCount(); i++) {
+                       String key = 
session.decodeString(r.getAttributeLocalName(i));
+                       String val = r.getAttributeValue(i);
+                       BeanPropertyMeta bpm = xmlMeta.getPropertyMeta(key);
+                       if (bpm == null) {
+                               if (m.getMeta().isSubTyped()) {
+                                       m.put(key, val);
+                               } else {
+                                       Location l = r.getLocation();
+                                       onUnknownProperty(session, key, m, 
l.getLineNumber(), l.getColumnNumber());
+                               }
+                       } else {
+                               bpm.set(m, val);
+                       }
+               }
+
+               BeanPropertyMeta cp = xmlMeta.getXmlContentProperty();
+               if (cp != null) {
+                       XmlContentHandler h = xmlMeta.getXmlContentHandler();
+                       if (h != null) {
+                               h.parse(r, m.getBean());
+                       } else {
+                               String text = r.getElementText();
+                               cp.set(m, session.decodeString(text));
+                       }
+                       return m;
+               }
+
+               int depth = 0;
+               do {
+                       int event = r.nextTag();
+                       String currAttr;
+                       if (event == START_ELEMENT) {
+                               depth++;
+                               currAttr = 
session.decodeString(r.getLocalName());
+                               BeanPropertyMeta pMeta = 
xmlMeta.getPropertyMeta(currAttr);
+                               if (pMeta == null) {
+                                       if (m.getMeta().isSubTyped()) {
+                                               Object value = 
parseAnything(session, string(), currAttr, r, m.getBean(false), false);
+                                               m.put(currAttr, value);
+                                       } else {
+                                               Location l = r.getLocation();
+                                               onUnknownProperty(session, 
currAttr, m, l.getLineNumber(), l.getColumnNumber());
+                                               skipCurrentTag(r);
+                                       }
+                               } else {
+                                       session.setCurrentProperty(pMeta);
+                                       XmlFormat xf = 
pMeta.getXmlMeta().getXmlFormat();
+                                       if (xf == COLLAPSED) {
+                                               ClassMeta<?> et = 
pMeta.getClassMeta().getElementType();
+                                               Object value = 
parseAnything(session, et, currAttr, r, m.getBean(false), false);
+                                               setName(et, value, currAttr);
+                                               pMeta.add(m, value);
+                                       } else if (xf == ATTR)  {
+                                               pMeta.set(m, 
session.decodeString(r.getAttributeValue(0)));
+                                               r.nextTag();
+                                       } else {
+                                               ClassMeta<?> cm = 
pMeta.getClassMeta();
+                                               Object value = 
parseAnything(session, cm, currAttr, r, m.getBean(false), false);
+                                               setName(cm, value, currAttr);
+                                               pMeta.set(m, value);
+                                       }
+                                       session.setCurrentProperty(null);
+                               }
+                       } else if (event == END_ELEMENT) {
+                               depth--;
+                               return m;
+                       }
+               } while (depth > 0);
+               return m;
+       }
+
+       private 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 {
+               BeanContext bc = session.getBeanContext();
+               if (r.getEventType() != XMLStreamConstants.START_ELEMENT) {
+                       throw new XMLStreamException("parser must be on 
START_ELEMENT to read next text", r.getLocation());
+               }
+               ObjectMap m = null;
+
+               // If this element has attributes, then it's always an 
ObjectMap.
+               if (r.getAttributeCount() > 0) {
+                       m = new ObjectMap(bc);
+                       for (int i = 0; i < r.getAttributeCount(); i++) {
+                               String key = 
session.decodeString(r.getAttributeLocalName(i));
+                               String val = r.getAttributeValue(i);
+                               if (! key.equals("type"))
+                                       m.put(key, val);
+                       }
+               }
+               int eventType = r.next();
+               StringBuilder sb = new StringBuilder();
+               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 XMLStreamException("Unexpected end of 
document when reading element text content", r.getLocation());
+                       } else if (eventType == 
XMLStreamConstants.START_ELEMENT) {
+                               // Oops...this has an element in it.
+                               // Parse it as a map.
+                               if (m == null)
+                                       m = new ObjectMap(bc);
+                               int depth = 0;
+                               do {
+                                       int event = (eventType == -1 ? 
r.nextTag() : eventType);
+                                       String currAttr;
+                                       if (event == START_ELEMENT) {
+                                               depth++;
+                                               currAttr = 
session.decodeString(r.getLocalName());
+                                               String key = 
convertAttrToType(session, null, currAttr, string());
+                                               Object value = 
parseAnything(session, object(), currAttr, r, null, false);
+                                               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).setBeanContext(bc));
+                                               } else {
+                                                       m.put(key, value);
+                                               }
+
+                                       } else if (event == END_ELEMENT) {
+                                               depth--;
+                                               break;
+                                       }
+                                       eventType = -1;
+                               } while (depth > 0);
+                               break;
+                       } else {
+                               throw new XMLStreamException("Unexpected event 
type " + eventType, r.getLocation());
+                       }
+                       eventType = r.next();
+               }
+               String s = sb.toString();
+               s = session.decodeString(s);
+               if (m != null) {
+                       if (! s.isEmpty())
+                               m.put("contents", s);
+                       return m;
+               }
+               return s;
+       }
+
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       @Override /* Parser */
+       public XmlParserSession createSession(Object input, ObjectMap 
properties, Method javaMethod, Object outer) {
+               return new XmlParserSession(getContext(XmlParserContext.class), 
getBeanContext(), input, properties, javaMethod, outer);
+       }
+
+       @Override /* Parser */
+       protected <T> T doParse(ParserSession session, ClassMeta<T> type) 
throws Exception {
+               XmlParserSession s = (XmlParserSession)session;
+               type = s.getBeanContext().normalizeClassMeta(type);
+               return parseAnything(s, type, null, s.getXmlStreamReader(), 
s.getOuter(), true);
+       }
+
+       @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 = s.getBeanContext().getMapClassMeta(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 = 
s.getBeanContext().getCollectionClassMeta(c.getClass(), elementType);
+               return parseIntoCollection(s,c, cm.getElementType());
+       }
+
+       @Override /* ReaderParser */
+       protected Object[] doParseArgs(ParserSession session, ClassMeta<?>[] 
argTypes) throws Exception {
+               XmlParserSession s = (XmlParserSession)session;
+               return doParseArgs(s, s.getXmlStreamReader(), argTypes);
+       }
+
+       @Override /* CoreApi */
+       public XmlParser setProperty(String property, Object value) throws 
LockedException {
+               super.setProperty(property, value);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser setProperties(ObjectMap properties) throws 
LockedException {
+               super.setProperties(properties);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser addNotBeanClasses(Class<?>...classes) throws 
LockedException {
+               super.addNotBeanClasses(classes);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser addTransforms(Class<?>...classes) throws 
LockedException {
+               super.addTransforms(classes);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public <T> XmlParser addImplClass(Class<T> interfaceClass, Class<? 
extends T> implClass) throws LockedException {
+               super.addImplClass(interfaceClass, implClass);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser setClassLoader(ClassLoader classLoader) throws 
LockedException {
+               super.setClassLoader(classLoader);
+               return this;
+       }
+
+       @Override /* Lockable */
+       public XmlParser lock() {
+               super.lock();
+               return this;
+       }
+
+       @Override /* Lockable */
+       public XmlParser clone() {
+               try {
+                       XmlParser c = (XmlParser)super.clone();
+                       return c;
+               } catch (CloneNotSupportedException e) {
+                       throw new RuntimeException(e); // Shouldn't happen.
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserContext.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserContext.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserContext.java
new file mode 100644
index 0000000..1957943
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserContext.java
@@ -0,0 +1,156 @@
+/***************************************************************************************************************************
+ * 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 javax.xml.stream.*;
+import javax.xml.stream.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.parser.*;
+
+/**
+ * Configurable properties on the {@link XmlParser} class.
+ * <p>
+ * Context properties are set by calling {@link 
ContextFactory#setProperty(String, Object)} on the context factory
+ * returned {@link CoreApi#getContextFactory()}.
+ * <p>
+ * The following convenience methods are also provided for setting context 
properties:
+ * <ul>
+ *     <li>{@link XmlParser#setProperty(String,Object)}
+ *     <li>{@link XmlParser#setProperties(ObjectMap)}
+ *     <li>{@link XmlParser#addNotBeanClasses(Class[])}
+ *     <li>{@link XmlParser#addTransforms(Class[])}
+ *     <li>{@link XmlParser#addImplClass(Class,Class)}
+ * </ul>
+ * <p>
+ * See {@link ContextFactory} for more information about context properties.
+ *
+ * @author James Bognar ([email protected])
+ */
+public final class XmlParserContext extends ParserContext {
+
+       /**
+        * XMLSchema-instance namespace URI ({@link String}, 
default=<js>"http://www.w3.org/2001/XMLSchema-instance";</js>).
+        * <p>
+        * The XMLSchema namespace.
+        */
+       public static final String XML_xsiNs = "XmlParser.xsiNs";
+
+       /**
+        * Trim whitespace from text elements ({@link Boolean}, 
default=<jk>true</jk>).
+        * <p>
+        * If <jk>true</jk>, whitespace in text elements will be automatically 
trimmed.
+        */
+       public static final String XML_trimWhitespace = 
"XmlParser.trimWhitespace";
+
+       /**
+        * Set validating mode ({@link Boolean}, default=<jk>false</jk>).
+        * <p>
+        * If <jk>true</jk>, XML document will be validated.
+        * See {@link XMLInputFactory#IS_VALIDATING} for more info.
+        */
+       public static final String XML_validating = "XmlParser.validating";
+
+       /**
+        * Set coalescing mode ({@link Boolean}, default=<jk>false</jk>).
+        * <p>
+        * If <jk>true</jk>, XML text elements will be coalesced.
+        * See {@link XMLInputFactory#IS_COALESCING} for more info.
+        */
+       public static final String XML_coalescing = "XmlParser.coalescing";
+
+       /**
+        * Replace entity references ({@link Boolean}, default=<jk>true</jk>).
+        * <p>
+        * If <jk>true</jk>, entity references will be replace during parsing.
+        * See {@link XMLInputFactory#IS_REPLACING_ENTITY_REFERENCES} for more 
info.
+        */
+       public static final String XML_replaceEntityReferences = 
"XmlParser.replaceEntityReferences";
+
+       /**
+        * XML reporter ({@link XMLReporter}, default=<jk>null</jk>).
+        * <p>
+        * Associates an {@link XMLReporter} with this parser.
+        * <p>
+        * Note:  Reporters are not copied to new parsers during a clone.
+        */
+       public static final String XML_reporter = "XmlParser.reporter";
+
+       /**
+        * XML resolver ({@link XMLResolver}, default=<jk>null</jk>).
+        * <p>
+        * Associates an {@link XMLResolver} with this parser.
+        */
+       public static final String XML_resolver = "XmlParser.resolver";
+
+       /**
+        * XML event allocator. ({@link XMLEventAllocator}, 
default=<jk>false</jk>).
+        * <p>
+        * Associates an {@link XMLEventAllocator} with this parser.
+        */
+       public static final String XML_eventAllocator = 
"XmlParser.eventAllocator";
+
+       /**
+        * Preserve root element during generalized parsing ({@link Boolean}, 
default=<jk>false</jk>).
+        * <p>
+        * If <jk>true</jk>, when parsing into a generic {@link ObjectMap}, the 
map will
+        *      contain a single entry whose key is the root element name.
+        *
+        * Example:
+        *      <table class='styled'>
+        *              <tr>
+        *                      <td>XML</td>
+        *                      <td>ObjectMap.toString(), 
preserveRootElement==false</td>
+        *                      <td>ObjectMap.toString(), 
preserveRootElement==true</td>
+        *              </tr>
+        *              <tr>
+        *                      
<td><code><xt>&lt;root&gt;&lt;a&gt;</xt>foobar<xt>&lt;/a&gt;&lt;/root&gt;</xt><code></td>
+        *                      <td><code>{ a:<js>'foobar'</js> }</code></td>
+        *                      <td><code>{ root: { a:<js>'foobar'</js> 
}}</code></td>
+        *              </tr>
+        *      </table>
+        *
+        */
+       public static final String XML_preserveRootElement = 
"XmlParser.preserveRootElement";
+
+       final String xsiNs;
+       final boolean
+               trimWhitespace,
+               validating,
+               coalescing,
+               replaceEntityReferences,
+               preserveRootElement;
+       final XMLReporter reporter;
+       final XMLResolver resolver;
+       final XMLEventAllocator eventAllocator;
+
+       /**
+        * Constructor.
+        * <p>
+        * Typically only called from {@link ContextFactory#getContext(Class)}.
+        *
+        * @param cf The factory that created this context.
+        */
+       public XmlParserContext(ContextFactory cf) {
+               super(cf);
+               xsiNs = cf.getProperty(XML_xsiNs, String.class, 
"http://www.w3.org/2001/XMLSchema-instance";);
+               trimWhitespace = cf.getProperty(XML_trimWhitespace, 
boolean.class, true);
+               validating = cf.getProperty(XML_validating, boolean.class, 
false);
+               coalescing = cf.getProperty(XML_coalescing, boolean.class, 
false);
+               replaceEntityReferences = 
cf.getProperty(XML_replaceEntityReferences, boolean.class, true);
+               preserveRootElement = cf.getProperty(XML_preserveRootElement, 
boolean.class, false);
+               reporter = cf.getProperty(XML_reporter, XMLReporter.class, 
null);
+               resolver = cf.getProperty(XML_resolver, XMLResolver.class, 
null);
+               eventAllocator = cf.getProperty(XML_eventAllocator, 
XMLEventAllocator.class, null);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/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
new file mode 100644
index 0000000..bddd1fd
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java
@@ -0,0 +1,189 @@
+/***************************************************************************************************************************
+ * 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.xml.XmlParserContext.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+
+import javax.xml.stream.*;
+import javax.xml.stream.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+
+/**
+ * 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.
+ *
+ * @author James Bognar ([email protected])
+ */
+public final class XmlParserSession extends ParserSession {
+
+       private final String xsiNs;
+       private final boolean
+               trimWhitespace,
+               validating,
+               coalescing,
+               replaceEntityReferences,
+               preserveRootElement;
+       private final XMLReporter reporter;
+       private final XMLResolver resolver;
+       private final XMLEventAllocator eventAllocator;
+       private XMLStreamReader xmlStreamReader;
+
+       /**
+        * 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 beanContext The bean context being used.
+        * @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.
+        */
+       public XmlParserSession(XmlParserContext ctx, BeanContext beanContext, 
Object input, ObjectMap op, Method javaMethod, Object outer) {
+               super(ctx, beanContext, input, op, javaMethod, outer);
+               if (op == null || op.isEmpty()) {
+                       xsiNs = ctx.xsiNs;
+                       trimWhitespace = ctx.trimWhitespace;
+                       validating = ctx.validating;
+                       coalescing = ctx.coalescing;
+                       replaceEntityReferences = ctx.replaceEntityReferences;
+                       reporter = ctx.reporter;
+                       resolver = ctx.resolver;
+                       eventAllocator = ctx.eventAllocator;
+                       preserveRootElement = ctx.preserveRootElement;
+               } else {
+                       xsiNs = op.getString(XML_xsiNs, ctx.xsiNs);
+                       trimWhitespace = op.getBoolean(XML_trimWhitespace, 
ctx.trimWhitespace);
+                       validating = op.getBoolean(XML_validating, 
ctx.validating);
+                       coalescing = op.getBoolean(XML_coalescing, 
ctx.coalescing);
+                       replaceEntityReferences = 
op.getBoolean(XML_replaceEntityReferences, ctx.replaceEntityReferences);
+                       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);
+               }
+       }
+
+       /**
+        * Returns the {@link XmlParserContext#XML_xsiNs} setting value for 
this session.
+        *
+        * @return The {@link XmlParserContext#XML_xsiNs} setting value for 
this session.
+        */
+       public final String getXsiNs() {
+               return xsiNs;
+       }
+
+       /**
+        * 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.
+        *
+        * @return The new STAX reader.
+        * @throws Exception If problem occurred trying to create reader.
+        */
+       public final XMLStreamReader getXmlStreamReader() throws Exception {
+               try {
+                       Reader r = IOUtils.getBufferedReader(getReader());
+                       XMLInputFactory factory = XMLInputFactory.newInstance();
+                       factory.setProperty(XMLInputFactory.IS_VALIDATING, 
validating);
+                       factory.setProperty(XMLInputFactory.IS_COALESCING, 
coalescing);
+                       
factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, 
replaceEntityReferences);
+                       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;
+       }
+
+       /**
+        * Decodes and trims the specified string.
+        *
+        * @param s The string to be decoded.
+        * @return The decoded string.
+        */
+       public final String decodeString(String s) {
+               if (s == null || s.isEmpty())
+                       return s;
+               if (trimWhitespace)
+                       s = s.trim();
+               s = XmlUtils.decode(s);
+               if (isTrimStrings())
+                       s = s.trim();
+               return s;
+       }
+
+       /**
+        * Decodes the specified literal (e.g. <js>"true"</js>, <js>"123"</js>).
+        * <p>
+        * Unlike <code>decodeString(String)</code>, the input string is ALWAYS 
trimmed before decoding, and
+        *      NEVER trimmed after decoding.
+        *
+        * @param s The string to trim.
+        * @return The trimmed string, or <jk>null</jk> if the string was 
<jk>null</jk>.
+        */
+       public final String decodeLiteral(String s) {
+               if (s == null || s.isEmpty())
+                       return s;
+               s = s.trim();
+               s = XmlUtils.decode(s);
+               return s;
+       }
+
+       /**
+        * Silently closes the XML stream.
+        */
+       @Override /* ParserContext */
+       public void close() throws ParseException {
+               super.close();
+               try {
+                       if (xmlStreamReader != null)
+                               xmlStreamReader.close();
+               } catch (XMLStreamException e) {
+                       // Ignore.
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/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
new file mode 100644
index 0000000..640fbb7
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java
@@ -0,0 +1,67 @@
+/***************************************************************************************************************************
+ * 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.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Serializes POJO metadata to HTTP responses as XML.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Accept</code> types: <code>text/xml+schema</code>
+ * <p>
+ *     Produces <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     Same as {@link XmlSchemaSerializer}, except prepends 
<code><xt>&lt;?xml</xt> <xa>version</xa>=<xs>'1.0'</xs> 
<xa>encoding</xa>=<xs>'UTF-8'</xs><xt>?&gt;</xt></code> to the response
+ *     to make it a valid XML document.
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+public class XmlSchemaDocSerializer extends XmlSchemaSerializer {
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       /**
+        * Constructor.
+        */
+       public XmlSchemaDocSerializer() {}
+
+       /**
+        * Constructor.
+        *
+        * @param cf The context factory to use for creating the context for 
this serializer.
+        */
+       protected XmlSchemaDocSerializer(ContextFactory cf) {
+               super(cf);
+       }
+
+       @Override /* Serializer */
+       protected void doSerialize(SerializerSession session, Object o) throws 
Exception {
+               XmlSerializerSession s = (XmlSerializerSession)session;
+               XmlWriter w = s.getWriter();
+               w.append("<?xml")
+                       .attr("version", "1.0")
+                       .attr("encoding", "UTF-8")
+                       .appendln("?>");
+               super.doSerialize(s, o);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/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
new file mode 100644
index 0000000..7a2c0f4
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaSerializer.java
@@ -0,0 +1,605 @@
+/***************************************************************************************************************************
+ * 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.xml.annotation.XmlFormat.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.text.*;
+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.internal.*;
+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.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Accept</code> types: <code>text/xml+schema</code>
+ * <p>
+ *     Produces <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     Produces the XML-schema representation of the XML produced by the 
{@link XmlSerializer} class with the same properties.
+ *
+ *
+ * <h6 class='topic'>Configurable properties</h6>
+ * <p>
+ *     This class has the following properties associated with it:
+ * <ul>
+ *     <li>{@link XmlSerializerContext}
+ *     <li>{@link BeanContext}
+ * </ul>
+ *
+ * @author James Bognar ([email protected])
+ */
+@Produces(value="text/xml+schema",contentType="text/xml")
+public class XmlSchemaSerializer extends XmlSerializer {
+
+       /**
+        * Constructor
+        */
+       public XmlSchemaSerializer() {
+               super();
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param config Initialize with the specified config property store.
+        */
+       protected XmlSchemaSerializer(ContextFactory config) {
+               getContextFactory().copyFrom(config);
+       }
+
+       @Override /* XmlSerializer */
+       protected void doSerialize(SerializerSession session, Object o) throws 
Exception {
+               XmlSerializerSession s = (XmlSerializerSession)session;
+
+               if (s.isEnableNamespaces() && s.isAutoDetectNamespaces())
+                       findNsfMappings(s, o);
+
+               Namespace xs = s.getXsNamespace();
+               Namespace[] allNs = ArrayUtils.append(new 
Namespace[]{s.getDefaultNamespace()}, s.getNamespaces());
+
+               Schemas schemas = new Schemas(s, xs, s.getDefaultNamespace(), 
allNs);
+               schemas.process(s, o);
+               schemas.serializeTo(session.getWriter());
+       }
+
+       /**
+        * Returns an XML-Schema validator based on the output returned by 
{@link #doSerialize(SerializerSession, Object)};
+        *
+        * @param session The serializer session object return by {@link 
#createSession(Object, ObjectMap, Method)}.<br>
+        *      Can be <jk>null</jk>.
+        * @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, Object o) 
throws Exception {
+               doSerialize(session, o);
+               String xmlSchema = session.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 
RuntimeException(MessageFormat.format("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 RuntimeException("No schema defined 
for namespace '"+ns+"'");
+                       return s;
+               }
+
+               private void process(SerializerSession session, Object o) 
throws IOException {
+                       ClassMeta<?> cm = 
session.getBeanContext().getClassMetaForObject(o);
+                       Namespace ns = defaultNs;
+                       if (cm == null)
+                               queueElement(ns, "null", object());
+                       else {
+                               XmlClassMeta xmlMeta = cm.getXmlMeta();
+                               if (xmlMeta.getElementName() != null && 
xmlMeta.getNamespace() != null)
+                                       ns = xmlMeta.getNamespace();
+                               queueElement(ns, xmlMeta.getElementName(), 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.isUseIndentation(), 
session.isTrimStrings(), session.getQuoteChar(), null, 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();
+                       for (Namespace ns : allNs) {
+                               if (ns != targetNs) {
+                                       w.oTag(i+1, "import")
+                                               .attr("namespace", ns.getUri())
+                                               .attr("schemaLocation", 
ns.getName()+".xsd")
+                                               .append("/>").nl();
+                               }
+                       }
+               }
+
+               private boolean processElement(String name, ClassMeta<?> cm) 
throws IOException {
+                       if (processedElements.contains(name))
+                               return false;
+                       processedElements.add(name);
+
+                       ClassMeta<?> ft = cm.getTransformedClassMeta();
+                       int i = session.getIndent() + 1;
+                       if (name == null)
+                               name = getElementName(ft);
+                       Namespace ns = first(ft.getXmlMeta().getNamespace(), 
defaultNs);
+                       String type = getXmlType(ns, ft);
+
+                       w.oTag(i, "element")
+                               .attr("name", XmlUtils.encodeElementName(name))
+                               .attr("type", type)
+                               .append('/').append('>').nl();
+
+                       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();
+
+                       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.getTransformedClassMeta();
+
+                       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 ((cm.isBean() && 
cm.getBeanMeta().getXmlMeta().getXmlContentProperty() != null) || cm.isObject())
+                               w.attr("mixed", "true");
+
+                       w.cTag().nl();
+
+                       if (! (cm.isMap() || cm.isBean() || 
cm.hasToObjectMapMethod() || cm.isCollection() || cm.isArray() || 
(cm.isAbstract() && ! cm.isNumber()) || cm.isObject())) {
+                               String base = getXmlAttrType(cm);
+                               w.sTag(i+1, "simpleContent").nl();
+                               w.oTag(i+2, "extension")
+                                       .attr("base", base);
+                               if (session.isAddJsonTypeAttrs() || 
(session.isAddJsonStringTypeAttrs() && base.equals("string"))) {
+                                       w.cTag().nl();
+                                       w.oTag(i+3, "attribute")
+                                               .attr("name", "type")
+                                               .attr("type", "string")
+                                               .ceTag().nl();
+                                       w.eTag(i+2, "extension").nl();
+                               } else {
+                                       w.ceTag().nl();
+                               }
+                               w.eTag(i+1, "simpleContent").nl();
+
+                       } else {
+
+                               //----- Bean -----
+                               if (cm.isBean()) {
+                                       BeanMeta<?> bm = cm.getBeanMeta();
+
+                                       boolean hasChildElements = false;
+
+                                       for (BeanPropertyMeta<?> pMeta : 
bm.getPropertyMetas())
+                                               if 
(pMeta.getXmlMeta().getXmlFormat() != XmlFormat.ATTR && 
pMeta.getXmlMeta().getXmlFormat() != XmlFormat.CONTENT)
+                                                       hasChildElements = true;
+
+                                       if 
(bm.getXmlMeta().getXmlContentProperty() != null) {
+                                               w.sTag(i+1, "sequence").nl();
+                                               w.oTag(i+2, "any")
+                                                       
.attr("processContents", "skip")
+                                                       .attr("minOccurs", 0)
+                                                       .ceTag().nl();
+                                               w.eTag(i+1, "sequence").nl();
+
+                                       } else if (hasChildElements) {
+                                               w.sTag(i+1, "sequence").nl();
+
+                                               boolean hasOtherNsElement = 
false;
+
+                                               for (BeanPropertyMeta<?> pMeta 
: bm.getPropertyMetas()) {
+                                                       XmlBeanPropertyMeta<?> 
xmlMeta = pMeta.getXmlMeta();
+                                                       if 
(xmlMeta.getXmlFormat() != XmlFormat.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.getXmlMeta().getNamespace(), 
cm.getXmlMeta().getNamespace(), defaultNs);
+                                                               if 
(xmlMeta.getNamespace() == null) {
+                                                                       
w.oTag(i+2, "element")
+                                                                               
.attr("name", XmlUtils.encodeElementName(childName), true)
+                                                                               
.attr("type", getXmlType(cNs, ct2));
+                                                                       if 
(isCollapsed) {
+                                                                               
w.attr("minOccurs", 0);
+                                                                               
w.attr("maxOccurs", "unbounded");
+                                                                       } else {
+                                                                               
if (! session.isTrimNulls())
+                                                                               
        w.attr("nillable", true);
+                                                                               
else
+                                                                               
        w.attr("minOccurs", 0);
+                                                                       }
+
+                                                                       
w.ceTag().nl();
+                                                               } else {
+                                                                       // 
Child element is in another namespace.
+                                                                       
schemas.queueElement(cNs, pMeta.getName(), ct2);
+                                                                       
hasOtherNsElement = true;
+                                                               }
+
+                                                       }
+                                               }
+
+                                               // If this bean has any child 
elements in another namespace,
+                                               // we need to add an <any> 
element.
+                                               if (hasOtherNsElement)
+                                                       w.oTag(i+2, "any")
+                                                               
.attr("minOccurs", 0)
+                                                               
.attr("maxOccurs", "unbounded")
+                                                               .ceTag().nl();
+                                               w.eTag(i+1, "sequence").nl();
+                                       }
+
+                                       for (BeanPropertyMeta<?> pMeta : 
bm.getXmlMeta().getXmlAttrProperties().values()) {
+                                               Namespace pNs = 
pMeta.getXmlMeta().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();
+                                               }
+
+                                               // 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();
+                                               }
+                                       }
+
+                               //----- Collection -----
+                               } else if (cm.isCollection() || cm.isArray()) {
+                                       ClassMeta<?> elementType = 
cm.getElementType();
+                                       if (elementType.isObject()) {
+                                               w.sTag(i+1, "sequence").nl();
+                                               w.oTag(i+2, "any")
+                                                       
.attr("processContents", "skip")
+                                                       .attr("maxOccurs", 
"unbounded")
+                                                       .attr("minOccurs", "0")
+                                                       .ceTag().nl();
+                                               w.eTag(i+1, "sequence").nl();
+                                       } else {
+                                               Namespace cNs = 
first(elementType.getXmlMeta().getNamespace(), cm.getXmlMeta().getNamespace(), 
defaultNs);
+                                               schemas.queueType(cNs, null, 
elementType);
+                                               w.sTag(i+1, "sequence").nl();
+                                               w.oTag(i+2, "choice")
+                                                       .attr("minOccurs", 0)
+                                                       .attr("maxOccurs", 
"unbounded")
+                                                       .cTag().nl();
+                                               w.oTag(i+3, "element")
+                                                       .attr("name", 
XmlUtils.encodeElementName(getElementName(elementType)))
+                                                       .attr("type", 
getXmlType(cNs, elementType))
+                                                       .ceTag().nl();
+                                               w.oTag(i+3, "element")
+                                                       .attr("name", "null")
+                                                       .attr("type", "string")
+                                                       .ceTag().nl();
+                                               w.eTag(i+2, "choice").nl();
+                                               w.eTag(i+1, "sequence").nl();
+                                       }
+
+                               //----- Map -----
+                               } else if (cm.isMap() || 
cm.hasToObjectMapMethod() || cm.isAbstract() || cm.isObject()) {
+                                       w.sTag(i+1, "sequence").nl();
+                                       w.oTag(i+2, "any")
+                                               .attr("processContents", "skip")
+                                               .attr("maxOccurs", "unbounded")
+                                               .attr("minOccurs", "0")
+                                               .ceTag().nl();
+                                       w.eTag(i+1, "sequence").nl();
+                               }
+
+                               if (session.isAddClassAttrs()) {
+                                       w.oTag(i+1, "attribute")
+                                               .attr("name", "_class")
+                                               .attr("type", "string")
+                                               .ceTag().nl();
+                               }
+                               if (session.isAddJsonTypeAttrs()) {
+                                       w.oTag(i+1, "attribute")
+                                               .attr("name", "type")
+                                               .attr("type", "string")
+                                               .ceTag().nl();
+                               }
+                       }
+
+                       w.eTag(i, "complexType").nl();
+                       schemas.processQueue();
+
+                       return true;
+               }
+
+               private String getElementName(ClassMeta<?> cm) {
+                       cm = cm.getTransformedClassMeta();
+                       String name = cm.getXmlMeta().getElementName();
+
+                       if (name == null) {
+                               if (cm.isBoolean())
+                                       name = "boolean";
+                               else if (cm.isNumber())
+                                       name = "number";
+                               else if (cm.isArray() || cm.isCollection())
+                                       name = "array";
+                               else if (! (cm.isMap() || 
cm.hasToObjectMapMethod() || cm.isBean() || cm.isCollection() || cm.isArray() 
|| cm.isObject() || cm.isAbstract()))
+                                       name = "string";
+                               else
+                                       name = "object";
+                       }
+                       return name;
+               }
+
+               @Override /* Object */
+               public String toString() {
+                       try {
+                               w.eTag(session.getIndent(), "schema").nl();
+                       } 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.getTransformedClassMeta();
+                       if (currentNs == targetNs && ! 
session.isAddJsonTypeAttrs()) {
+                               if (cm.isBoolean())
+                                       name = "boolean";
+                               else if (cm.isNumber()) {
+                                       if (cm.isDecimal())
+                                               name = "decimal";
+                                       else
+                                               name = "integer";
+                               }
+                               if (name == null && ! 
session.isAddJsonStringTypeAttrs()) {
+                                       if (! (cm.isMap() || 
cm.hasToObjectMapMethod() || cm.isBean() || cm.isCollection() || cm.isArray() 
|| cm.isObject() || cm.isAbstract()))
+                                               name = "string";
+                               }
+                       }
+                       if (name == null) {
+                               name = XmlUtils.encodeElementName(cm);
+                               schemas.queueType(currentNs, name, cm);
+                               return currentNs.getName() + ":" + name;
+                       }
+
+                       return name;
+               }
+       }
+
+       private <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";
+       }
+
+       @Override /* Serializer */
+       public XmlSerializerSession createSession(Object output, ObjectMap 
properties, Method javaMethod) {
+               // This serializer must always have namespaces enabled.
+               if (properties == null)
+                       properties = new ObjectMap();
+               properties.put(XmlSerializerContext.XML_enableNamespaces, true);
+               return new 
XmlSerializerSession(getContext(XmlSerializerContext.class), getBeanContext(), 
output, properties, javaMethod);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/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
new file mode 100644
index 0000000..a686412
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -0,0 +1,709 @@
+/***************************************************************************************************************************
+ * 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.serializer.SerializerContext.*;
+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.json.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
+import org.apache.juneau.xml.annotation.*;
+
+/**
+ * Serializes POJO models to XML.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Accept</code> types: <code>text/xml</code>
+ * <p>
+ *     Produces <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     See the {@link JsonSerializer} class for details on how Java models map 
to JSON.
+ * <p>
+ *     For example, the following JSON...
+ * <p class='bcode'>
+ *     {
+ *             name:<js>'John Smith'</js>,
+ *             address: {
+ *                     streetAddress: <js>'21 2nd Street'</js>,
+ *                     city: <js>'New York'</js>,
+ *                     state: <js>'NY'</js>,
+ *                     postalCode: <js>10021</js>
+ *             },
+ *             phoneNumbers: [
+ *                     <js>'212 555-1111'</js>,
+ *                     <js>'212 555-2222'</js>
+ *             ],
+ *             additionalInfo: <jk>null</jk>,
+ *             remote: <jk>false</jk>,
+ *             height: <js>62.4</js>,
+ *             <js>'fico score'</js>:  <js>' &gt; 640'</js>
+ *     }
+ * <p>
+ *     ...maps to the following XML...
+ * <p class='bcode'>
+ *     <xt>&lt;object&gt;</xt>
+ *             <xt>&lt;name</xt> 
<xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
+ *             <xt>&lt;address</xt> 
<xa>type</xa>=<xs>'object'</xs><xt>&gt;</xt>
+ *                     <xt>&lt;streetAddress</xt> 
<xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt>21 2nd 
Street<xt>&lt;/streetAddress&gt;</xt>
+ *                     <xt>&lt;city</xt> 
<xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt>New York<xt>&lt;/city&gt;</xt>
+ *                     <xt>&lt;state</xt> 
<xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt>NY<xt>&lt;/state&gt;</xt>
+ *                     <xt>&lt;postalCode</xt> 
<xa>type</xa>=<xs>'number'</xs><xt>&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
+ *             <xt>&lt;/address&gt;</xt>
+ *             <xt>&lt;phoneNumbers</xt> 
<xa>type</xa>=<xs>'array'</xs><xt>&gt;</xt>
+ *                     <xt>&lt;string&gt;</xt>212 
555-1111<xt>&lt;/string&gt;</xt>
+ *                     <xt>&lt;string&gt;</xt>212 
555-2222<xt>&lt;/string&gt;</xt>
+ *             <xt>&lt;/phoneNumbers&gt;</xt>
+ *             <xt>&lt;additionalInfo</xt> 
<xa>type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
+ *             <xt>&lt;remote</xt> 
<xa>type</xa>=<xs>'boolean'</xs><xt>&gt;</xt>false<xt>&lt;/remote&gt;</xt>
+ *             <xt>&lt;height</xt> 
<xa>type</xa>=<xs>'number'</xs><xt>&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
+ *             <xt>&lt;fico_x0020_score</xt> 
<xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt> &amp;gt; 
640<xt>&lt;/fico_x0020_score&gt;</xt>
+ *     <xt>&lt;/object&gt;</xt>
+ * <p>
+ *     This serializer provides several serialization options.  Typically, one 
of the predefined <jsf>DEFAULT</jsf> serializers will be sufficient.
+ *     However, custom serializers can be constructed to fine-tune behavior.
+ * <p>
+ *     If an attribute name contains any non-valid XML element characters, 
they will be escaped using standard {@code _x####_} notation.
+ *
+ *
+ * <h6 class='topic'>Configurable properties</h6>
+ * <p>
+ *     This class has the following properties associated with it:
+ * <ul>
+ *     <li>{@link XmlSerializerContext}
+ *     <li>{@link BeanContext}
+ * </ul>
+ *
+ *
+ * <h6 class='topic'>Behavior-specific subclasses</h6>
+ * <p>
+ *     The following direct subclasses are provided for convenience:
+ * <ul class='spaced-list'>
+ *     <li>{@link Sq} - Default serializer, single quotes.
+ *     <li>{@link SqReadable} - Default serializer, single quotes, whitespace 
added.
+ *     <li>{@link XmlJson} - Default serializer with JSON attribute tags.
+ *     <li>{@link XmlJsonSq} - Default serializer with JSON attribute tags, 
single quotes.
+ * </ul>
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+@SuppressWarnings({ "rawtypes", "unchecked" })
+@Produces("text/xml")
+public class XmlSerializer extends WriterSerializer {
+
+       /** Default serializer, all default settings. */
+       public static final XmlSerializer DEFAULT = new XmlSerializer().lock();
+
+       /** Default serializer, single quotes. */
+       public static final XmlSerializer DEFAULT_SQ = new 
XmlSerializer.Sq().lock();
+
+       /** Default serializer, single quotes, whitespace added. */
+       public static final XmlSerializer DEFAULT_SQ_READABLE = new 
XmlSerializer.SqReadable().lock();
+
+       /** Default serializer with JSON attribute tags. */
+       public static final XmlSerializer DEFAULT_XMLJSON = new 
XmlSerializer.XmlJson().lock();
+
+       /** Default serializer with JSON attribute tags, single quotes. */
+       public static final XmlSerializer DEFAULT_XMLJSON_SQ = new 
XmlSerializer.XmlJsonSq().lock();
+
+       /** Default serializer without namespaces. */
+       public static final XmlSerializer DEFAULT_SIMPLE = new 
XmlSerializer.Simple().lock();
+
+       /** Default serializer without namespaces, with single quotes. */
+       public static final XmlSerializer DEFAULT_SIMPLE_SQ = new 
XmlSerializer.SimpleSq().lock();
+
+       /** Default serializer without namespaces, with JSON attribute tags and 
single quotes. */
+       public static final XmlSerializer DEFAULT_SIMPLE_XMLJSON_SQ = new 
XmlSerializer.SimpleXmlJsonSq().lock();
+
+
+       /** Default serializer, single quotes. */
+       public static class Sq extends XmlSerializer {
+               /** Constructor */
+               public Sq() {
+                       setProperty(SERIALIZER_quoteChar, '\'');
+               }
+       }
+
+       /** Default serializer, single quotes, whitespace added. */
+       public static class SqReadable extends Sq {
+               /** Constructor */
+               public SqReadable() {
+                       setProperty(SERIALIZER_useIndentation, true);
+               }
+       }
+
+       /** Default serializer with JSON attribute tags. */
+       @Produces(value="text/xml+json",contentType="text/xml")
+       public static class XmlJson extends XmlSerializer {
+               /** Constructor */
+               public XmlJson() {
+                       setProperty(XML_addJsonTypeAttrs, true);
+               }
+       }
+
+       /** Default serializer with JSON attribute tags, single quotes. */
+       public static class XmlJsonSq extends XmlJson {
+               /** Constructor */
+               public XmlJsonSq() {
+                       setProperty(SERIALIZER_quoteChar, '\'');
+               }
+       }
+
+       /** Default serializer without namespaces. */
+       @Produces(value="text/xml+simple",contentType="text/xml")
+       public static class Simple extends XmlSerializer {
+               /** Constructor */
+               public Simple() {
+                       setProperty(XML_enableNamespaces, false);
+               }
+       }
+
+       /** Default serializer without namespaces, single quotes. */
+       public static class SimpleSq extends Simple {
+               /** Constructor */
+               public SimpleSq() {
+                       setProperty(SERIALIZER_quoteChar, '\'');
+               }
+       }
+
+       /** Default serializer with JSON attribute tags, single quotes. */
+       public static class SimpleXmlJsonSq extends SimpleSq {
+               /** Constructor */
+               public SimpleXmlJsonSq() {
+                       setProperty(XML_addJsonTypeAttrs, true);
+               }
+       }
+
+       /**
+        * 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 {
+               BeanContext bc = session.getBeanContext();
+               ClassMeta<?> aType = null;                                      
        // The actual type
+               aType = session.push(null, o, null);
+
+               if (aType != null) {
+                       Namespace ns = aType.getXmlMeta().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 = bc.forBean(o);
+                       } else if (aType.isDelegate()) {
+                               ClassMeta innerType = 
((Delegate)o).getClassMeta();
+                               Namespace ns = 
innerType.getXmlMeta().getNamespace();
+                               if (ns != null) {
+                                       if (ns.uri != null)
+                                               session.addNamespace(ns);
+                                       else
+                                               ns = null;
+                               }
+
+                               if (innerType.isBean()) {
+                                       for (BeanPropertyMeta bpm : 
(Collection<BeanPropertyMeta>)innerType.getBeanMeta().getPropertyMetas()) {
+                                               ns = 
bpm.getXmlMeta().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(false, 
session.isTrimNulls())) {
+
+                                       Namespace ns = 
p.getMeta().getXmlMeta().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 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, BeanPropertyMeta<?> pMeta) throws 
Exception {
+
+               BeanContext bc = session.getBeanContext();
+               String ts = null;              // The type string (e.g. <type> 
or <x x='type'>
+               int indent = session.indent;       // Current indentation
+               ClassMeta<?> aType = null;     // The actual type
+               ClassMeta<?> wType = null;     // The wrapped type
+               ClassMeta<?> gType = object(); // The generic 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;
+                               aType = ((Delegate)o).getClassMeta();
+                       }
+
+                       gType = aType.getTransformedClassMeta();
+
+                       // Transform if necessary
+                       PojoTransform transform = aType.getPojoTransform();
+                       if (transform != null) {
+                               o = transform.transform(o);
+
+                               // If the transform's getTransformedClass() 
method returns Object, we need to figure out
+                               // the actual type now.
+                               if (gType.isObject())
+                                       gType = bc.getClassMetaForObject(o);
+                       }
+               } else {
+                       gType = eType.getTransformedClassMeta();
+               }
+
+               String classAttr = null;
+               if (session.isAddClassAttrs()) {
+                       if (o != null && ! eType.equals(aType))
+                               classAttr = aType.toString();
+                       else if (o == null)
+                               classAttr = eType.toString();
+               }
+
+               // char '\0' is interpreted as null.
+               if (o != null && gType.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 (gType.isCharSequence() || gType.isChar())
+                       ts = "string";
+               else if (gType.isNumber())
+                       ts = "number";
+               else if (gType.isBoolean())
+                       ts = "boolean";
+               else if (gType.isMap() || gType.isBean() || 
gType.hasToObjectMapMethod()) {
+                       isCollapsed = gType.getXmlMeta().getFormat() == 
XmlFormat.COLLAPSED;
+                       ts = "object";
+               }
+               else if (gType.isCollection() || gType.isArray()) {
+                       isCollapsed = (format == COLLAPSED && ! 
addNamespaceUris);
+                       ts = "array";
+               }
+               else
+                       ts = "string";
+
+
+               // Is there a name associated with this bean?
+               if (elementName == null)
+                       elementName = gType.getXmlMeta().getElementName();
+               if (elementName == null)
+                       elementName = aType.getXmlMeta().getElementName();
+
+               // If the value is null then it's either going to be <null/> or 
<XmlSerializer nil='true'/>
+               // depending on whether the element has a name.
+               boolean isNullTag = (elementName == null && o == null);
+
+               if (isNullTag)
+                       ts = "null";
+
+               if (session.isEnableNamespaces()) {
+                       if (elementNamespace == null)
+                               elementNamespace = 
gType.getXmlMeta().getNamespace();
+                       if (elementNamespace == null)
+                               elementNamespace = 
aType.getXmlMeta().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 && (gType.isMap() || 
gType.isCollection() || gType.isArray() || gType.isBean() || 
gType.hasToObjectMapMethod());
+
+               String en = (elementName == null ? ts : elementName);
+               boolean encodeEn = elementName != null;
+               String ns = (elementNamespace == null ? null : 
elementNamespace.name);
+               String xsi = null, dns = null, elementNs = null;
+               if (session.isEnableNamespaces()) {
+                       xsi = session.getXsiNamespace().name;
+                       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());
+
+                               Namespace xsiNs = session.getXsiNamespace();
+                               if (xsiNs != null)
+                                       out.attr("xmlns", xsiNs.name, 
xsiNs.uri);
+                       }
+                       if (elementName != null && session.isAddJsonTypeAttrs() 
&& (session.isAddJsonStringTypeAttrs() || ! ts.equals("string")))
+                               out.attr(dns, "type", ts);
+                       if (classAttr != null)
+                               out.attr(dns, "_class", classAttr);
+                       if (o == null) {
+                               if (! isNullTag)
+                                       out.attr(xsi, "nil", "true");
+                               if ((gType.isBoolean() || gType.isNumber()) && 
! gType.isNullable())
+                                       o = gType.getPrimitiveDefault();
+                       }
+
+                       if (o != null && !(gType.isMap() || gType.isBean() || 
gType.hasToObjectMapMethod()))
+                               out.append('>');
+
+                       if (cr && !(gType.isMap() || gType.isBean() || 
gType.hasToObjectMapMethod()))
+                               out.nl();
+               }
+
+               boolean hasChildren = true;
+
+               // Render the tag contents.
+               if (o != null) {
+                       if (gType.isUri() || (pMeta != null && pMeta.isUri()))
+                               out.appendUri(o);
+                       else if (gType.isCharSequence() || gType.isChar())
+                               out.encodeText(session.trim(o));
+                       else if (gType.isNumber() || gType.isBoolean())
+                               out.append(o);
+                       else if (gType.isMap() || (wType != null && 
wType.isMap())) {
+                               if (o instanceof BeanMap)
+                                       hasChildren = serializeBeanMap(session, 
out, (BeanMap)o, elementNamespace, isCollapsed);
+                               else
+                                       hasChildren = serializeMap(session, 
out, (Map)o, gType);
+                       }
+                       else if (gType.hasToObjectMapMethod())
+                               hasChildren = serializeMap(session, out, 
gType.toObjectMap(o), gType);
+                       else if (gType.isBean())
+                               hasChildren = serializeBeanMap(session, out, 
bc.forBean(o), elementNamespace, isCollapsed);
+                       else if (gType.isCollection() || (wType != null && 
wType.isCollection())) {
+                               if (isCollapsed)
+                                       session.indent--;
+                               serializeCollection(session, out, 
(Collection)o, gType, pMeta);
+                               if (isCollapsed)
+                                       session.indent++;
+                       }
+                       else if (gType.isArray()) {
+                               if (isCollapsed)
+                                       session.indent--;
+                               serializeCollection(session, out, 
toList(gType.getInnerClass(), o), gType, pMeta);
+                               if (isCollapsed)
+                                       session.indent++;
+                       }
+                       else
+                               out.encodeText(session.toString(o));
+               }
+
+               session.pop();
+
+               // Render the end tag.
+               if (! isCollapsed) {
+                       if (o == null || ! hasChildren)
+                               out.append('/').append('>').nl();
+                       else
+                               out.i(cr ? indent : 0).eTag(elementNs, en, 
encodeEn).nl();
+               }
+
+               return out;
+       }
+
+       private boolean serializeMap(XmlSerializerSession session, XmlWriter 
out, Map m, ClassMeta<?> type) throws Exception {
+
+               m = session.sort(m);
+
+               ClassMeta<?> keyType = type.getKeyType(), valueType = 
type.getValueType();
+
+               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('>').nl();
+                       }
+                       serializeAnything(session, out, value, valueType, 
session.toString(k), null, false, NORMAL, null);
+               }
+               return hasChildren;
+       }
+
+       private boolean serializeBeanMap(XmlSerializerSession session, 
XmlWriter out, BeanMap<?> m, Namespace elementNs, boolean isCollapsed) throws 
Exception {
+               boolean hasChildren = false;
+               BeanMeta bm = m.getMeta();
+
+               List<BeanPropertyValue> lp = m.getValues(false, 
session.isTrimNulls());
+
+               Map<String,BeanPropertyMeta> xmlAttrs = 
bm.getXmlMeta().getXmlAttrProperties();
+               Object content = null;
+               for (BeanPropertyValue p : lp) {
+                       if (xmlAttrs.containsKey(p.getName())) {
+                               BeanPropertyMeta pMeta = p.getMeta();
+                               String key = p.getName();
+                               Object value = p.getValue();
+                               Throwable t = p.getThrown();
+                               if (t != null)
+                                       session.addBeanGetterWarning(pMeta, t);
+
+                               if 
(session.canIgnoreValue(pMeta.getClassMeta(), key, value))
+                                       continue;
+
+                               Namespace ns = (session.isEnableNamespaces() && 
pMeta.getXmlMeta().getNamespace() != elementNs ? 
pMeta.getXmlMeta().getNamespace() : null);
+
+                               if (pMeta.isBeanUri() || pMeta.isUri())
+                                       out.attrUri(ns, key, value);
+                               else
+                                       out.attr(ns, key, value);
+                       }
+               }
+
+               boolean hasContent = false;
+
+               for (BeanPropertyValue p : lp) {
+                       BeanPropertyMeta pMeta = p.getMeta();
+                       XmlFormat xf = pMeta.getXmlMeta().getXmlFormat();
+
+                       if (xf == CONTENT) {
+                               content = p.getValue();
+                               hasContent = true;
+                       } else if (xf == ATTR) {
+                               // Do nothing
+                       } else {
+                               String key = p.getName();
+                               Object value = p.getValue();
+                               Throwable t = p.getThrown();
+                               if (t != null)
+                                       session.addBeanGetterWarning(pMeta, t);
+
+                               if 
(session.canIgnoreValue(pMeta.getClassMeta(), key, value))
+                                       continue;
+
+                               if (! hasChildren) {
+                                       hasChildren = true;
+                                       out.appendIf(! isCollapsed, '>').nl();
+                               }
+                               serializeAnything(session, out, value, 
pMeta.getClassMeta(), key, pMeta.getXmlMeta().getNamespace(), false, 
pMeta.getXmlMeta().getXmlFormat(), pMeta);
+                       }
+               }
+               if ((! hasContent) || session.canIgnoreValue(string(), null, 
content))
+                       return hasChildren;
+               out.append('>').cr(session.indent);
+
+               // Serialize XML content.
+               XmlContentHandler h = bm.getXmlMeta().getXmlContentHandler();
+               if (h != null)
+                       h.serialize(out, m.getBean());
+               else
+                       out.encodeText(content);
+               out.nl();
+               return true;
+       }
+
+       private XmlWriter serializeCollection(XmlSerializerSession session, 
XmlWriter out, Collection c, ClassMeta<?> type, BeanPropertyMeta<?> ppMeta) 
throws Exception {
+
+               c = session.sort(c);
+
+               ClassMeta<?> elementType = type.getElementType();
+
+               String eName = null;
+               Namespace eNs = null;
+
+               if (ppMeta != null) {
+                       eName = ppMeta.getXmlMeta().getChildName();
+                       eNs = ppMeta.getXmlMeta().getNamespace();
+               }
+
+               if (eName == null) {
+                       eName = type.getXmlMeta().getChildName();
+                       eNs = type.getXmlMeta().getNamespace();
+               }
+
+               if (eName == null && ! elementType.isObject()) {
+                       eName = elementType.getXmlMeta().getElementName();
+                       eNs = elementType.getXmlMeta().getNamespace();
+               }
+
+               for (Iterator i = c.iterator(); i.hasNext();) {
+                       Object value = i.next();
+                       serializeAnything(session, out, value, elementType, 
eName, eNs, false, NORMAL, null);
+               }
+               return out;
+       }
+
+       /**
+        * Returns the schema serializer based on the settings of this 
serializer.
+        * @return The schema serializer.
+        */
+       public XmlSerializer getSchemaSerializer() {
+               XmlSchemaSerializer s = new 
XmlSchemaSerializer(getContextFactory());
+               return s;
+       }
+
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       @Override /* Serializer */
+       protected void doSerialize(SerializerSession session, Object o) throws 
Exception {
+               XmlSerializerSession s = (XmlSerializerSession)session;
+               if (s.isEnableNamespaces() && s.isAutoDetectNamespaces())
+                       findNsfMappings(s, o);
+               serializeAnything(s, s.getWriter(), o, null, null, null, 
s.isEnableNamespaces() && s.isAddNamespaceUrlsToRoot(), NORMAL, null);
+       }
+
+       @Override /* Serializer */
+       public XmlSerializerSession createSession(Object output, ObjectMap 
properties, Method javaMethod) {
+               return new 
XmlSerializerSession(getContext(XmlSerializerContext.class), getBeanContext(), 
output, properties, javaMethod);
+       }
+
+       @Override /* CoreApi */
+       public XmlSerializer setProperty(String property, Object value) throws 
LockedException {
+               super.setProperty(property, value);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlSerializer setProperties(ObjectMap properties) throws 
LockedException {
+               super.setProperties(properties);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlSerializer addNotBeanClasses(Class<?>...classes) throws 
LockedException {
+               super.addNotBeanClasses(classes);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlSerializer addTransforms(Class<?>...classes) throws 
LockedException {
+               super.addTransforms(classes);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public <T> XmlSerializer addImplClass(Class<T> interfaceClass, Class<? 
extends T> implClass) throws LockedException {
+               super.addImplClass(interfaceClass, implClass);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlSerializer setClassLoader(ClassLoader classLoader) throws 
LockedException {
+               super.setClassLoader(classLoader);
+               return this;
+       }
+
+       @Override /* Lockable */
+       public XmlSerializer lock() {
+               super.lock();
+               return this;
+       }
+
+       @Override /* Lockable */
+       public XmlSerializer clone() {
+               try {
+                       XmlSerializer c = (XmlSerializer)super.clone();
+                       return c;
+               } catch (CloneNotSupportedException e) {
+                       throw new RuntimeException(e); // Shouldn't happen.
+               }
+       }
+}

Reply via email to