http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
new file mode 100644
index 0000000..8ca9c37
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
@@ -0,0 +1,1702 @@
+// 
***************************************************************************************************************************
+// * 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.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.xml.annotation.*;
+import org.junit.*;
+import org.junit.runner.*;
+import org.junit.runners.*;
+
+@RunWith(Parameterized.class)
+@SuppressWarnings({"javadoc","serial"})
+public class BasicXmlTest {
+
+       private static final XmlSerializer
+               s1 = XmlSerializer.DEFAULT_SQ,
+               s2 = XmlSerializer.DEFAULT_SQ_READABLE,
+               s3 = XmlSerializer.DEFAULT_NS_SQ;
+       private static final XmlParser parser = XmlParser.DEFAULT;
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> getParameters() {
+               return Arrays.asList(new Object[][] {
+
+                       {
+                               "SimpleTypes-1",
+                               "foo",
+                               "<string>foo</string>",
+                               "<string>foo</string>\n",
+                               "<string>foo</string>",
+                       },
+                       {
+                               "SimpleTypes-2",
+                               true,
+                               "<boolean>true</boolean>",
+                               "<boolean>true</boolean>\n",
+                               "<boolean>true</boolean>",
+                       },
+                       {
+                               "SimpleTypes-3",
+                               123,
+                               "<number>123</number>",
+                               "<number>123</number>\n",
+                               "<number>123</number>",
+                       },
+                       {
+                               "SimpleTypes-4",
+                               1.23f,
+                               "<number>1.23</number>",
+                               "<number>1.23</number>\n",
+                               "<number>1.23</number>",
+                       },
+                       {
+                               "SimpleTypes-5",
+                               null,
+                               "<null/>",
+                               "<null/>\n",
+                               "<null/>",
+                       },
+                       {
+                               "Arrays-1",
+                               new String[]{"foo"},
+                               "<array><string>foo</string></array>",
+                               "<array>\n\t<string>foo</string>\n</array>\n",
+                               "<array><string>foo</string></array>",
+                       },
+                       {
+                               "Arrays-2",
+                               new String[]{null},
+                               "<array><null/></array>",
+                               "<array>\n\t<null/>\n</array>\n",
+                               "<array><null/></array>",
+                       },
+                       {
+                               "Arrays-3",
+                               new Object[]{"foo"},
+                               "<array><string>foo</string></array>",
+                               "<array>\n\t<string>foo</string>\n</array>\n",
+                               "<array><string>foo</string></array>",
+                       },
+                       {
+                               "Arrays-4",
+                               new int[]{123},
+                               "<array><number>123</number></array>",
+                               "<array>\n\t<number>123</number>\n</array>\n",
+                               "<array><number>123</number></array>",
+                       },
+                       {
+                               "Arrays-5",
+                               new boolean[]{true},
+                               "<array><boolean>true</boolean></array>",
+                               
"<array>\n\t<boolean>true</boolean>\n</array>\n",
+                               "<array><boolean>true</boolean></array>",
+                       },
+                       {
+                               "Arrays-6",
+                               new String[][]{{"foo"}},
+                               
"<array><array><string>foo</string></array></array>",
+                               
"<array>\n\t<array>\n\t\t<string>foo</string>\n\t</array>\n</array>\n",
+                               
"<array><array><string>foo</string></array></array>",
+                       },
+                       {
+                               "MapWithStrings",
+                               new MapWithStrings().append("k1", 
"v1").append("k2", null),
+                               "<object><k1>v1</k1><k2 
_type='null'/></object>",
+                               "<object>\n\t<k1>v1</k1>\n\t<k2 
_type='null'/>\n</object>\n",
+                               "<object><k1>v1</k1><k2 
_type='null'/></object>",
+                       },
+                       {
+                               "MapsWithNumbers",
+                               new MapWithNumbers().append("k1", 
123).append("k2", 1.23).append("k3", null),
+                               "<object><k1>123</k1><k2>1.23</k2><k3 
_type='null'/></object>",
+                               
"<object>\n\t<k1>123</k1>\n\t<k2>1.23</k2>\n\t<k3 _type='null'/>\n</object>\n",
+                               "<object><k1>123</k1><k2>1.23</k2><k3 
_type='null'/></object>",
+                       },
+                       {
+                               "MapWithObjects",
+                               new MapWithObjects().append("k1", 
"v1").append("k2", 123).append("k3", 1.23).append("k4", true).append("k5", 
null),
+                               "<object><k1>v1</k1><k2 
_type='number'>123</k2><k3 _type='number'>1.23</k3><k4 
_type='boolean'>true</k4><k5 _type='null'/></object>",
+                               "<object>\n\t<k1>v1</k1>\n\t<k2 
_type='number'>123</k2>\n\t<k3 _type='number'>1.23</k3>\n\t<k4 
_type='boolean'>true</k4>\n\t<k5 _type='null'/>\n</object>\n",
+                               "<object><k1>v1</k1><k2 
_type='number'>123</k2><k3 _type='number'>1.23</k3><k4 
_type='boolean'>true</k4><k5 _type='null'/></object>",
+                       },
+                       {
+                               "ListWithStrings",
+                               new 
ListWithStrings().append("foo").append(null),
+                               "<array><string>foo</string><null/></array>",
+                               
"<array>\n\t<string>foo</string>\n\t<null/>\n</array>\n",
+                               "<array><string>foo</string><null/></array>",
+                       },
+                       {
+                               "ListWithNumbers",
+                               new 
ListWithNumbers().append(123).append(1.23).append(null),
+                               
"<array><number>123</number><number>1.23</number><null/></array>",
+                               
"<array>\n\t<number>123</number>\n\t<number>1.23</number>\n\t<null/>\n</array>\n",
+                               
"<array><number>123</number><number>1.23</number><null/></array>",
+                       },
+                       {
+                               "ListWithObjects",
+                               new 
ListWithObjects().append("foo").append(123).append(1.23).append(true).append(null),
+                               
"<array><string>foo</string><number>123</number><number>1.23</number><boolean>true</boolean><null/></array>",
+                               
"<array>\n\t<string>foo</string>\n\t<number>123</number>\n\t<number>1.23</number>\n\t<boolean>true</boolean>\n\t<null/>\n</array>\n",
+                               
"<array><string>foo</string><number>123</number><number>1.23</number><boolean>true</boolean><null/></array>",
+                       },
+                       {
+                               "BeanWithNormalProperties",
+                               new BeanWithNormalProperties().init(),
+                               "<object>"
+                                       +"<a>foo</a>"
+                                       +"<b>123</b>"
+                                       +"<c>bar</c>"
+                                       +"<d _type='number'>456</d>"
+                                       +"<e>"
+                                               +"<h>qux</h>"
+                                       +"</e>"
+                                       +"<f>"
+                                               +"<string>baz</string>"
+                                       +"</f>"
+                                       +"<g>"
+                                               +"<number>789</number>"
+                                       +"</g>"
+                               +"</object>",
+                               "<object>"
+                                       +"\n\t<a>foo</a>"
+                                       +"\n\t<b>123</b>"
+                                       +"\n\t<c>bar</c>"
+                                       +"\n\t<d _type='number'>456</d>"
+                                       +"\n\t<e>"
+                                               +"\n\t\t<h>qux</h>"
+                                       +"\n\t</e>"
+                                       +"\n\t<f>"
+                                               +"\n\t\t<string>baz</string>"
+                                       +"\n\t</f>"
+                                       +"\n\t<g>"
+                                               +"\n\t\t<number>789</number>"
+                                       +"\n\t</g>"
+                               +"\n</object>\n",
+                               "<object>"
+                                       +"<a>foo</a>"
+                                       +"<b>123</b>"
+                                       +"<c>bar</c>"
+                                       +"<d _type='number'>456</d>"
+                                       +"<e>"
+                                               +"<h>qux</h>"
+                                       +"</e>"
+                                       +"<f>"
+                                               +"<string>baz</string>"
+                                       +"</f>"
+                                       +"<g>"
+                                               +"<number>789</number>"
+                                       +"</g>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithMapProperties",
+                               new BeanWithMapProperties().init(),
+                               "<object>"
+                                       +"<a>"
+                                               +"<k1>foo</k1>"
+                                       +"</a>"
+                                       +"<b>"
+                                               +"<k2>123</k2>"
+                                       +"</b>"
+                                       +"<c>"
+                                               +"<k3>bar</k3>"
+                                               +"<k4 _type='number'>456</k4>"
+                                               +"<k5 _type='boolean'>true</k5>"
+                                               +"<k6 _type='null'/>"
+                                       +"</c>"
+                               +"</object>",
+                               "<object>"
+                                       +"\n\t<a>"
+                                               +"\n\t\t<k1>foo</k1>"
+                                       +"\n\t</a>"
+                                       +"\n\t<b>"
+                                               +"\n\t\t<k2>123</k2>"
+                                       +"\n\t</b>"
+                                       +"\n\t<c>"
+                                               +"\n\t\t<k3>bar</k3>"
+                                               +"\n\t\t<k4 
_type='number'>456</k4>"
+                                               +"\n\t\t<k5 
_type='boolean'>true</k5>"
+                                               +"\n\t\t<k6 _type='null'/>"
+                                       +"\n\t</c>"
+                               +"\n</object>\n",
+                               "<object>"
+                                       +"<a>"
+                                               +"<k1>foo</k1>"
+                                       +"</a>"
+                                       +"<b>"
+                                               +"<k2>123</k2>"
+                                       +"</b>"
+                                       +"<c>"
+                                               +"<k3>bar</k3>"
+                                               +"<k4 _type='number'>456</k4>"
+                                               +"<k5 _type='boolean'>true</k5>"
+                                               +"<k6 _type='null'/>"
+                                       +"</c>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithTypeName",
+                               new BeanWithTypeName().init(),
+                               "<X><a>123</a><b>foo</b></X>",
+                               "<X>\n\t<a>123</a>\n\t<b>foo</b>\n</X>\n",
+                               "<X><a>123</a><b>foo</b></X>",
+                       },
+                       {
+                               "BeanWithPropertiesWithTypeNames",
+                               new BeanWithPropertiesWithTypeNames().init(),
+                               "<object><b1><b>foo</b></b1><b2 
_type='B'><b>foo</b></b2></object>",
+                               
"<object>\n\t<b1>\n\t\t<b>foo</b>\n\t</b1>\n\t<b2 
_type='B'>\n\t\t<b>foo</b>\n\t</b2>\n</object>\n",
+                               "<object><b1><b>foo</b></b1><b2 
_type='B'><b>foo</b></b2></object>"
+                       },
+                       {
+                               "BeanWithPropertiesWithArrayTypeNames",
+                               new 
BeanWithPropertiesWithArrayTypeNames().init(),
+                               "<object>"
+                                       +"<b1>"
+                                               +"<B>"
+                                                       +"<b>foo</b>"
+                                               +"</B>"
+                                       +"</b1>"
+                                       +"<b2>"
+                                               +"<B>"
+                                                       +"<b>foo</b>"
+                                               +"</B>"
+                                       +"</b2>"
+                                       +"<b3>"
+                                               +"<B>"
+                                                       +"<b>foo</b>"
+                                               +"</B>"
+                                       +"</b3>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<b1>\n"
+                                               +"\t\t<B>\n"
+                                                       +"\t\t\t<b>foo</b>\n"
+                                               +"\t\t</B>\n"
+                                       +"\t</b1>\n"
+                                       +"\t<b2>\n"
+                                               +"\t\t<B>\n"
+                                                       +"\t\t\t<b>foo</b>\n"
+                                               +"\t\t</B>\n"
+                                       +"\t</b2>\n"
+                                       +"\t<b3>\n"
+                                               +"\t\t<B>\n"
+                                                       +"\t\t\t<b>foo</b>\n"
+                                               +"\t\t</B>\n"
+                                       +"\t</b3>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<b1>"
+                                               +"<B>"
+                                                       +"<b>foo</b>"
+                                               +"</B>"
+                                       +"</b1>"
+                                       +"<b2>"
+                                               +"<B>"
+                                                       +"<b>foo</b>"
+                                               +"</B>"
+                                       +"</b2>"
+                                       +"<b3>"
+                                               +"<B>"
+                                                       +"<b>foo</b>"
+                                               +"</B>"
+                                       +"</b3>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithPropertiesWithArray2dTypeNames",
+                               new 
BeanWithPropertiesWith2dArrayTypeNames().init(),
+                               "<object>"
+                                       +"<b1>"
+                                               +"<array>"
+                                                       +"<B>"
+                                                               +"<b>foo</b>"
+                                                       +"</B>"
+                                               +"</array>"
+                                       +"</b1>"
+                                       +"<b2>"
+                                               +"<array>"
+                                                       +"<B>"
+                                                               +"<b>foo</b>"
+                                                       +"</B>"
+                                               +"</array>"
+                                       +"</b2>"
+                                       +"<b3>"
+                                               +"<array>"
+                                                       +"<B>"
+                                                               +"<b>foo</b>"
+                                                       +"</B>"
+                                               +"</array>"
+                                       +"</b3>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<b1>\n"
+                                               +"\t\t<array>\n"
+                                                       +"\t\t\t<B>\n"
+                                                               
+"\t\t\t\t<b>foo</b>\n"
+                                                       +"\t\t\t</B>\n"
+                                               +"\t\t</array>\n"
+                                       +"\t</b1>\n"
+                                       +"\t<b2>\n"
+                                               +"\t\t<array>\n"
+                                                       +"\t\t\t<B>\n"
+                                                               
+"\t\t\t\t<b>foo</b>\n"
+                                                       +"\t\t\t</B>\n"
+                                               +"\t\t</array>\n"
+                                       +"\t</b2>\n"
+                                       +"\t<b3>\n"
+                                               +"\t\t<array>\n"
+                                                       +"\t\t\t<B>\n"
+                                                               
+"\t\t\t\t<b>foo</b>\n"
+                                                       +"\t\t\t</B>\n"
+                                               +"\t\t</array>\n"
+                                       +"\t</b3>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<b1>"
+                                               +"<array>"
+                                                       +"<B>"
+                                                               +"<b>foo</b>"
+                                                       +"</B>"
+                                               +"</array>"
+                                       +"</b1>"
+                                       +"<b2>"
+                                               +"<array>"
+                                                       +"<B>"
+                                                               +"<b>foo</b>"
+                                                       +"</B>"
+                                               +"</array>"
+                                       +"</b2>"
+                                       +"<b3>"
+                                               +"<array>"
+                                                       +"<B>"
+                                                               +"<b>foo</b>"
+                                                       +"</B>"
+                                               +"</array>"
+                                       +"</b3>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithPropertiesWithMapTypeNames",
+                               new BeanWithPropertiesWithMapTypeNames().init(),
+                               "<object>"
+                                       +"<b1>"
+                                               +"<k1>"
+                                                       +"<b>foo</b>"
+                                               +"</k1>"
+                                       +"</b1>"
+                                       +"<b2>"
+                                               +"<k2 _type='B'>"
+                                                       +"<b>foo</b>"
+                                               +"</k2>"
+                                       +"</b2>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<b1>\n"
+                                               +"\t\t<k1>\n"
+                                                       +"\t\t\t<b>foo</b>\n"
+                                               +"\t\t</k1>\n"
+                                       +"\t</b1>\n"
+                                       +"\t<b2>\n"
+                                               +"\t\t<k2 _type='B'>\n"
+                                                       +"\t\t\t<b>foo</b>\n"
+                                               +"\t\t</k2>\n"
+                                       +"\t</b2>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<b1>"
+                                               +"<k1>"
+                                                       +"<b>foo</b>"
+                                               +"</k1>"
+                                       +"</b1>"
+                                       +"<b2>"
+                                               +"<k2 _type='B'>"
+                                                       +"<b>foo</b>"
+                                               +"</k2>"
+                                       +"</b2>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithChildTypeNames",
+                               new BeanWithChildTypeNames().init(),
+                               "<object>"
+                                       +"<a>"
+                                               +"<fx>fx1</fx>"
+                                       +"</a>"
+                                       +"<b _type='X'>"
+                                               +"<fx>fx1</fx>"
+                                       +"</b>"
+                                       +"<c>"
+                                               +"<X>"
+                                                       +"<fx>fx1</fx>"
+                                               +"</X>"
+                                       +"</c>"
+                                       +"<d>"
+                                               +"<X>"
+                                                       +"<fx>fx1</fx>"
+                                               +"</X>"
+                                       +"</d>"
+                               +"</object>",
+                               "<object>"
+                                       +"\n\t<a>"
+                                               +"\n\t\t<fx>fx1</fx>"
+                                       +"\n\t</a>"
+                                       +"\n\t<b _type='X'>"
+                                               +"\n\t\t<fx>fx1</fx>"
+                                       +"\n\t</b>"
+                                       +"\n\t<c>"
+                                               +"\n\t\t<X>"
+                                                       +"\n\t\t\t<fx>fx1</fx>"
+                                               +"\n\t\t</X>"
+                                       +"\n\t</c>"
+                                       +"\n\t<d>"
+                                               +"\n\t\t<X>"
+                                                       +"\n\t\t\t<fx>fx1</fx>"
+                                               +"\n\t\t</X>"
+                                       +"\n\t</d>"
+                               +"\n</object>\n",
+                               "<object>"
+                                       +"<a>"
+                                               +"<fx>fx1</fx>"
+                                       +"</a>"
+                                       +"<b _type='X'>"
+                                               +"<fx>fx1</fx>"
+                                       +"</b>"
+                                       +"<c>"
+                                               +"<X>"
+                                                       +"<fx>fx1</fx>"
+                                               +"</X>"
+                                       +"</c>"
+                                       +"<d>"
+                                               +"<X>"
+                                                       +"<fx>fx1</fx>"
+                                               +"</X>"
+                                       +"</d>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithChildName",
+                               new BeanWithChildName().init(),
+                               
"<object><a><X>foo</X><X>bar</X></a><b><Y>123</Y><Y>456</Y></b></object>",
+                               
"<object>\n\t<a>\n\t\t<X>foo</X>\n\t\t<X>bar</X>\n\t</a>\n\t<b>\n\t\t<Y>123</Y>\n\t\t<Y>456</Y>\n\t</b>\n</object>\n",
+                               
"<object><a><X>foo</X><X>bar</X></a><b><Y>123</Y><Y>456</Y></b></object>",
+                       },
+                       {
+                               "BeanWithXmlFormatAttrProperty",
+                               new BeanWithXmlFormatAttrProperty().init(),
+                               "<object a='foo' b='123'/>",
+                               "<object a='foo' b='123'/>\n",
+                               "<object a='foo' b='123'/>",
+                       },
+                       {
+                               "BeanWithXmlFormatAttrs",
+                               new BeanWithXmlFormatAttrs().init(),
+                               "<object a='foo' b='123'/>",
+                               "<object a='foo' b='123'/>\n",
+                               "<object a='foo' b='123'/>",
+                       },
+                       {
+                               "BeanWithXmlFormatElementProperty",
+                               new BeanWithXmlFormatElementProperty().init(),
+                               "<object a='foo'><b>123</b></object>",
+                               "<object a='foo'>\n\t<b>123</b>\n</object>\n",
+                               "<object a='foo'><b>123</b></object>",
+                       },
+                       {
+                               "BeanWithXmlFormatAttrsProperty",
+                               new BeanWithXmlFormatAttrsProperty().init(),
+                               "<object k1='foo' k2='123' b='456'/>",
+                               "<object k1='foo' k2='123' b='456'/>\n",
+                               "<object k1='foo' k2='123' b='456'/>",
+                       },
+                       {
+                               "BeanWithXmlFormatCollapsedProperty",
+                               new BeanWithXmlFormatCollapsedProperty().init(),
+                               
"<object><A>foo</A><A>bar</A><B>123</B><B>456</B></object>",
+                               
"<object>\n\t<A>foo</A>\n\t<A>bar</A>\n\t<B>123</B>\n\t<B>456</B>\n</object>\n",
+                               
"<object><A>foo</A><A>bar</A><B>123</B><B>456</B></object>",
+                       },
+                       {
+                               "BeanWithXmlFormatTextProperty",
+                               new BeanWithXmlFormatTextProperty().init(),
+                               "<object a='foo'>bar</object>",
+                               "<object a='foo'>bar</object>\n",
+                               "<object a='foo'>bar</object>",
+                       },
+                       {
+                               "BeanWithXmlFormatXmlTextProperty",
+                               new BeanWithXmlFormatXmlTextProperty().init(),
+                               "<object a='foo'>bar<b>baz</b>qux</object>",
+                               "<object a='foo'>bar<b>baz</b>qux</object>\n",
+                               "<object a='foo'>bar<b>baz</b>qux</object>",
+                       },
+                       {
+                               "BeanWithXmlFormatElementsPropertyCollection",
+                               new 
BeanWithXmlFormatElementsPropertyCollection().init(),
+                               "<object 
a='foo'><string>bar</string><string>baz</string><number>123</number><boolean>true</boolean><null/></object>",
+                               "<object 
a='foo'>\n\t<string>bar</string>\n\t<string>baz</string>\n\t<number>123</number>\n\t<boolean>true</boolean>\n\t<null/>\n</object>\n",
+                               "<object 
a='foo'><string>bar</string><string>baz</string><number>123</number><boolean>true</boolean><null/></object>",
+                       },
+                       {
+                               "BeanWithMixedContent",
+                               new BeanWithMixedContent().init(),
+                               "<object>foo<X fx='fx1'/>bar<Y 
fy='fy1'/>baz</object>",
+                               "<object>foo<X fx='fx1'/>bar<Y 
fy='fy1'/>baz</object>\n",  // Mixed content doesn't use whitespace!
+                               "<object>foo<X fx='fx1'/>bar<Y 
fy='fy1'/>baz</object>",
+                       },
+                       {
+                               "BeanWithSpecialCharacters",
+                               new BeanWithSpecialCharacters().init(),
+                               "<object><a>_x0020_ 
_x0008__x000C_&#x000a;&#x0009;&#x000d; _x0020_</a></object>",
+                               "<object>\n\t<a>_x0020_ 
_x0008__x000C_&#x000a;&#x0009;&#x000d; _x0020_</a>\n</object>\n",
+                               "<object><a>_x0020_ 
_x0008__x000C_&#x000a;&#x0009;&#x000d; _x0020_</a></object>"
+                       },
+                       {
+                               "BeanWithSpecialCharacters2",
+                               new BeanWithSpecialCharacters2().init(),
+                               
"<_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_><_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>_x0020_
 _x0008__x000C_&#x000a;&#x0009;&#x000d; 
_x0020_</_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_></_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>",
+                               
"<_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>\n\t<_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>_x0020_
 _x0008__x000C_&#x000a;&#x0009;&#x000d; 
_x0020_</_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>\n</_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>\n",
+                               
"<_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_><_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>_x0020_
 _x0008__x000C_&#x000a;&#x0009;&#x000d; 
_x0020_</_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_></_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>"
+                       },
+                       {
+                               "BeanWithNullProperties",
+                               new BeanWithNullProperties(),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>"
+                       },
+                       {
+                               "BeanWithAbstractFields",
+                               new BeanWithAbstractFields().init(),
+                               "<object>"
+                                       +"<a>"
+                                               +"<a>foo</a>"
+                                       +"</a>"
+                                       +"<ia _type='A'>"
+                                               +"<a>foo</a>"
+                                       +"</ia>"
+                                       +"<aa _type='A'>"
+                                               +"<a>foo</a>"
+                                       +"</aa>"
+                                       +"<o _type='A'>"
+                                               +"<a>foo</a>"
+                                       +"</o>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<a>\n"
+                                               +"\t\t<a>foo</a>\n"
+                                       +"\t</a>\n"
+                                       +"\t<ia _type='A'>\n"
+                                               +"\t\t<a>foo</a>\n"
+                                       +"\t</ia>\n"
+                                       +"\t<aa _type='A'>\n"
+                                               +"\t\t<a>foo</a>\n"
+                                       +"\t</aa>\n"
+                                       +"\t<o _type='A'>\n"
+                                               +"\t\t<a>foo</a>\n"
+                                       +"\t</o>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<a>"
+                                               +"<a>foo</a>"
+                                       +"</a>"
+                                       +"<ia _type='A'>"
+                                               +"<a>foo</a>"
+                                       +"</ia>"
+                                       +"<aa _type='A'>"
+                                               +"<a>foo</a>"
+                                       +"</aa>"
+                                       +"<o _type='A'>"
+                                               +"<a>foo</a>"
+                                       +"</o>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithAbstractArrayFields",
+                               new BeanWithAbstractArrayFields().init(),
+                               "<object>"
+                                       +"<a>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</a>"
+                                       +"<ia1>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</ia1>"
+                                       +"<ia2>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</ia2>"
+                                       +"<aa1>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</aa1>"
+                                       +"<aa2>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</aa2>"
+                                       +"<o1>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</o1>"
+                                       +"<o2>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</o2>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<a>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</a>\n"
+                                       +"\t<ia1>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</ia1>\n"
+                                       +"\t<ia2>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</ia2>\n"
+                                       +"\t<aa1>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</aa1>\n"
+                                       +"\t<aa2>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</aa2>\n"
+                                       +"\t<o1>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</o1>\n"
+                                       +"\t<o2>\n"
+                                               +"\t\t<A>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</A>\n"
+                                       +"\t</o2>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<a>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</a>"
+                                       +"<ia1>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</ia1>"
+                                       +"<ia2>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</ia2>"
+                                       +"<aa1>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</aa1>"
+                                       +"<aa2>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</aa2>"
+                                       +"<o1>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</o1>"
+                                       +"<o2>"
+                                               +"<A>"
+                                                       +"<a>foo</a>"
+                                               +"</A>"
+                                       +"</o2>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithAbstractMapFields",
+                               new BeanWithAbstractMapFields().init(),
+                               "<object>"
+                                       +"<a>"
+                                               +"<k1>"
+                                                       +"<a>foo</a>"
+                                               +"</k1>"
+                                       +"</a>"
+                                       +"<b>"
+                                               +"<k2 _type='A'>"
+                                                       +"<a>foo</a>"
+                                               +"</k2>"
+                                       +"</b>"
+                                       +"<c>"
+                                               +"<k3 _type='A'>"
+                                                       +"<a>foo</a>"
+                                               +"</k3>"
+                                       +"</c>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<a>\n"
+                                               +"\t\t<k1>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</k1>\n"
+                                       +"\t</a>\n"
+                                       +"\t<b>\n"
+                                               +"\t\t<k2 _type='A'>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</k2>\n"
+                                       +"\t</b>\n"
+                                       +"\t<c>\n"
+                                               +"\t\t<k3 _type='A'>\n"
+                                                       +"\t\t\t<a>foo</a>\n"
+                                               +"\t\t</k3>\n"
+                                       +"\t</c>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<a>"
+                                               +"<k1>"
+                                                       +"<a>foo</a>"
+                                               +"</k1>"
+                                       +"</a>"
+                                       +"<b>"
+                                               +"<k2 _type='A'>"
+                                                       +"<a>foo</a>"
+                                               +"</k2>"
+                                       +"</b>"
+                                       +"<c>"
+                                               +"<k3 _type='A'>"
+                                                       +"<a>foo</a>"
+                                               +"</k3>"
+                                       +"</c>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithAbstractMapArrayFields",
+                               new BeanWithAbstractMapArrayFields().init(),
+                               "<object>"
+                                       +"<a>"
+                                               +"<a1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</a1>"
+                                       +"</a>"
+                                       +"<ia>"
+                                               +"<ia1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</ia1>"
+                                               +"<ia2>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</ia2>"
+                                       +"</ia>"
+                                       +"<aa>"
+                                               +"<aa1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</aa1>"
+                                               +"<aa2>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</aa2>"
+                                       +"</aa>"
+                                       +"<o>"
+                                               +"<o1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</o1>"
+                                               +"<o2>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</o2>"
+                                       +"</o>"
+                               +"</object>",
+                               "<object>\n"
+                                       +"\t<a>\n"
+                                               +"\t\t<a1>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</a1>\n"
+                                       +"\t</a>\n"
+                                       +"\t<ia>\n"
+                                               +"\t\t<ia1>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</ia1>\n"
+                                               +"\t\t<ia2>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</ia2>\n"
+                                       +"\t</ia>\n"
+                                       +"\t<aa>\n"
+                                               +"\t\t<aa1>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</aa1>\n"
+                                               +"\t\t<aa2>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</aa2>\n"
+                                       +"\t</aa>\n"
+                                       +"\t<o>\n"
+                                               +"\t\t<o1>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</o1>\n"
+                                               +"\t\t<o2>\n"
+                                                       +"\t\t\t<A>\n"
+                                                               
+"\t\t\t\t<a>foo</a>\n"
+                                                       +"\t\t\t</A>\n"
+                                               +"\t\t</o2>\n"
+                                       +"\t</o>\n"
+                               +"</object>\n",
+                               "<object>"
+                                       +"<a>"
+                                               +"<a1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</a1>"
+                                       +"</a>"
+                                       +"<ia>"
+                                               +"<ia1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</ia1>"
+                                               +"<ia2>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</ia2>"
+                                       +"</ia>"
+                                       +"<aa>"
+                                               +"<aa1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</aa1>"
+                                               +"<aa2>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</aa2>"
+                                       +"</aa>"
+                                       +"<o>"
+                                               +"<o1>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</o1>"
+                                               +"<o2>"
+                                                       +"<A>"
+                                                               +"<a>foo</a>"
+                                                       +"</A>"
+                                               +"</o2>"
+                                       +"</o>"
+                               +"</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextFields-1",
+                               new BeanWithWhitespaceTextFields().init(null),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextFields-2",
+                               new BeanWithWhitespaceTextFields().init(""),
+                               "<object>_xE000_</object>",
+                               "<object>_xE000_</object>\n",
+                               "<object>_xE000_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextFields-3",
+                               new BeanWithWhitespaceTextFields().init(" "),
+                               "<object>_x0020_</object>",
+                               "<object>_x0020_</object>\n",
+                               "<object>_x0020_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextFields-4",
+                               new BeanWithWhitespaceTextFields().init("  "),
+                               "<object>_x0020__x0020_</object>",
+                               "<object>_x0020__x0020_</object>\n",
+                               "<object>_x0020__x0020_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextFields-5",
+                               new BeanWithWhitespaceTextFields().init(" 
foo\n\tbar "),
+                               
"<object>_x0020_foo&#x000a;&#x0009;bar_x0020_</object>",
+                               
"<object>_x0020_foo&#x000a;&#x0009;bar_x0020_</object>\n",
+                               
"<object>_x0020_foo&#x000a;&#x0009;bar_x0020_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextPwsFields-1",
+                               new 
BeanWithWhitespaceTextPwsFields().init(null),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextPwsFields-2",
+                               new BeanWithWhitespaceTextPwsFields().init(""),
+                               "<object>_xE000_</object>",
+                               "<object>_xE000_</object>\n",
+                               "<object>_xE000_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextPwsFields-3",
+                               new BeanWithWhitespaceTextPwsFields().init(" "),
+                               "<object> </object>",
+                               "<object> </object>\n",
+                               "<object> </object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextPwsFields-4",
+                               new BeanWithWhitespaceTextPwsFields().init("  
"),
+                               "<object>  </object>",
+                               "<object>  </object>\n",
+                               "<object>  </object>",
+                       },
+                       {
+                               "BeanWithWhitespaceTextPwsFields-5",
+                               new BeanWithWhitespaceTextPwsFields().init("  
foobar  "),
+                               "<object>  foobar  </object>",
+                               "<object>  foobar  </object>\n",
+                               "<object>  foobar  </object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedFields-1",
+                               new BeanWithWhitespaceMixedFields().init(null),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedFields-2",
+                               new BeanWithWhitespaceMixedFields().init(new 
String[0]),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedFields-3",
+                               new BeanWithWhitespaceMixedFields().init(new 
String[]{""}),
+                               "<object>_xE000_</object>",
+                               "<object>_xE000_</object>\n",
+                               "<object>_xE000_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedFields-4",
+                               new BeanWithWhitespaceMixedFields().init(new 
String[]{" "}),
+                               "<object>_x0020_</object>",
+                               "<object>_x0020_</object>\n",
+                               "<object>_x0020_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedFields-5",
+                               new BeanWithWhitespaceMixedFields().init(new 
String[]{"  "}),
+                               "<object>_x0020__x0020_</object>",
+                               "<object>_x0020__x0020_</object>\n",
+                               "<object>_x0020__x0020_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedFields-6",
+                               new BeanWithWhitespaceMixedFields().init(new 
String[]{"  foobar  "}),
+                               "<object>_x0020_ foobar _x0020_</object>",
+                               "<object>_x0020_ foobar _x0020_</object>\n",
+                               "<object>_x0020_ foobar _x0020_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedPwsFields-1",
+                               new 
BeanWithWhitespaceMixedPwsFields().init(null),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedPwsFields-2",
+                               new BeanWithWhitespaceMixedPwsFields().init(new 
String[0]),
+                               "<object/>",
+                               "<object/>\n",
+                               "<object/>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedPwsFields-3",
+                               new BeanWithWhitespaceMixedPwsFields().init(new 
String[]{""}),
+                               "<object>_xE000_</object>",
+                               "<object>_xE000_</object>\n",
+                               "<object>_xE000_</object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedPwsFields-4",
+                               new BeanWithWhitespaceMixedPwsFields().init(new 
String[]{" "}),
+                               "<object> </object>",
+                               "<object> </object>\n",
+                               "<object> </object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedPwsFields-5",
+                               new BeanWithWhitespaceMixedPwsFields().init(new 
String[]{"  "}),
+                               "<object>  </object>",
+                               "<object>  </object>\n",
+                               "<object>  </object>",
+                       },
+                       {
+                               "BeanWithWhitespaceMixedPwsFields-6",
+                               new BeanWithWhitespaceMixedPwsFields().init(new 
String[]{"  foobar  "}),
+                               "<object>  foobar  </object>",
+                               "<object>  foobar  </object>\n",
+                               "<object>  foobar  </object>",
+                       },
+               });
+       }
+
+       private String label, e1, e2, e3;
+       private Object in;
+
+       public BasicXmlTest(String label, Object in, String e1, String e2, 
String e3) throws Exception {
+               this.label = label;
+               this.in = in;
+               this.e1 = e1;
+               this.e2 = e2;
+               this.e3 = e3;
+       }
+
+       @Test
+       public void serializeNormal() {
+               try {
+                       String r = s1.serialize(in);
+                       assertEquals(label + " serialize-normal failed", e1, r);
+               } catch (AssertionError e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new RuntimeException(label + " test failed", e);
+               }
+       }
+
+       @Test
+       public void parseNormal() {
+               try {
+                       String r = s1.serialize(in);
+                       Class<?> c = in == null ? Object.class : in.getClass();
+                       Object o = parser.parse(r, c);
+                       r = s1.serialize(o);
+                       assertEquals(label + " parse-normal failed", e1, r);
+               } catch (AssertionError e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new RuntimeException(label + " test failed", e);
+               }
+       }
+
+       @Test
+       public void serializeReadable() {
+               try {
+                       String r = s2.serialize(in);
+                       assertEquals(label + " serialize-readable failed", e2, 
r);
+               } catch (AssertionError e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new RuntimeException(label + " test failed", e);
+               }
+       }
+
+       @Test
+       public void parseReadable() {
+               try {
+                       String r = s2.serialize(in);
+                       Class<?> c = in == null ? Object.class : in.getClass();
+                       Object o = parser.parse(r, c);
+                       r = s2.serialize(o);
+                       assertEquals(label + " parse-readable failed", e2, r);
+               } catch (AssertionError e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new RuntimeException(label + " test failed", e);
+               }
+       }
+
+       @Test
+       public void serializeNsEnabled() {
+               try {
+                       String r = s3.serialize(in);
+                       assertEquals(label + " serialize-ns-enabled failed", 
e3, r);
+               } catch (AssertionError e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new RuntimeException(label + " test failed", e);
+               }
+       }
+
+       @Test
+       public void parseNsEnabled() {
+               try {
+                       String r = s3.serialize(in);
+                       Class<?> c = in == null ? Object.class : in.getClass();
+                       Object o = parser.parse(r, c);
+                       r = s3.serialize(o);
+                       assertEquals(label + " parse-ns-enabled failed", e3, r);
+               } catch (AssertionError e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new RuntimeException(label + " test failed", e);
+               }
+       }
+
+
+       
//--------------------------------------------------------------------------------
+       // Test beans
+       
//--------------------------------------------------------------------------------
+
+       public static class MapWithStrings extends LinkedHashMap<String,String> 
{
+               public MapWithStrings append(String key, String value) {
+                       put(key, value);
+                       return this;
+               }
+       }
+
+       public static class MapWithNumbers extends LinkedHashMap<String,Number> 
{
+               public MapWithNumbers append(String key, Number value) {
+                       put(key, value);
+                       return this;
+               }
+       }
+
+       public static class MapWithObjects extends LinkedHashMap<String,Object> 
{
+               public MapWithObjects append(String key, Object value) {
+                       put(key, value);
+                       return this;
+               }
+       }
+
+       public static class ListWithStrings extends ArrayList<String> {
+               public ListWithStrings append(String value) {
+                       this.add(value);
+                       return this;
+               }
+       }
+
+       public static class ListWithNumbers extends ArrayList<Number> {
+               public ListWithNumbers append(Number value) {
+                       this.add(value);
+                       return this;
+               }
+       }
+
+       public static class ListWithObjects extends ArrayList<Object> {
+               public ListWithObjects append(Object value) {
+                       this.add(value);
+                       return this;
+               }
+       }
+
+       public static class BeanWithNormalProperties {
+               public String a;
+               public int b;
+               public Object c;
+               public Object d;
+               public Bean1a e;
+               public String[] f;
+               public int[] g;
+
+               BeanWithNormalProperties init() {
+                       a = "foo";
+                       b = 123;
+                       c = "bar";
+                       d = 456;
+                       e = new Bean1a().init();
+                       f = new String[]{ "baz" };
+                       g = new int[]{ 789 };
+                       return this;
+               }
+       }
+
+       public static class Bean1a {
+               public String h;
+
+               Bean1a init() {
+                       h = "qux";
+                       return this;
+               }
+       }
+
+       public static class BeanWithMapProperties {
+               @BeanProperty(type=MapWithStrings.class)
+               public Map<String,String> a;
+               @BeanProperty(type=MapWithNumbers.class)
+               public Map<String,Number> b;
+               @BeanProperty(type=MapWithObjects.class)
+               public Map<String,Object> c;
+
+               BeanWithMapProperties init() {
+                       a = new MapWithStrings().append("k1","foo");
+                       b = new MapWithNumbers().append("k2",123);
+                       c = new 
MapWithObjects().append("k3","bar").append("k4",456).append("k5",true).append("k6",null);
+                       return this;
+               }
+       }
+
+       @Bean(typeName="X")
+       public static class BeanWithTypeName {
+               public int a;
+               public String b;
+
+               BeanWithTypeName init() {
+                       a = 123;
+                       b = "foo";
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={B.class})
+       public static class BeanWithPropertiesWithTypeNames {
+               public B b1;
+               public Object b2;
+
+               BeanWithPropertiesWithTypeNames init() {
+                       b1 = new B().init();
+                       b2 = new B().init();
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={B.class})
+       public static class BeanWithPropertiesWithArrayTypeNames {
+               public B[] b1;
+               public Object[] b2;
+               public Object[] b3;
+
+               BeanWithPropertiesWithArrayTypeNames init() {
+                       b1 = new B[]{new B().init()};
+                       b2 = new B[]{new B().init()};
+                       b3 = new Object[]{new B().init()};
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={B.class})
+       public static class BeanWithPropertiesWith2dArrayTypeNames {
+               public B[][] b1;
+               public Object[][] b2;
+               public Object[][] b3;
+
+               BeanWithPropertiesWith2dArrayTypeNames init() {
+                       b1 = new B[][]{{new B().init()}};
+                       b2 = new B[][]{{new B().init()}};
+                       b3 = new Object[][]{{new B().init()}};
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={B.class})
+       public static class BeanWithPropertiesWithMapTypeNames {
+               public Map<String,B> b1;
+               public Map<String,Object> b2;
+
+               BeanWithPropertiesWithMapTypeNames init() {
+                       b1 = new HashMap<String,B>();
+                       b1.put("k1", new B().init());
+                       b2 = new HashMap<String,Object>();
+                       b2.put("k2", new B().init());
+                       return this;
+               }
+       }
+
+       @Bean(typeName="B")
+       public static class B {
+               public String b;
+
+               B init() {
+                       b = "foo";
+                       return this;
+               }
+       }
+
+       public static class BeanWithChildTypeNames {
+               public BeanX a;
+               @BeanProperty(beanDictionary=BeanX.class)
+               public Object b;
+               public BeanX[] c;
+               @BeanProperty(beanDictionary=BeanX.class)
+               public Object[] d;
+               BeanWithChildTypeNames init() {
+                       a = new BeanX().init();
+                       b = new BeanX().init();
+                       c = new BeanX[]{new BeanX().init()};
+                       d = new Object[]{new BeanX().init()};
+                       return this;
+               }
+       }
+
+       public static class BeanWithChildName {
+               @Xml(childName = "X")
+               public String[] a;
+               @Xml(childName = "Y")
+               public int[] b;
+               BeanWithChildName init() {
+                       a = new String[] { "foo", "bar" };
+                       b = new int[] { 123, 456 };
+                       return this;
+               }
+       }
+
+       public static class BeanWithXmlFormatAttrProperty {
+               @Xml(format=XmlFormat.ATTR)
+               public String a;
+               @Xml(format=XmlFormat.ATTR)
+               public int b;
+               BeanWithXmlFormatAttrProperty init() {
+                       a = "foo";
+                       b = 123;
+                       return this;
+               }
+       }
+
+       @Xml(format=XmlFormat.ATTRS)
+       public static class BeanWithXmlFormatAttrs {
+               public String a;
+               public int b;
+               BeanWithXmlFormatAttrs init() {
+                       a = "foo";
+                       b = 123;
+                       return this;
+               }
+       }
+
+       @Xml(format=XmlFormat.ATTRS)
+       public static class BeanWithXmlFormatElementProperty {
+               public String a;
+               @Xml(format=XmlFormat.ELEMENT)
+               public int b;
+               BeanWithXmlFormatElementProperty init() {
+                       a = "foo";
+                       b = 123;
+                       return this;
+               }
+       }
+
+       public static class BeanWithXmlFormatAttrsProperty {
+               @Xml(format=XmlFormat.ATTRS)
+               public Map<String,Object> a;
+               @Xml(format=XmlFormat.ATTR)
+               public int b;
+               BeanWithXmlFormatAttrsProperty init() {
+                       a = new ObjectMap().append("k1", "foo").append("k2", 
123);
+                       b = 456;
+                       return this;
+               }
+       }
+
+       public static class BeanWithXmlFormatCollapsedProperty {
+               @Xml(childName="A",format=XmlFormat.COLLAPSED)
+               public String[] a;
+               @Xml(childName="B",format=XmlFormat.COLLAPSED)
+               public int[] b;
+               BeanWithXmlFormatCollapsedProperty init() {
+                       a = new String[]{"foo","bar"};
+                       b = new int[]{123,456};
+                       return this;
+               }
+       }
+
+       public static class BeanWithXmlFormatTextProperty {
+               @Xml(format=XmlFormat.ATTR)
+               public String a;
+               @Xml(format=XmlFormat.TEXT)
+               public String b;
+               BeanWithXmlFormatTextProperty init() {
+                       a = "foo";
+                       b = "bar";
+                       return this;
+               }
+       }
+
+       public static class BeanWithXmlFormatXmlTextProperty {
+               @Xml(format=XmlFormat.ATTR)
+               public String a;
+               @Xml(format=XmlFormat.XMLTEXT)
+               public String b;
+               BeanWithXmlFormatXmlTextProperty init() {
+                       a = "foo";
+                       b = "bar<b>baz</b>qux";
+                       return this;
+               }
+       }
+
+       public static class BeanWithXmlFormatElementsPropertyCollection {
+               @Xml(format=XmlFormat.ATTR)
+               public String a;
+               @Xml(format=XmlFormat.ELEMENTS)
+               public Object[] b;
+               BeanWithXmlFormatElementsPropertyCollection init() {
+                       a = "foo";
+                       b = new Object[]{"bar","baz",123,true,null};
+                       return this;
+               }
+       }
+
+       public static class BeanWithMixedContent {
+               @Xml(format=XmlFormat.MIXED)
+               @BeanProperty(beanDictionary={BeanXSimple.class, 
BeanYSimple.class})
+               public Object[] a;
+               BeanWithMixedContent init() {
+                       a = new Object[]{
+                               "foo",
+                               new BeanXSimple().init(),
+                               "bar",
+                               new BeanYSimple().init(),
+                               "baz"
+                       };
+                       return this;
+               }
+       }
+
+       @Bean(typeName="X")
+       public static class BeanX {
+               public String fx;
+               BeanX init() {
+                       fx = "fx1";
+                       return this;
+               }
+       }
+
+       @Bean(typeName="X")
+       public static class BeanXSimple {
+               @Xml(format=XmlFormat.ATTR)
+               public String fx;
+               BeanXSimple init() {
+                       fx = "fx1";
+                       return this;
+               }
+       }
+
+       @Bean(typeName="Y")
+       public static class BeanY {
+               public String fy;
+               BeanY init() {
+                       fy = "fy1";
+                       return this;
+               }
+       }
+
+       @Bean(typeName="Y")
+       public static class BeanYSimple {
+               @Xml(format=XmlFormat.ATTR)
+               public String fy;
+               BeanYSimple init() {
+                       fy = "fy1";
+                       return this;
+               }
+       }
+
+       public static class BeanWithSpecialCharacters {
+               public String a;
+
+               BeanWithSpecialCharacters init() {
+                       a = "  \b\f\n\t\r  ";
+                       return this;
+               }
+       }
+
+       @Bean(typeName="  \b\f\n\t\r  ")
+       public static class BeanWithSpecialCharacters2 {
+
+               @BeanProperty(name="  \b\f\n\t\r  ")
+               public String a;
+
+               BeanWithSpecialCharacters2 init() {
+                       a = "  \b\f\n\t\r  ";
+                       return this;
+               }
+       }
+
+       public static class BeanWithNullProperties {
+               public String a;
+               public String[] b;
+       }
+
+       @Bean(beanDictionary={A.class})
+       public static class BeanWithAbstractFields {
+               public A a;
+               public IA ia;
+               public AA aa;
+               public Object o;
+
+               BeanWithAbstractFields init() {
+                       ia = new A().init();
+                       aa = new A().init();
+                       a = new A().init();
+                       o = new A().init();
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={A.class})
+       public static class BeanWithAbstractArrayFields {
+               public A[] a;
+               public IA[] ia1, ia2;
+               public AA[] aa1, aa2;
+               public Object[] o1, o2;
+
+               BeanWithAbstractArrayFields init() {
+                       a = new A[]{new A().init()};
+                       ia1 = new A[]{new A().init()};
+                       aa1 = new A[]{new A().init()};
+                       o1 = new A[]{new A().init()};
+                       ia2 = new IA[]{new A().init()};
+                       aa2 = new AA[]{new A().init()};
+                       o2 = new Object[]{new A().init()};
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={A.class})
+       public static class BeanWithAbstractMapFields {
+               public Map<String,A> a;
+               public Map<String,AA> b;
+               public Map<String,Object> c;
+
+               BeanWithAbstractMapFields init() {
+                       a = new HashMap<String,A>();
+                       b = new HashMap<String,AA>();
+                       c = new HashMap<String,Object>();
+                       a.put("k1", new A().init());
+                       b.put("k2", new A().init());
+                       c.put("k3", new A().init());
+                       return this;
+               }
+       }
+
+       @Bean(beanDictionary={A.class})
+       public static class BeanWithAbstractMapArrayFields {
+               public Map<String,A[]> a;
+               public Map<String,IA[]> ia;
+               public Map<String,AA[]> aa;
+               public Map<String,Object[]> o;
+
+               BeanWithAbstractMapArrayFields init() {
+                       a = new LinkedHashMap<String,A[]>();
+                       ia = new LinkedHashMap<String,IA[]>();
+                       aa = new LinkedHashMap<String,AA[]>();
+                       o = new LinkedHashMap<String,Object[]>();
+                       a.put("a1", new A[]{new A().init()});
+                       ia.put("ia1", new A[]{new A().init()});
+                       ia.put("ia2", new IA[]{new A().init()});
+                       aa.put("aa1", new A[]{new A().init()});
+                       aa.put("aa2", new AA[]{new A().init()});
+                       o.put("o1", new A[]{new A().init()});
+                       o.put("o2", new Object[]{new A().init()});
+                       return this;
+               }
+       }
+
+       public static interface IA {
+               public String getA();
+               public void setA(String a);
+       }
+
+       public static abstract class AA implements IA {}
+
+       @Bean(typeName="A")
+       public static class A extends AA {
+               private String a;
+
+               @Override
+               public String getA() {
+                       return a;
+               }
+
+               @Override
+               public void setA(String a) {
+                       this.a = a;
+               }
+
+               A init() {
+                       this.a = "foo";
+                       return this;
+               }
+       }
+
+       public static class BeanWithWhitespaceTextFields {
+               @Xml(format=XmlFormat.TEXT)
+               public String a;
+
+               public BeanWithWhitespaceTextFields init(String s) {
+                       a = s;
+                       return this;
+               }
+       }
+
+       public static class BeanWithWhitespaceTextPwsFields {
+               @Xml(format=XmlFormat.TEXT_PWS)
+               public String a;
+
+               public BeanWithWhitespaceTextPwsFields init(String s) {
+                       a = s;
+                       return this;
+               }
+       }
+
+       public static class BeanWithWhitespaceMixedFields {
+               @Xml(format=XmlFormat.MIXED)
+               public String[] a;
+
+               public BeanWithWhitespaceMixedFields init(String[] s) {
+                       a = s;
+                       return this;
+               }
+       }
+
+       public static class BeanWithWhitespaceMixedPwsFields {
+               @Xml(format=XmlFormat.MIXED_PWS)
+               public String[] a;
+
+               public BeanWithWhitespaceMixedPwsFields init(String[] s) {
+                       a = s;
+                       return this;
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
new file mode 100755
index 0000000..5fba9a1
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
@@ -0,0 +1,178 @@
+// 
***************************************************************************************************************************
+// * 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.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.parser.*;
+import org.junit.*;
+
+@SuppressWarnings({"rawtypes","serial","javadoc"})
+public class CommonParserTest {
+
+       
//====================================================================================================
+       // testFromSerializer
+       
//====================================================================================================
+       @Test
+       public void testFromSerializer() throws Exception {
+               ReaderParser p = XmlParser.DEFAULT;
+
+               Map m = null;
+               m = (Map)p.parse("<object><a _type='number'>1</a></object>", 
Object.class);
+               assertEquals(1, m.get("a"));
+               m = (Map)p.parse("<object><a _type='number'>1</a><b 
_type='string'>foo bar</b></object>", Object.class);
+               assertEquals(1, m.get("a"));
+               assertEquals("foo bar", m.get("b"));
+               m = (Map)p.parse("<object><a _type='number'>1</a><b 
_type='string'>foo bar</b><c _type='boolean'>false</c></object>", Object.class);
+               assertEquals(1, m.get("a"));
+               assertEquals(false, m.get("c"));
+               m = (Map)p.parse("   <object>   <a _type='number'>      1       
</a>    <b _type='string'>      foo     </b>    <c _type='boolean'>     false   
</c>    </object>       ", Object.class);
+               assertEquals(1, m.get("a"));
+               assertEquals("foo", m.get("b"));
+               assertEquals(false, m.get("c"));
+
+               m = (Map)p.parse("<object><x 
_type='string'>org.apache.juneau.test.Person</x><addresses 
_type='array'><object><x _type='string'>org.apache.juneau.test.Address</x><city 
_type='string'>city A</city><state _type='string'>state A</state><street 
_type='string'>street A</street><zip 
_type='number'>12345</zip></object></addresses></object>", Object.class);
+               assertEquals("org.apache.juneau.test.Person", m.get("x"));
+               List l = (List)m.get("addresses");
+               assertNotNull(l);
+               m = (Map)l.get(0);
+               assertNotNull(m);
+               assertEquals("org.apache.juneau.test.Address", m.get("x"));
+               assertEquals("city A", m.get("city"));
+               assertEquals("state A", m.get("state"));
+               assertEquals("street A", m.get("street"));
+               assertEquals(12345, m.get("zip"));
+
+               ObjectList jl = (ObjectList)p.parse("<array><object><attribute 
_type='string'>value</attribute></object><object><attribute 
_type='string'>value</attribute></object></array>", Object.class);
+               assertEquals("value", 
jl.getObjectMap(0).getString("attribute"));
+               assertEquals("value", 
jl.getObjectMap(1).getString("attribute"));
+
+               try {
+                       jl = (ObjectList)p.parse("<array><object><attribute 
_type='string'>value</attribute></object><object><attribute 
_type='string'>value</attribute></object></array>", Object.class);
+                       assertEquals("value", 
jl.getObjectMap(0).getString("attribute"));
+                       assertEquals("value", 
jl.getObjectMap(1).getString("attribute"));
+               } catch (Exception e) {
+                       fail(e.getLocalizedMessage());
+               }
+
+               A1 t1 = new A1();
+               A2 t2 = new A2();
+               t2.add(new A3("name0","value0"));
+               t2.add(new A3("name1","value1"));
+               t1.list = t2;
+               String r = XmlSerializer.DEFAULT_NS.serialize(t1);
+               t1 = p.parse(r, A1.class);
+               assertEquals("value1", t1.list.get(1).value);
+
+               r = XmlSerializer.DEFAULT_NS.serialize(t1);
+               t1 = p.parse(r, A1.class);
+               assertEquals("value1", t1.list.get(1).value);
+       }
+
+       public static class A1 {
+               public A2 list;
+       }
+
+       public static class A2 extends LinkedList<A3> {
+       }
+
+       public static class A3 {
+               public String name, value;
+               public A3(){}
+               public A3(String name, String value) {
+                       this.name = name;
+                       this.value = value;
+               }
+       }
+
+       
//====================================================================================================
+       // Correct handling of unknown properties.
+       
//====================================================================================================
+       @Test
+       public void testCorrectHandlingOfUnknownProperties() throws Exception {
+               ReaderParser p = new 
XmlParserBuilder().ignoreUnknownBeanProperties(true).build();
+               B t;
+
+               String in =  
"<object><a>1</a><unknown>foo</unknown><b>2</b></object>";
+               t = p.parse(in, B.class);
+               assertEquals(t.a, 1);
+               assertEquals(t.b, 2);
+
+               in =  "<object><a>1</a><unknown><object><a 
_type='string'>foo</a></object></unknown><b>2</b></object>";
+               t = p.parse(in, B.class);
+               assertEquals(t.a, 1);
+               assertEquals(t.b, 2);
+
+
+               try {
+                       p = XmlParser.DEFAULT;
+                       p.parse(in, B.class);
+                       fail("Exception expected");
+               } catch (ParseException e) {}
+       }
+
+       public static class B {
+               public int a, b;
+       }
+
+       
//====================================================================================================
+       // Writing to Collection properties with no setters.
+       
//====================================================================================================
+       @Test
+       public void testCollectionPropertiesWithNoSetters() throws Exception {
+
+               ReaderParser p = XmlParser.DEFAULT;
+
+               String in = "<object><ints 
_type='array'><number>1</number><number>2</number><number>3</number></ints><beans
 _type='array'><object><a _type='number'>1</a><b 
_type='number'>2</b></object></beans></object>";
+               C t = p.parse(in, C.class);
+               assertEquals(t.getInts().size(), 3);
+               assertEquals(t.getBeans().get(0).b, 2);
+       }
+
+       public static class C {
+               private Collection<Integer> ints = new LinkedList<Integer>();
+               private List<B> beans = new LinkedList<B>();
+               public Collection<Integer> getInts() {
+                       return ints;
+               }
+               public List<B> getBeans() {
+                       return beans;
+               }
+       }
+
+       
//====================================================================================================
+       // Parser listeners.
+       
//====================================================================================================
+       @Test
+       public void testParserListeners() throws Exception {
+               XmlParser p = new 
XmlParserBuilder().ignoreUnknownBeanProperties(true).listener(MyParserListener.class).build();
+
+               String in = "<object><a _type='number'>1</a><unknownProperty 
_type='string'>foo</unknownProperty><b _type='number'>2</b></object>";
+               p.parse(in, B.class);
+               assertEquals(1, MyParserListener.events.size());
+               // XML parser may or may not support line numbers.
+               
assertTrue(MyParserListener.events.get(0).startsWith("unknownProperty,"));
+       }
+
+       public static class MyParserListener extends ParserListener {
+               final static List<String> events = new LinkedList<String>();
+
+               @Override /* ParserListener */
+               public <T> void onUnknownBeanProperty(ParserSession session, 
ParserPipe pipe, String propertyName, Class<T> beanClass, T bean, int line, int 
col) {
+                       events.add(propertyName + "," + line + "," + col);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
new file mode 100755
index 0000000..3e8563f
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
@@ -0,0 +1,304 @@
+// 
***************************************************************************************************************************
+// * 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.TestUtils.*;
+import static org.apache.juneau.xml.annotation.XmlFormat.*;
+import static org.junit.Assert.*;
+
+import java.net.*;
+import java.net.URI;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.jena.annotation.*;
+import org.apache.juneau.utils.*;
+import org.apache.juneau.xml.annotation.*;
+import org.junit.*;
+
+@SuppressWarnings({"serial","javadoc"})
+public class CommonTest {
+
+       
//====================================================================================================
+       // Trim nulls from beans
+       
//====================================================================================================
+       @Test
+       public void testTrimNullsFromBeans() throws Exception {
+               XmlSerializerBuilder s = new XmlSerializerBuilder().sq();
+               XmlParser p = XmlParser.DEFAULT;
+               A t1 = A.create(), t2;
+
+               s.trimNullProperties(false);
+               String r = s.build().serialize(t1);
+               assertEquals("<object><s1 _type='null'/><s2>s2</s2></object>", 
r);
+               t2 = p.parse(r, A.class);
+               assertEqualObjects(t1, t2);
+
+               s.trimNullProperties(true);
+               r = s.build().serialize(t1);
+               assertEquals("<object><s2>s2</s2></object>", r);
+               t2 = p.parse(r, A.class);
+               assertEqualObjects(t1, t2);
+       }
+
+       public static class A {
+               public String s1, s2;
+
+               public static A create() {
+                       A t = new A();
+                       t.s2 = "s2";
+                       return t;
+               }
+       }
+
+       
//====================================================================================================
+       // Trim empty maps
+       
//====================================================================================================
+       @Test
+       public void testTrimEmptyMaps() throws Exception {
+               XmlSerializerBuilder s = new XmlSerializerBuilder().sq();
+               XmlParser p = XmlParser.DEFAULT;
+               B t1 = B.create(), t2;
+               String r;
+
+               s.trimEmptyMaps(false);
+               r = s.build().serialize(t1);
+               assertEquals("<object><f1/><f2><f2a 
_type='null'/><f2b><s2>s2</s2></f2b></f2></object>", r);
+               t2 = p.parse(r, B.class);
+               assertEqualObjects(t1, t2);
+
+               s.trimEmptyMaps(true);
+               r = s.build().serialize(t1);
+               assertEquals("<object><f2><f2a 
_type='null'/><f2b><s2>s2</s2></f2b></f2></object>", r);
+               t2 = p.parse(r, B.class);
+               assertNull(t2.f1);
+       }
+
+       public static class B {
+               public TreeMap<String,A> f1, f2;
+
+               public static B create() {
+                       B t = new B();
+                       t.f1 = new TreeMap<String,A>();
+                       t.f2 = new 
TreeMap<String,A>(){{put("f2a",null);put("f2b",A.create());}};
+                       return t;
+               }
+       }
+
+       
//====================================================================================================
+       // Trim empty lists
+       
//====================================================================================================
+       @Test
+       public void testTrimEmptyLists() throws Exception {
+               XmlSerializerBuilder s = new XmlSerializerBuilder().sq();
+               XmlParser p = XmlParser.DEFAULT;
+               C t1 = C.create(), t2;
+               String r;
+
+               s.trimEmptyCollections(false);
+               r = s.build().serialize(t1);
+               
assertEquals("<object><f1></f1><f2><null/><object><s2>s2</s2></object></f2></object>",
 r);
+               t2 = p.parse(r, C.class);
+               assertEqualObjects(t1, t2);
+
+               s.trimEmptyCollections(true);
+               r = s.build().serialize(t1);
+               
assertEquals("<object><f2><null/><object><s2>s2</s2></object></f2></object>", 
r);
+               t2 = p.parse(r, C.class);
+               assertNull(t2.f1);
+       }
+
+       public static class C {
+               public List<A> f1, f2;
+
+               public static C create() {
+                       C t = new C();
+                       t.f1 = new AList<A>();
+                       t.f2 = new AList<A>().append(null).append(A.create());
+                       return t;
+               }
+       }
+
+       
//====================================================================================================
+       // Trim empty arrays
+       
//====================================================================================================
+       @Test
+       public void testTrimEmptyArrays() throws Exception {
+               XmlSerializerBuilder s = new XmlSerializerBuilder().sq();
+               XmlParser p = XmlParser.DEFAULT;
+               D t1 = D.create(), t2;
+               String r;
+
+               s.trimEmptyCollections(false);
+               r = s.build().serialize(t1);
+               
assertEquals("<object><f1></f1><f2><null/><object><s2>s2</s2></object></f2></object>",
 r);
+               t2 = p.parse(r, D.class);
+               assertEqualObjects(t1, t2);
+
+               s.trimEmptyCollections(true);
+               r = s.build().serialize(t1);
+               
assertEquals("<object><f2><null/><object><s2>s2</s2></object></f2></object>", 
r);
+               t2 = p.parse(r, D.class);
+               assertNull(t2.f1);
+       }
+
+       public static class D {
+               public A[] f1, f2;
+
+               public static D create() {
+                       D t = new D();
+                       t.f1 = new A[]{};
+                       t.f2 = new A[]{null, A.create()};
+                       return t;
+               }
+       }
+
+       
//====================================================================================================
+       // @BeanProperty.properties annotation.
+       
//====================================================================================================
+       @Test
+       public void testBeanPropertyProperties() throws Exception {
+               XmlSerializer s = XmlSerializer.DEFAULT_SQ;
+               E1 t = new E1();
+               String r = s.serialize(t);
+               assertEquals(
+                       "<object>"
+                               +"<x1 f2='2'><f1>1</f1></x1>"
+                               +"<x2><f1>1</f1></x2>"
+                               +"<x3><object f2='2'><f1>1</f1></object></x3>"
+                               +"<x4><object f2='2'><f1>1</f1></object></x4>"
+                               +"<x5><object><f1 
_type='number'>1</f1></object></x5>"
+                               +"<x6><object><f1 
_type='number'>1</f1></object></x6>"
+                       +"</object>",
+                       r);
+               TestUtils.validateXml(t);
+       }
+
+       public static class E1 {
+               @BeanProperty(properties="f1,f2") public E2 x1 = new E2();
+               @BeanProperty(properties="f1,f2") public Map<String,Integer> x2 
= new AMap<String,Integer>().append("f1",1).append("f3",3);
+               @BeanProperty(properties="f1,f2") public E2[] x3 = {new E2()};
+               @BeanProperty(properties="f1,f2") public List<E2> x4 = new 
AList<E2>().append(new E2());
+               @BeanProperty(properties="f1") public ObjectMap[] x5 = {new 
ObjectMap().append("f1",1).append("f3",3)};
+               @BeanProperty(properties="f1") public List<ObjectMap> x6 = new 
AList<ObjectMap>().append(new ObjectMap().append("f1",1).append("f3",3));
+       }
+
+       public static class E2 {
+               public int f1 = 1;
+               @Xml(format=ATTR) public int f2 = 2;
+               public int f3 = 3;
+               @Xml(format=ATTR) public int f4 = 4;
+       }
+
+       
//====================================================================================================
+       // @BeanProperty.properties annotation on list of beans.
+       
//====================================================================================================
+       @Test
+       public void testBeanPropertyPropertiesOnListOfBeans() throws Exception {
+               XmlSerializer s = XmlSerializer.DEFAULT_SQ;
+               List<Test7b> l = new LinkedList<Test7b>();
+               Test7b t = new Test7b();
+               t.x1.add(new Test7b());
+               l.add(t);
+               String xml = s.serialize(l);
+               
assertEquals("<array><object><x1><object><x2>2</x2></object></x1><x2>2</x2></object></array>",
 xml);
+       }
+
+       public static class Test7b {
+               @BeanProperty(properties="x2") public List<Test7b> x1 = new 
LinkedList<Test7b>();
+               public int x2 = 2;
+       }
+
+       
//====================================================================================================
+       // Test that URLs and URIs are serialized and parsed correctly.
+       
//====================================================================================================
+       @Test
+       public void testURIAttr() throws Exception {
+               XmlSerializer s = XmlSerializer.DEFAULT_SQ;
+               XmlParser p = XmlParser.DEFAULT;
+
+               G t = new G();
+               t.uri = new URI("http://uri";);
+               t.f1 = new URI("http://f1";);
+               t.f2 = new URL("http://f2";);
+
+               String xml = s.serialize(t);
+               t = p.parse(xml, G.class);
+               assertEquals("http://uri";, t.uri.toString());
+               assertEquals("http://f1";, t.f1.toString());
+               assertEquals("http://f2";, t.f2.toString());
+       }
+
+       public static class G {
+               @Rdf(beanUri=true) public URI uri;
+               public URI f1;
+               public URL f2;
+       }
+
+       
//====================================================================================================
+       // Recursion
+       
//====================================================================================================
+       @Test
+       public void testRecursion() throws Exception {
+               XmlSerializerBuilder s = new 
XmlSerializerBuilder().enableNamespaces(false);
+
+               R1 r1 = new R1();
+               R2 r2 = new R2();
+               R3 r3 = new R3();
+               r1.r2 = r2;
+               r2.r3 = r3;
+               r3.r1 = r1;
+
+               // No recursion detection
+               try {
+                       s.build().serialize(r1);
+                       fail("Exception expected!");
+               } catch (Exception e) {
+                       String msg = e.getLocalizedMessage();
+                       assertTrue(msg.contains("It's recommended you use the 
SerializerContext.SERIALIZER_detectRecursions setting to help locate the 
loop."));
+               }
+
+               // Recursion detection, no ignore
+               s.detectRecursions(true);
+               try {
+                       s.build().serialize(r1);
+                       fail("Exception expected!");
+               } catch (Exception e) {
+                       String msg = e.getLocalizedMessage();
+                       
assertTrue(msg.contains("[0]<noname>:org.apache.juneau.xml.CommonTest$R1"));
+                       
assertTrue(msg.contains("->[1]r2:org.apache.juneau.xml.CommonTest$R2"));
+                       
assertTrue(msg.contains("->[2]r3:org.apache.juneau.xml.CommonTest$R3"));
+                       
assertTrue(msg.contains("->[3]r1:org.apache.juneau.xml.CommonTest$R1"));
+               }
+
+               s.ignoreRecursions(true);
+               
assertEquals("<object><name>foo</name><r2><name>bar</name><r3><name>baz</name></r3></r2></object>",
 s.build().serialize(r1));
+
+               // Make sure this doesn't blow up.
+               s.build().getSchemaSerializer().serialize(r1);
+       }
+
+       public static class R1 {
+               public String name = "foo";
+               public R2 r2;
+       }
+       public static class R2 {
+               public String name = "bar";
+               public R3 r3;
+       }
+       public static class R3 {
+               public String name = "baz";
+               public R1 r1;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
new file mode 100755
index 0000000..031a879
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
@@ -0,0 +1,80 @@
+// 
***************************************************************************************************************************
+// * 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.TestUtils.*;
+import static org.apache.juneau.xml.annotation.XmlFormat.*;
+import static org.junit.Assert.*;
+
+import java.net.*;
+
+import org.apache.juneau.xml.annotation.*;
+import org.junit.*;
+
+@SuppressWarnings("javadoc")
+public class CommonXmlTest {
+
+       
//====================================================================================================
+       // Test 18a - @Bean.uri annotation
+       
//====================================================================================================
+       @Test
+       public void testBeanUriAnnotation() throws Exception {
+               XmlParser p = XmlParser.DEFAULT;
+               XmlSerializer s = XmlSerializer.DEFAULT_SQ;
+
+               A t = new A("http://foo";, 123, "bar");
+               String xml = s.serialize(t);
+               assertEquals("<object url='http://foo' 
id='123'><name>bar</name></object>", xml);
+
+               t = p.parse(xml, A.class);
+               assertEquals("http://foo";, t.url.toString());
+               assertEquals(123, t.id);
+               assertEquals("bar", t.name);
+
+               validateXml(t, s);
+       }
+
+       public static class A {
+               @Xml(format=XmlFormat.ATTR) public URL url;
+               @Xml(format=ATTR) public int id;
+               public String name;
+               public A() {}
+               public A(String url, int id, String name) throws Exception {
+                       this.url = new URL(url);
+                       this.id = id;
+                       this.name = name;
+               }
+       }
+
+       
//====================================================================================================
+       // Bean.uri annotation, only uri property
+       
//====================================================================================================
+       @Test
+       public void testBeanUriAnnotationOnlyUriProperty() throws Exception {
+               XmlSerializer s = new 
XmlSerializerBuilder().sq().addNamespaceUrisToRoot(false).build();
+
+               B t = new B("http://foo";);
+               String xml = s.serialize(t);
+               assertEquals("<object 
url='http://foo'><url2>http://foo/2</url2></object>", xml);
+       }
+
+       public static class B {
+               @Xml(format=XmlFormat.ATTR) public URL url;
+               public URL url2;
+               public B() {}
+               public B(String url) throws Exception {
+                       this.url = new URL(url);
+                       this.url2 = new URL(url+"/2");
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java
new file mode 100644
index 0000000..8d115a8
--- /dev/null
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java
@@ -0,0 +1,230 @@
+// 
***************************************************************************************************************************
+// * 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.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.xml.annotation.*;
+import org.junit.*;
+import org.junit.runner.*;
+import org.junit.runners.*;
+
+/**
+ * Verifies that the correct error messages are displayed when you do 
something wrong with the @Xml annotation.
+ */
+@RunWith(Parameterized.class)
+@SuppressWarnings({"javadoc"})
+public class InvalidXmlBeansTest {
+
+       private static final XmlSerializer
+               s1 = XmlSerializer.DEFAULT_SQ;
+
+       @Parameterized.Parameters
+       public static Collection<Object[]> getParameters() {
+               return Arrays.asList(new Object[][] {
+
+                       {
+                               "BeanWithAttrFormat",
+                               new BeanWithAttrFormat(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithAttrFormat: Invalid format 
specified in @Xml annotation on bean: ATTR.  Must be one of the following: 
DEFAULT,ATTRS,ELEMENTS,VOID",
+                       },
+                       {
+                               "BeanWithElementFormat",
+                               new BeanWithElementFormat(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithElementFormat: Invalid 
format specified in @Xml annotation on bean: ELEMENT.  Must be one of the 
following: DEFAULT,ATTRS,ELEMENTS,VOID",
+                       },
+                       {
+                               "BeanWithCollapsedFormat",
+                               new BeanWithCollapsedFormat(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithCollapsedFormat: Invalid 
format specified in @Xml annotation on bean: COLLAPSED.  Must be one of the 
following: DEFAULT,ATTRS,ELEMENTS,VOID",
+                       },
+                       {
+                               "BeanWithMixedFormat",
+                               new BeanWithMixedFormat(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithMixedFormat: Invalid format 
specified in @Xml annotation on bean: MIXED.  Must be one of the following: 
DEFAULT,ATTRS,ELEMENTS,VOID",
+                       },
+                       {
+                               "BeanWithMultipleAttrs",
+                               new BeanWithMultipleAttrs(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithMultipleAttrs: Multiple 
instances of ATTRS properties defined on class.  Only one property can be 
designated as such.",
+                       },
+                       {
+                               "BeanWithWrongAttrsType",
+                               new BeanWithWrongAttrsType(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithWrongAttrsType: Invalid type 
for ATTRS property.  Only properties of type Map and bean can be used.",
+                       },
+                       {
+                               "BeanWithMulipleElements",
+                               new BeanWithMulipleElements(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithMulipleElements: Multiple 
instances of ELEMENTS properties defined on class.  Only one property can be 
designated as such.",
+                       },
+                       {
+                               "BeanWithWrongElementsType",
+                               new BeanWithWrongElementsType(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithWrongElementsType: Invalid 
type for ELEMENTS property.  Only properties of type Collection and array can 
be used.",
+                       },
+                       {
+                               "BeanWithMulipleMixed",
+                               new BeanWithMulipleMixed(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithMulipleMixed: Multiple 
instances of MIXED properties defined on class.  Only one property can be 
designated as such.",
+                       },
+                       {
+                               "BeanWithConflictingChildNames",
+                               new BeanWithConflictingChildNames(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithConflictingChildNames: 
Multiple properties found with the child name 'X'.",
+                       },
+                       {
+                               "BeanWithElementsAndMixed",
+                               new BeanWithElementsAndMixed(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithElementsAndMixed: ELEMENTS 
and MIXED properties found on the same bean.  Only one property can be 
designated as such.",
+                       },
+                       {
+                               "BeanWithElementsAndElement",
+                               new BeanWithElementsAndElement(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithElementsAndElement: ELEMENTS 
and ELEMENT properties found on the same bean.  These cannot be mixed.",
+                       },
+                       {
+                               "BeanWithElementsAndDefault",
+                               new BeanWithElementsAndDefault(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithElementsAndDefault: ELEMENTS 
and ELEMENT properties found on the same bean.  These cannot be mixed.",
+                       },
+                       {
+                               "BeanWithElementsAndCollapsed",
+                               new BeanWithElementsAndCollapsed(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithElementsAndCollapsed: 
ELEMENTS and COLLAPSED properties found on the same bean.  These cannot be 
mixed.",
+                       },
+                       {
+                               "BeanWithChildAndPropNameConflict",
+                               new BeanWithChildAndPropNameConflict(),
+                               
"org.apache.juneau.xml.InvalidXmlBeansTest$BeanWithChildAndPropNameConflict: 
Child element name conflicts found with another property.",
+                       },
+               });
+       }
+
+       private String label, expected;
+       private Object in;
+
+       public InvalidXmlBeansTest(String label, Object in, String expected) 
throws Exception {
+               this.label = label;
+               this.in = in;
+               this.expected = expected;
+       }
+
+       @Test
+       public void test() {
+               try {
+                       s1.serialize(in);
+                       fail(label + ":  Expected exception didn't occur.");
+               } catch (Exception e) {
+                       assertEquals(label + ":  Wrong error message.", 
expected, e.getLocalizedMessage());
+               }
+       }
+
+       
//--------------------------------------------------------------------------------
+       // Test beans
+       
//--------------------------------------------------------------------------------
+
+       @Xml(format=XmlFormat.ATTR)
+       public static class BeanWithAttrFormat {
+               public int f1;
+       }
+
+       @Xml(format=XmlFormat.ELEMENT)
+       public static class BeanWithElementFormat {
+               public int f1;
+       }
+
+       @Xml(format=XmlFormat.COLLAPSED)
+       public static class BeanWithCollapsedFormat {
+               public int f1;
+       }
+
+       @Xml(format=XmlFormat.MIXED)
+       public static class BeanWithMixedFormat {
+               public int f1;
+       }
+
+       public static class BeanWithMultipleAttrs {
+               @Xml(format=XmlFormat.ATTRS)
+               public ObjectMap f1;
+               @Xml(format=XmlFormat.ATTRS)
+               public ObjectMap f2;
+       }
+
+       public static class BeanWithWrongAttrsType {
+               @Xml(format=XmlFormat.ATTRS)
+               public ObjectList f1;
+       }
+
+       public static class BeanWithMulipleElements {
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectList f1;
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectList f2;
+       }
+
+       public static class BeanWithWrongElementsType {
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectMap f1;
+       }
+
+       public static class BeanWithMulipleMixed {
+               @Xml(format=XmlFormat.MIXED)
+               public ObjectList f1;
+               @Xml(format=XmlFormat.MIXED)
+               public ObjectList f2;
+       }
+
+       public static class BeanWithConflictingChildNames {
+               @Xml(format=XmlFormat.COLLAPSED, childName="X")
+               public ObjectList f1;
+               @Xml(format=XmlFormat.COLLAPSED, childName="X")
+               public ObjectList f2;
+       }
+
+       public static class BeanWithElementsAndMixed {
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectList f1;
+               @Xml(format=XmlFormat.MIXED)
+               public ObjectList f2;
+       }
+
+       public static class BeanWithElementsAndElement {
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectList f1;
+               @Xml(format=XmlFormat.ELEMENT)
+               public ObjectList f2;
+       }
+
+       public static class BeanWithElementsAndDefault {
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectList f1;
+               public ObjectList f2;
+       }
+
+       public static class BeanWithElementsAndCollapsed {
+               @Xml(format=XmlFormat.ELEMENTS)
+               public ObjectList f1;
+               @Xml(format=XmlFormat.COLLAPSED)
+               public ObjectList f2;
+       }
+
+       public static class BeanWithChildAndPropNameConflict {
+               @Xml(format=XmlFormat.COLLAPSED, childName="f2")
+               public ObjectList f1;
+               public ObjectList f2;
+       }
+}

Reply via email to