juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [27/49] incubator-juneau git commit: Separate RDF and JAX-RS support into separate projects.
Date Sun, 22 Jan 2017 00:39:26 GMT
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java b/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
new file mode 100644
index 0000000..c3b9abb
--- /dev/null
+++ b/juneau-core-test/src/test/java/org/apache/juneau/xml/BasicXmlTest.java
@@ -0,0 +1,1508 @@
+// ***************************************************************************************************************************
+// * 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 _type='B^'>"
+						+"<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 _type='B^'>\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 _type='B^'>"
+						+"<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 _type='B^^'>"
+						+"<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 _type='B^^'>\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 _type='B^^'>"
+						+"<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>_x000A__x0008__x000C__x0009_</a></object>",
+				"<object>\n\t<a>_x000A__x0008__x000C__x0009_</a>\n</object>\n",
+				"<object><a>_x000A__x0008__x000C__x0009_</a></object>"
+			},
+			{
+				"BeanWithSpecialCharacters2",
+				new BeanWithSpecialCharacters2().init(),
+				"<_x0024__x0023__x0021_><_x002A__x0028__x0029_>_x000A__x0008__x000C__x0009_</_x002A__x0028__x0029_></_x0024__x0023__x0021_>",
+				"<_x0024__x0023__x0021_>\n\t<_x002A__x0028__x0029_>_x000A__x0008__x000C__x0009_</_x002A__x0028__x0029_>\n</_x0024__x0023__x0021_>\n",
+				"<_x0024__x0023__x0021_><_x002A__x0028__x0029_>_x000A__x0008__x000C__x0009_</_x002A__x0028__x0029_></_x0024__x0023__x0021_>"
+			},
+			{
+				"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 _type='A^'>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</ia1>"
+					+"<ia2>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</ia2>"
+					+"<aa1 _type='A^'>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</aa1>"
+					+"<aa2>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</aa2>"
+					+"<o1 _type='A^'>"
+						+"<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 _type='A^'>\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 _type='A^'>\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 _type='A^'>\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 _type='A^'>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</ia1>"
+					+"<ia2>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</ia2>"
+					+"<aa1 _type='A^'>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</aa1>"
+					+"<aa2>"
+						+"<A>"
+							+"<a>foo</a>"
+						+"</A>"
+					+"</aa2>"
+					+"<o1 _type='A^'>"
+						+"<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 _type='A^'>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</ia1>"
+						+"<ia2>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</ia2>"
+					+"</ia>"
+					+"<aa>"
+						+"<aa1 _type='A^'>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</aa1>"
+						+"<aa2>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</aa2>"
+					+"</aa>"
+					+"<o>"
+						+"<o1 _type='A^'>"
+							+"<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 _type='A^'>\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 _type='A^'>\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 _type='A^'>\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 _type='A^'>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</ia1>"
+						+"<ia2>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</ia2>"
+					+"</ia>"
+					+"<aa>"
+						+"<aa1 _type='A^'>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</aa1>"
+						+"<aa2>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</aa2>"
+					+"</aa>"
+					+"<o>"
+						+"<o1 _type='A^'>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</o1>"
+						+"<o2>"
+							+"<A>"
+								+"<a>foo</a>"
+							+"</A>"
+						+"</o2>"
+					+"</o>"
+				+"</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 = "\n\b\f\t";
+			return this;
+		}
+	}
+
+	@Bean(typeName="$#!")
+	public static class BeanWithSpecialCharacters2 {
+
+		@BeanProperty(name="*()")
+		public String a;
+
+		BeanWithSpecialCharacters2 init() {
+			a = "\n\b\f\t";
+			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;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java b/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
new file mode 100755
index 0000000..481cfb7
--- /dev/null
+++ b/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonParserTest.java
@@ -0,0 +1,179 @@
+// ***************************************************************************************************************************
+// * 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.BeanContext.*;
+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 XmlParser().setProperty(BEAN_ignoreUnknownBeanProperties, true);
+		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 = new XmlParser();
+			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 {
+		final List<String> events = new LinkedList<String>();
+		XmlParser p = new XmlParser().setProperty(BEAN_ignoreUnknownBeanProperties, true);
+		p.addListener(
+			new ParserListener() {
+				@Override /* ParserListener */
+				public <T> void onUnknownProperty(String propertyName, Class<T> beanClass, T bean, int line, int col) {
+					events.add(propertyName + "," + line + "," + col);
+				}
+			}
+		);
+
+		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, events.size());
+		// XML parser may or may not support line numbers.
+		assertTrue(events.get(0).startsWith("unknownProperty,"));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java b/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
new file mode 100755
index 0000000..7ef01fd
--- /dev/null
+++ b/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonTest.java
@@ -0,0 +1,463 @@
+// ***************************************************************************************************************************
+// * 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.serializer.SerializerContext.*;
+import static org.apache.juneau.xml.XmlSerializerContext.*;
+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.serializer.*;
+import org.apache.juneau.testbeans.*;
+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 {
+		XmlSerializer s = new XmlSerializer.Sq();
+		XmlParser p = new XmlParser();
+		A t1 = A.create(), t2;
+
+		s.setProperty(SERIALIZER_trimNullProperties, false);
+		String r = s.serialize(t1);
+		assertEquals("<object><s1 _type='null'/><s2>s2</s2></object>", r);
+		t2 = p.parse(r, A.class);
+		assertEqualObjects(t1, t2);
+
+		s.setProperty(SERIALIZER_trimNullProperties, true);
+		r = s.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 {
+		XmlSerializer s = new XmlSerializer.Sq();
+		XmlParser p = XmlParser.DEFAULT;
+		B t1 = B.create(), t2;
+		String r;
+
+		s.setProperty(SERIALIZER_trimEmptyMaps, false);
+		r = s.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.setProperty(SERIALIZER_trimEmptyMaps, true);
+		r = s.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 {
+		XmlSerializer s = new XmlSerializer.Sq();
+		XmlParser p = XmlParser.DEFAULT;
+		C t1 = C.create(), t2;
+		String r;
+
+		s.setProperty(SERIALIZER_trimEmptyCollections, false);
+		r = s.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.setProperty(SERIALIZER_trimEmptyCollections, true);
+		r = s.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 LinkedList<A>();
+			t.f2 = new LinkedList<A>(){{add(null);add(A.create());}};
+			return t;
+		}
+	}
+
+	//====================================================================================================
+	// Trim empty arrays
+	//====================================================================================================
+	@Test
+	public void testTrimEmptyArrays() throws Exception {
+		XmlSerializer s = new XmlSerializer.Sq();
+		XmlParser p = XmlParser.DEFAULT;
+		D t1 = D.create(), t2;
+		String r;
+
+		s.setProperty(SERIALIZER_trimEmptyCollections, false);
+		r = s.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.setProperty(SERIALIZER_trimEmptyCollections, true);
+		r = s.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 LinkedHashMap<String,Integer>() {{
+			put("f1",1); put("f3",3);
+		}};
+		@BeanProperty(properties="f1,f2") public E2[] x3 = {new E2()};
+		@BeanProperty(properties="f1,f2") public List<E2> x4 = new LinkedList<E2>() {{
+			add(new E2());
+		}};
+		@BeanProperty(properties="f1") public ObjectMap[] x5 = {new ObjectMap().append("f1",1).append("f3",3)};
+		@BeanProperty(properties="f1") public List<ObjectMap> x6 = new LinkedList<ObjectMap>() {{
+			add(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;
+	}
+
+	//====================================================================================================
+	// Test URIs with URI_CONTEXT and URI_AUTHORITY
+	//====================================================================================================
+	@Test
+	public void testUris() throws Exception {
+		WriterSerializer s = new XmlSerializer.Sq();
+		TestURI t = new TestURI();
+		String r;
+		String expected;
+
+		s.setProperty(SERIALIZER_relativeUriBase, null);
+		r = s.serialize(t);
+		expected = ""
+			+"<object f0='f0/x0'>"
+			+"<f1>f1/x1</f1>"
+			+"<f2>/f2/x2</f2>"
+			+"<f3>http://www.apache.org/f3/x3</f3>"
+			+"<f4>f4/x4</f4>"
+			+"<f5>/f5/x5</f5>"
+			+"<f6>http://www.apache.org/f6/x6</f6>"
+			+"<f7>http://www.apache.org/f7/x7</f7>"
+			+"<f8>f8/x8</f8>"
+			+"<f9>f9/x9</f9>"
+			+"<fa>http://www.apache.org/fa/xa#MY_LABEL</fa>"
+			+"<fb>http://www.apache.org/fb/xb?label=MY_LABEL&amp;foo=bar</fb>"
+			+"<fc>http://www.apache.org/fc/xc?foo=bar&amp;label=MY_LABEL</fc>"
+			+"<fd>http://www.apache.org/fd/xd?label2=MY_LABEL&amp;foo=bar</fd>"
+			+"<fe>http://www.apache.org/fe/xe?foo=bar&amp;label2=MY_LABEL</fe>"
+			+"</object>";
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_relativeUriBase, "");  // Same as null.
+		r = s.serialize(t);
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_relativeUriBase, "/cr");
+		r = s.serialize(t);
+		expected = ""
+			+"<object f0='/cr/f0/x0'>"
+			+"<f1>/cr/f1/x1</f1>"
+			+"<f2>/f2/x2</f2>"
+			+"<f3>http://www.apache.org/f3/x3</f3>"
+			+"<f4>/cr/f4/x4</f4>"
+			+"<f5>/f5/x5</f5>"
+			+"<f6>http://www.apache.org/f6/x6</f6>"
+			+"<f7>http://www.apache.org/f7/x7</f7>"
+			+"<f8>/cr/f8/x8</f8>"
+			+"<f9>/cr/f9/x9</f9>"
+			+"<fa>http://www.apache.org/fa/xa#MY_LABEL</fa>"
+			+"<fb>http://www.apache.org/fb/xb?label=MY_LABEL&amp;foo=bar</fb>"
+			+"<fc>http://www.apache.org/fc/xc?foo=bar&amp;label=MY_LABEL</fc>"
+			+"<fd>http://www.apache.org/fd/xd?label2=MY_LABEL&amp;foo=bar</fd>"
+			+"<fe>http://www.apache.org/fe/xe?foo=bar&amp;label2=MY_LABEL</fe>"
+			+"</object>";
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_relativeUriBase, "/cr/");  // Same as above
+		r = s.serialize(t);
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_relativeUriBase, "/");
+		r = s.serialize(t);
+		expected = ""
+			+"<object f0='/f0/x0'>"
+			+"<f1>/f1/x1</f1>"
+			+"<f2>/f2/x2</f2>"
+			+"<f3>http://www.apache.org/f3/x3</f3>"
+			+"<f4>/f4/x4</f4>"
+			+"<f5>/f5/x5</f5>"
+			+"<f6>http://www.apache.org/f6/x6</f6>"
+			+"<f7>http://www.apache.org/f7/x7</f7>"
+			+"<f8>/f8/x8</f8>"
+			+"<f9>/f9/x9</f9>"
+			+"<fa>http://www.apache.org/fa/xa#MY_LABEL</fa>"
+			+"<fb>http://www.apache.org/fb/xb?label=MY_LABEL&amp;foo=bar</fb>"
+			+"<fc>http://www.apache.org/fc/xc?foo=bar&amp;label=MY_LABEL</fc>"
+			+"<fd>http://www.apache.org/fd/xd?label2=MY_LABEL&amp;foo=bar</fd>"
+			+"<fe>http://www.apache.org/fe/xe?foo=bar&amp;label2=MY_LABEL</fe>"
+			+"</object>";
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_relativeUriBase, null);
+
+		s.setProperty(SERIALIZER_absolutePathUriBase, "http://foo");
+		r = s.serialize(t);
+		expected = ""
+			+"<object f0='f0/x0'>"
+			+"<f1>f1/x1</f1>"
+			+"<f2>http://foo/f2/x2</f2>"
+			+"<f3>http://www.apache.org/f3/x3</f3>"
+			+"<f4>f4/x4</f4>"
+			+"<f5>http://foo/f5/x5</f5>"
+			+"<f6>http://www.apache.org/f6/x6</f6>"
+			+"<f7>http://www.apache.org/f7/x7</f7>"
+			+"<f8>f8/x8</f8>"
+			+"<f9>f9/x9</f9>"
+			+"<fa>http://www.apache.org/fa/xa#MY_LABEL</fa>"
+			+"<fb>http://www.apache.org/fb/xb?label=MY_LABEL&amp;foo=bar</fb>"
+			+"<fc>http://www.apache.org/fc/xc?foo=bar&amp;label=MY_LABEL</fc>"
+			+"<fd>http://www.apache.org/fd/xd?label2=MY_LABEL&amp;foo=bar</fd>"
+			+"<fe>http://www.apache.org/fe/xe?foo=bar&amp;label2=MY_LABEL</fe>"
+			+"</object>";
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_absolutePathUriBase, "http://foo/");
+		r = s.serialize(t);
+		assertEquals(expected, r);
+
+		s.setProperty(SERIALIZER_absolutePathUriBase, "");  // Same as null.
+		r = s.serialize(t);
+		expected = ""
+			+"<object f0='f0/x0'>"
+			+"<f1>f1/x1</f1>"
+			+"<f2>/f2/x2</f2>"
+			+"<f3>http://www.apache.org/f3/x3</f3>"
+			+"<f4>f4/x4</f4>"
+			+"<f5>/f5/x5</f5>"
+			+"<f6>http://www.apache.org/f6/x6</f6>"
+			+"<f7>http://www.apache.org/f7/x7</f7>"
+			+"<f8>f8/x8</f8>"
+			+"<f9>f9/x9</f9>"
+			+"<fa>http://www.apache.org/fa/xa#MY_LABEL</fa>"
+			+"<fb>http://www.apache.org/fb/xb?label=MY_LABEL&amp;foo=bar</fb>"
+			+"<fc>http://www.apache.org/fc/xc?foo=bar&amp;label=MY_LABEL</fc>"
+			+"<fd>http://www.apache.org/fd/xd?label2=MY_LABEL&amp;foo=bar</fd>"
+			+"<fe>http://www.apache.org/fe/xe?foo=bar&amp;label2=MY_LABEL</fe>"
+			+"</object>";
+		assertEquals(expected, r);
+	}
+
+	//====================================================================================================
+	// Validate that you cannot update properties on locked serializer.
+	//====================================================================================================
+	@Test
+	public void testLockedSerializer() throws Exception {
+		XmlSerializer s = new XmlSerializer().lock();
+		try {
+			s.setProperty(XmlSerializerContext.XML_enableNamespaces, true);
+			fail("Locked exception not thrown");
+		} catch (LockedException e) {}
+		try {
+			s.setProperty(SerializerContext.SERIALIZER_addBeanTypeProperties, true);
+			fail("Locked exception not thrown");
+		} catch (LockedException e) {}
+		try {
+			s.setProperty(BeanContext.BEAN_beanMapPutReturnsOldValue, true);
+			fail("Locked exception not thrown");
+		} catch (LockedException e) {}
+	}
+
+	//====================================================================================================
+	// Recursion
+	//====================================================================================================
+	@Test
+	public void testRecursion() throws Exception {
+		XmlSerializer s = new XmlSerializer().setProperty(XML_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.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.setProperty(SERIALIZER_detectRecursions, true);
+		try {
+			s.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.setProperty(SERIALIZER_ignoreRecursions, true);
+		assertEquals("<object><name>foo</name><r2><name>bar</name><r3><name>baz</name></r3></r2></object>", s.serialize(r1));
+
+		// Make sure this doesn't blow up.
+		s.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/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java b/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
new file mode 100755
index 0000000..e2fd383
--- /dev/null
+++ b/juneau-core-test/src/test/java/org/apache/juneau/xml/CommonXmlTest.java
@@ -0,0 +1,81 @@
+// ***************************************************************************************************************************
+// * 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.XmlSerializerContext.*;
+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 XmlSerializer.Sq().setProperty(XML_addNamespaceUrisToRoot, false);
+
+		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/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java b/juneau-core-test/src/test/java/org/apache/juneau/xml/InvalidXmlBeansTest.java
new file mode 100644
index 0000000..1bfec26
--- /dev/null
+++ b/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",
+			},
+			{
+				"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",
+			},
+			{
+				"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",
+			},
+			{
+				"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",
+			},
+			{
+				"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;
+	}
+}


Mime
View raw message