[Practicalxml-commits] SF.net SVN: practicalxml:[112] branches/dev-1.1/src
Brought to you by:
kdgregory
From: Auto-Generated S. C. M. <pra...@li...> - 2009-08-18 17:41:55
|
Revision: 112 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=112&view=rev Author: kdgregory Date: 2009-08-18 17:41:38 +0000 (Tue, 18 Aug 2009) Log Message: ----------- change BeanConverter API, write tests for it Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractBeanConverterTestCase.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/TestBeanConverter.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java 2009-08-17 20:24:04 UTC (rev 111) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java 2009-08-18 17:41:38 UTC (rev 112) @@ -19,6 +19,8 @@ import net.sf.practicalxml.converter.bean.Bean2XmlDriver; import net.sf.practicalxml.converter.bean.Bean2XmlOptions; +import net.sf.practicalxml.converter.bean.Xml2BeanDriver; +import net.sf.practicalxml.converter.bean.Xml2BeanOptions; /** @@ -26,11 +28,13 @@ * Originally developed to support simple web services, without the overhead * (schema definitions and/or annotations) required by JAXB. * <p> - * A single instance handles conversions in one direction only. This is a - * consequence of specifying options as varargs, but fits well with "normal" - * application design, in which input and output are distinct operations. - * Note that, depending on options settings, output generated by one converter - * may not be valid input for another. + * A single instance is intended for conversions in one direction only. This + * is a consequence of specifying options as varargs, but fits well with + * "normal" application design, in which input and output are handled by + * different parts of the code. You won't get an error if you try to convert + * the "wrong" way, you'll simply get default behavior. Note that, depending + * on options settings, output generated by one converter may not be valid + * input for another. * <p> * The basic structure of XML produced/consumed by this class is that the * root element represents the object being converted, and its child nodes @@ -140,15 +144,50 @@ * </table> * * <strong>Warning</strong>: - * this class makes use of <code>java.beans.Introspector</code>, which holds - * a cache of introspected objects. If you use this converter in an app-server - * you should call <code>Introspector.flushCaches()</code> during deploy. + * <code>java.beans.Introspector</code> holds a cache of introspected objects. + * If you use this converter in an app-server you should call + * <code>Introspector.flushCaches()</code> during deploy. */ public class BeanConverter { + private Bean2XmlDriver _outputDriver; + private Xml2BeanDriver _inputDriver; + + /** + * Creates an instance with all options disabled. This can be used for + * conversions in either direction, and is meant primarily for testing. + */ + public BeanConverter() + { + _outputDriver = new Bean2XmlDriver(); + _inputDriver = new Xml2BeanDriver(); + } + + + /** + * Creates an instance to be used for Bean -> XML conversion, + */ + public BeanConverter(Bean2XmlOptions... options) + { + _outputDriver = new Bean2XmlDriver(options); + _inputDriver = new Xml2BeanDriver(); + } + + /** + * Creates an instance to be used for XML -> Bean conversion. + */ + public BeanConverter(Xml2BeanOptions options) + { + _outputDriver = new Bean2XmlDriver(); + _inputDriver = new Xml2BeanDriver(options); + } + + + /** * Creates a new DOM document from the passed bean, in which all elements - * are members of the specified namespace. + * are members of the specified namespace and will inherit the root's + * prefix (if any). * * @param bean The source object. This can be any Java object: * bean, collection, or simple type. @@ -157,14 +196,10 @@ * @param rootName The qualified name given to the root element of the * generated document. If a qualified name, all child * elements will inherit its prefix. - * @param options Options controlling output. -. */ - public static Document generateXml(Object bean, String nsUri, String rootName, - Bean2XmlOptions... options) + public Element convertToXml(Object bean, String nsUri, String rootName) { - Bean2XmlDriver driver = new Bean2XmlDriver(options); - return driver.convert(bean, nsUri, rootName).getOwnerDocument(); + return _outputDriver.convert(bean, nsUri, rootName); } @@ -175,13 +210,37 @@ * bean, collection, or simple type. * @param rootName The name given to the root element of the produced * document. - * @param options Options controlling output. -. */ - public static Document generateXml(Object bean, String rootName, - Bean2XmlOptions... options) + public Element convertToXml(Object bean, String rootName) { - Bean2XmlDriver driver = new Bean2XmlDriver(options); - return driver.convert(bean, rootName).getOwnerDocument(); + return _outputDriver.convert(bean, rootName); } + + + /** + * Creates a new Java object from the root of the passed <code>Document + * </code>. + * + * @param dom The source document. + * @param klass The desired class to instantiate and fill from this + * document. + */ + public <T> T convertToJava(Document dom, Class<T> klass) + { + return convertToJava(dom.getDocumentElement(), klass); + } + + + /** + * Creates a new Java object from the the passed DOM <code>Element</code>. + * + * @param dom The source element -- this may or may not be the + * root element of its document. + * @param klass The desired class to instantiate and fill from this + * document. + */ + public <T> T convertToJava(Element root, Class<T> klass) + { + return _inputDriver.convert(root, klass); + } } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractBeanConverterTestCase.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractBeanConverterTestCase.java 2009-08-17 20:24:04 UTC (rev 111) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/AbstractBeanConverterTestCase.java 2009-08-18 17:41:38 UTC (rev 112) @@ -16,6 +16,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -23,6 +24,8 @@ import org.w3c.dom.Element; +import junit.framework.Assert; + import net.sf.practicalxml.AbstractTestCase; import net.sf.practicalxml.DomUtil; @@ -120,6 +123,15 @@ public boolean isBval() { return _bval; } public void setBval(boolean bval) { _bval = bval; } + + public void assertEquals(SimpleBean that) + { + assertNotNull(that); + Assert.assertEquals("sval", _sval, that._sval); + Assert.assertEquals("ival", _ival, that._ival); + Assert.assertEquals("dval", _dval, that._dval); + Assert.assertEquals("bval", _bval, that._bval); + } } @@ -150,6 +162,13 @@ public List<String> getStringList() { return _stringList; } public void setStringList(List<String> list) { _stringList = list; } + + public void assertEquals(CompoundBean that) + { + _simple.assertEquals(that._simple); + Assert.assertTrue("primArray", Arrays.equals(_primArray, that._primArray)); + Assert.assertEquals("stringlist", _stringList, that._stringList); + } } Modified: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/TestBeanConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/TestBeanConverter.java 2009-08-17 20:24:04 UTC (rev 111) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/TestBeanConverter.java 2009-08-18 17:41:38 UTC (rev 112) @@ -14,19 +14,34 @@ package net.sf.practicalxml.converter; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import net.sf.practicalxml.DomUtil; import net.sf.practicalxml.OutputUtil; import net.sf.practicalxml.converter.bean.Bean2XmlOptions; +import net.sf.practicalxml.converter.bean.Xml2BeanOptions; +import net.sf.practicalxml.junit.DomAsserts; -import javax.xml.XMLConstants; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** - * Tests for the top-level <code>BeanConverter</code> methods. These are - * minimal; the detailed testing happens in {@link TestBean2XmlDriver} - * and {@link TestXml2BeanDriver}. + * Tests for the top-level <code>BeanConverter</code> methods. These are all + * "out and back" tests to verify that we can read the XML that we produce + * (and to show cases where we can't). Detailed tests (verifying specific + * output) are in {@link TestBean2XmlDriver} and {@link TestXml2BeanDriver}. + * <p> + * Note that each conversion has a commented-out line that will print the + * generated XML. Uncommenting these lines may help you understand how + * conversion works in particular cases. */ public class TestBeanConverter extends AbstractBeanConverterTestCase @@ -41,41 +56,368 @@ // Support Code //---------------------------------------------------------------------------- + private static void assertConversionError( + String message, BeanConverter converter, Element elem, Class<?> klass) + { + try + { + converter.convertToJava(elem, klass); + fail(message); + } + catch (ConversionException ee) + { /* success */ } + } //---------------------------------------------------------------------------- // Test Cases //---------------------------------------------------------------------------- - public void testGenerateSimpleContentSansNamespace() throws Exception + // an initial test to verify everything works + public void testConvertStringDefault() throws Exception { - String rootName = "argle"; - String value = "foo"; + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); - Document dom = BeanConverter.generateXml(value, rootName, Bean2XmlOptions.XSI_TYPE); -// System.out.println(OutputUtil.compactString(dom)); + String obj = "this is a test"; + Element root = outConverter.convertToXml(obj, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + assertEquals("test", DomUtil.getLocalName(root)); - Element root = dom.getDocumentElement(); - assertEquals(rootName, root.getNodeName()); - assertEquals(value, root.getTextContent()); - assertEquals("xsd:string", root.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type")); - assertEquals(0, DomUtil.getChildren(root).size()); + Object result = inConverter.convertToJava(root, String.class); + assertEquals(obj, result); } - public void testGenerateSimpleContentWithNamespace() throws Exception + public void testConvertPrimitiveDefault() throws Exception { - String nsUri = "urn:fibble"; - String rootName = "argle:bargle"; - String value = "foo"; + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); - Document dom = BeanConverter.generateXml(value, nsUri, rootName, Bean2XmlOptions.XSI_TYPE); + for (PrimitiveValue value : PRIMITIVE_VALUES) + { + Object obj = value.getValue(); + Element root = outConverter.convertToXml(obj, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + Object result = inConverter.convertToJava(root, value.getKlass()); + assertEquals(obj, result); + } + } + + + public void testConvertPrimitiveFormatXsd() throws Exception + { + BeanConverter outConverter = new BeanConverter(Bean2XmlOptions.XSD_FORMAT); + BeanConverter inConverter = new BeanConverter(Xml2BeanOptions.EXPECT_XSD_FORMAT); + + for (PrimitiveValue value : PRIMITIVE_VALUES) + { + Object obj = value.getValue(); + Element root = outConverter.convertToXml(obj, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + Object result = inConverter.convertToJava(root, value.getKlass()); + assertEquals(obj, result); + } + } + + + public void testConvertNullDefault() throws Exception + { + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(null, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + Object result = inConverter.convertToJava(root, String.class); + assertNull(result); + } + + + public void testConvertNullUseAndRequireXsiNil() throws Exception + { + BeanConverter outConverter = new BeanConverter(Bean2XmlOptions.XSI_NIL); + BeanConverter inConverter = new BeanConverter(Xml2BeanOptions.REQUIRE_XSI_NIL); + + Element root = outConverter.convertToXml(null, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + Object result = inConverter.convertToJava(root, String.class); + assertNull(result); + } + + + public void testConvertNullFailureRequireXsiNil() throws Exception + { + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(Xml2BeanOptions.REQUIRE_XSI_NIL); + + Element root = outConverter.convertToXml(null, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + assertConversionError("accepted DOM with null entry but no xsi:nil", + inConverter, root, String.class); + } + + + public void testPrimitiveArrayDefault() throws Exception + { + int[] data = new int[] { 1, 2, 4, 5 }; + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + int[] result = inConverter.convertToJava(root, int[].class); + assertTrue(Arrays.equals(data, result)); + } + + + public void testStringListDefault() throws Exception + { + List<String> data = Arrays.asList("foo", "bar", "baz"); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<String> result = inConverter.convertToJava(root, List.class); + assertEquals(data, result); + } + + + // demonstrates that the list will be read as List<String> even though + // it was written as List<Integer> + public void testIntegerListDefault() throws Exception + { + List<Integer> data = Arrays.asList(1, 2, 3); + assert(data.get(0) instanceof Integer); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<?> result = inConverter.convertToJava(root, List.class); + assertTrue(result instanceof List); + assertTrue(result.get(0) instanceof String); + } + + + // demonstrates that you don't need to require xsi:type to use it + public void testIntegerListWithXsiType() throws Exception + { + List<Integer> data = Arrays.asList(1, 2, 3); + assert(data.get(0) instanceof Integer); + + BeanConverter outConverter = new BeanConverter(Bean2XmlOptions.XSI_TYPE); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<?> result = inConverter.convertToJava(root, List.class); + assertEquals(data, result); + } + + + // demonstrates that the caller drives the inbound conversion + public void testConvertListToSortedSet() throws Exception + { + List<String> data = Arrays.asList("foo", "bar", "baz", "bar"); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + Set<?> result = inConverter.convertToJava(root, SortedSet.class); + Iterator<?> itx = result.iterator(); + assertEquals("bar", itx.next()); + assertEquals("baz", itx.next()); + assertEquals("foo", itx.next()); + assertFalse(itx.hasNext()); + } + + + public void testMapDefault() throws Exception + { + Map<String,String> data = new HashMap<String,String>(); + data.put("foo", "argle"); + data.put("bar", "bargle"); + data.put("baz", "bazgle"); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + DomAsserts.assertCount(3, root, "/test/data"); + DomAsserts.assertCount(1, root, "/test/data[@key='foo']"); + DomAsserts.assertEquals("argle", root, "/test/data[@key='foo']"); + + Map<?,?> result = inConverter.convertToJava(root, Map.class); + assertEquals(data, result); + } + + + // demonstrates that the input converter handles either format by default + public void testMapIntrospected() throws Exception + { + Map<String,String> data = new HashMap<String,String>(); + data.put("foo", "argle"); + data.put("bar", "bargle"); + data.put("baz", "bazgle"); + + BeanConverter outConverter = new BeanConverter(Bean2XmlOptions.INTROSPECT_MAPS); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + DomAsserts.assertCount(0, root, "/test/data"); + DomAsserts.assertCount(1, root, "/test/foo"); + DomAsserts.assertEquals("argle", root, "/test/foo"); + + Map<?,?> result = inConverter.convertToJava(root, Map.class); + assertEquals(data, result); + } + + + public void testSimpleBeanDefault() throws Exception + { + SimpleBean data = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + SimpleBean result = inConverter.convertToJava(root, SimpleBean.class); + data.assertEquals(result); + } + + + public void testSimpleBeanRequireXsiType() throws Exception + { + SimpleBean data = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); + + BeanConverter outconverter1 = new BeanConverter(Bean2XmlOptions.XSI_TYPE); + BeanConverter outconverter2 = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(Xml2BeanOptions.REQUIRE_XSI_TYPE); + + Element valid = outconverter1.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(valid.getOwnerDocument())); + + SimpleBean result = inConverter.convertToJava(valid, SimpleBean.class); + data.assertEquals(result); + + Element invalid = outconverter2.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(invalid.getOwnerDocument())); + + assertConversionError("converter requiring xsi:type accepted XML without", + inConverter, invalid, SimpleBean.class); + } + + + public void testListOfSimpleBeanWithXsiTypeAndNulls() throws Exception + { + SimpleBean bean1 = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); + SimpleBean bean2 = new SimpleBean("zyx", 987, null, false); + List<SimpleBean> data = Arrays.asList(bean1, bean2); + + BeanConverter outConverter = new BeanConverter(Bean2XmlOptions.XSI_TYPE); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + List<SimpleBean> result = inConverter.convertToJava(root, List.class); + assertEquals(2, result.size()); + bean1.assertEquals(result.get(0)); + bean2.assertEquals(result.get(1)); + } + + + // another demonstration that caller drives input conversion + // ... and note that we don't care about xsi:type in this case + public void testListOfSimpleBeanToArrayOfSame() throws Exception + { + SimpleBean bean1 = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); + SimpleBean bean2 = new SimpleBean("zyx", 987, null, false); + List<SimpleBean> data = Arrays.asList(bean1, bean2); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + SimpleBean[] result = inConverter.convertToJava(root, SimpleBean[].class); + assertEquals(2, result.length); + bean1.assertEquals(result[0]); + bean2.assertEquals(result[1]); + } + + + public void testCompoundBeanDefault() throws Exception + { + CompoundBean data = new CompoundBean( + new SimpleBean("abc", 123, new BigDecimal("456.789"), true), + new int[] { 1, 5, 7, 9 }, + Arrays.asList("foo", "bar", "baz")); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + CompoundBean result = inConverter.convertToJava(root, CompoundBean.class); + data.assertEquals(result); + } + + + public void testSimpleBeanWithNamespace() throws Exception + { + SimpleBean data = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Element root = outConverter.convertToXml(data, "urn:foo", "bar:test"); +// System.out.println(OutputUtil.compactString(root.getOwnerDocument())); + + Element child = DomUtil.getChild(root, "sval"); + assertEquals("urn:foo", child.getNamespaceURI()); + assertEquals("bar", child.getPrefix()); + + SimpleBean result = inConverter.convertToJava(root, SimpleBean.class); + data.assertEquals(result); + } + + + // this one is here just for coverage + public void testSimpleBeanFromDocument() throws Exception + { + SimpleBean data = new SimpleBean("abc", 123, new BigDecimal("456.789"), true); + + BeanConverter outConverter = new BeanConverter(); + BeanConverter inConverter = new BeanConverter(); + + Document dom = outConverter.convertToXml(data, "test").getOwnerDocument(); // System.out.println(OutputUtil.compactString(dom)); - Element root = dom.getDocumentElement(); - assertEquals(nsUri, root.getNamespaceURI()); - assertEquals(rootName, root.getNodeName()); - assertEquals(value, root.getTextContent()); - assertEquals("xsd:string", root.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type")); - assertEquals(0, DomUtil.getChildren(root).size()); + SimpleBean result = inConverter.convertToJava(dom, SimpleBean.class); + data.assertEquals(result); } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |