Thread: [Practicalxml-commits] SF.net SVN: practicalxml:[97] branches/dev-1.1/src/main/java/net/sf/ practic
Brought to you by:
kdgregory
From: Auto-Generated S. C. M. <pra...@li...> - 2009-08-10 22:31:11
|
Revision: 97 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=97&view=rev Author: kdgregory Date: 2009-08-10 22:30:50 +0000 (Mon, 10 Aug 2009) Log Message: ----------- introduce ConversionException Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/Bean2XmlDriver.java Added Paths: ----------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/ConversionException.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/Bean2XmlDriver.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/Bean2XmlDriver.java 2009-07-23 23:28:30 UTC (rev 96) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/Bean2XmlDriver.java 2009-08-10 22:30:50 UTC (rev 97) @@ -179,7 +179,7 @@ } catch (IntrospectionException ee) { - throw new RuntimeException("introspection failure", ee); + throw new ConversionException("introspection failure", ee); } } @@ -198,7 +198,7 @@ } catch (Exception ee) { - throw new RuntimeException("unable to retrieve bean value", ee); + throw new ConversionException("unable to retrieve bean value", ee); } dispatch(propDesc.getName(), value, handler); Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/ConversionException.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/ConversionException.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/ConversionException.java 2009-08-10 22:30:50 UTC (rev 97) @@ -0,0 +1,36 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed 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 net.sf.practicalxml.converter; + + +/** + * A runtime exception thrown for any conversion error. Will always have a + * message, and typically contains a wrapped exception. + */ +public class ConversionException +extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public ConversionException(String message, Throwable cause) + { + super(message, cause); + } + + public ConversionException(String message) + { + super(message); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-08-17 20:24:31
|
Revision: 111 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=111&view=rev Author: kdgregory Date: 2009-08-17 20:24:04 +0000 (Mon, 17 Aug 2009) Log Message: ----------- update comments Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/package.html 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 17:26:40 UTC (rev 110) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/BeanConverter.java 2009-08-17 20:24:04 UTC (rev 111) @@ -15,60 +15,162 @@ package net.sf.practicalxml.converter; import org.w3c.dom.Document; +import org.w3c.dom.Element; import net.sf.practicalxml.converter.bean.Bean2XmlDriver; import net.sf.practicalxml.converter.bean.Bean2XmlOptions; /** - * Converts Java objects (not just beans) to and from an XML representation. - * This was originally developed to support RESTful web services, without the - * class-generation hassle of JAXB. + * Converts Java objects (not just beans) to or from an XML representation. + * Originally developed to support simple web services, without the overhead + * (schema definitions and/or annotations) required by JAXB. * <p> - * The XML generated/consumed by this class obeys the following rules, with - * options controlled by {@link Bean2XmlOptions}: - * <ul> - * <li> All elements inherit their parent's namespace and namespace prefix. - * <li> Elements of sets are output using the element name "data". - * <li> Elements of lists and arrays are output using the element name "data", - * with an attribute "index" that contains the numeric index. - * <li> Elements of maps are by default output using the name "data", with an - * attribute "name" containing the actual map key. The output option - * <code>INTROSPECT_MAPS</code> will change this behavior, but will throw - * if the map keys are not valid XML element names. - * <li> Values are output using <code>toString()</code>, except as overridden - * by options. - * <li> Null values do not generate output, unless the <code>XSI_NIL</code> - * option is in effect. - * </ul> + * 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. + * <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 + * represent the elements/properties of the object. Nodes representing complex + * objects have child elements, those representing simple (primitive) objects + * have a single text child. Objects are processed recursively, and cycles are + * <em>not</em> detected (although this may change). + * <p> + * A namespace and qualified name may be provided to {@link #convertToXml}, + * and all elements will inherit the namespace and prefix. Namespaces are + * ignored on input; all property matches uses the element's local name. + * <p> + * Each element may have an <code>xsi:type</code> attribute (where <code>xsi + * </code> references to the XML Schema instance namespace). This attribute + * is optional for both output and input; if used for output, it is merely + * informational, but for input will be examined to validate that the XML is + * appropriate for the desired object type. For primitive types, wrappers, + * and strings, it takes the form "<code>xsd:TYPE</code>", where <code>TYPE + * </code> is one of the simple types defined by XML schema. For other Java + * types, it takes the form "<code>java:TYPE</code>", where <code>TYPE</code> + * is the fully qualified Java classname. + * <p> + * On input, the desired type is specified by the caller or by introspection + * (except in the case of collection elements; see below). The <code>xsi:type + * </code> value, if any, is ignored except for validation. + * <p> + * Additional conversion rules are as follows: + * + * <table border="1"> + * <tr><th>Java Object Type + * <th>{@link #convertToXml} + * <th>{@link #convertToJava} + * <tr><td>Primitives, Wrapper objects, and String + * <td> + * <td> + * <tr><td>Arrays + * <td>Elements of the array are written in sequence to the DOM, using the + * element name "<code>data</code>". Elements are given an attribute + * named "<code>index</code>", which contains the element's position + * within the array. + * <td>Elements of the array are processed in sequence, ignoring both + * element name and "index" attribute. + * <tr><td>Lists and Sets + * <td>The collection is iterated, and elements are written in sequence to + * the DOM, using the element name "<code>data</code>". Elements are + * given an attribute named "<code>index</code>", which contains the + * element's position within the iteration (meaningful only for lists). + * <td>Elements of the are processed in sequence, ignoring both element + * name and "index" attribute. + * <p> + * If an <code>xsi:type</code> attribute is present, it will be used + * to drive conversion of the element. Otherwise, the element will be + * converted as a <code>String</code> (which will fail for complex + * types, because string conversion assumes a single text node). + * <p> + * Where the caller specifies an interface as the conversion class, the + * converter will choose an appropriate implementation class: + * <ul> + * <li> <code>ArrayList</code> for <code>List</code> or <code>Collection</code> + * <li> <code>TreeSet</code> for <code>SortedSet</code> + * <li> <code>HashSet</code> for <code>Set</code> + * </ul> + * <tr><td>Maps + * <td>The collection is iterated, and elements are written in sequence to + * the DOM. Depending on the output options, either the entry key will + * be used as the element name, or the name will be "<code>data</code>" + * and the key stored in an attribute named "<code>key</code>". The + * former option is only permitted if all keys in the map are valid + * XML element names; otherwise the converter will throw. + * <td>Elements are processed in sequence. The converter first looks for + * a "<code>key</code>" attribute, and will use it as the entry key + * if found. Otherwise, it will use the element name. If your maps + * are being reduced to a single entry, look for a missing attribute. + * <p> + * If an <code>xsi:type</code> attribute is present, it will be used + * to drive conversion of the element. Otherwise, the element will be + * converted as a <code>String</code> (which will fail for complex + * types, because string conversion assumes a single text node). + * <p> + * Where the caller specifies an interface as the conversion class, + * the converter will choose an appropriate implementation class: + * <code>TreeMap</code> for <code>SortedMap</code>, and <code>HashMap + * </code> for <code>Map</code>. + * <tr><td>Bean-structured Objects + * <td>The object is introspected, and properties are written in the order + * provided by the <code>Introspector</code>. + * <td>The bean class must provide a no-argument constructor (otherwise it + * doesn't follow the bean spec, and we can't use it). + * <p> + * The converter relies on <code>java.beans.Introspector</code> to find + * property setter methods for an object. If the object provides + * multiple methods for the property, the converter will use whichever + * one the introspector provides. + * <p> + * Elements are processed in order, and the element's localname is used + * to find the associated object property. If the XML does not contain + * an element corresponding to a bean property, that property is left + * with its default value (ie, we don't try to find an element based + * on property name). + * <p> + * If the XML contains an element that does not correspond to any bean + * property, the converter will either throw or ignore the element, + * depending on options settings. + * <tr><td>Other Objects + * <td>not supported + * <td>not supported + * </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. */ public class BeanConverter { /** * Creates a new DOM document from the passed bean, in which all elements * are members of the specified namespace. - * + * * @param bean The source object. This can be any Java object: * bean, collection, or simple type. * @param nsUri The namespace of the root element. This will be * inherited by all child elements. - * @param rootName The qualified name given to the root element of the + * @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, + public static Document generateXml(Object bean, String nsUri, String rootName, Bean2XmlOptions... options) { Bean2XmlDriver driver = new Bean2XmlDriver(options); return driver.convert(bean, nsUri, rootName).getOwnerDocument(); } - - + + /** * Creates a new DOM document from the passed bean, without namespace. - * + * * @param bean The source object. This can be any Java object: * bean, collection, or simple type. * @param rootName The name given to the root element of the produced @@ -76,7 +178,7 @@ * @param options Options controlling output. . */ - public static Document generateXml(Object bean, String rootName, + public static Document generateXml(Object bean, String rootName, Bean2XmlOptions... options) { Bean2XmlDriver driver = new Bean2XmlDriver(options); Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java 2009-08-17 17:26:40 UTC (rev 110) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java 2009-08-17 20:24:04 UTC (rev 111) @@ -48,31 +48,6 @@ * Driver class for converting an XML DOM into a Java bean. Normal usage is * to create a single instance of this class with desired options, then use * it for multiple conversions. This class is thread-safe. - * <p> - * This class assumes that the source XML will be in the form produced by - * {@link Bean2XmlDriver}: each element either contains child elements, or - * a text node containing the element's value. However, conversion is - * driven by the parameters passed to {@link #convert}, not by the content - * of the XML document; this can lead to some unexpected behavior: - * <ul> - * <li> Bean classes are introspected, and recursively processed base on - * the property descriptors. If the bean has multiple setter methods - * for a property, the method selected is arbitrarily chosen by the - * JavaBeans introspector. You can pass an option that looks for a - * setters using <code>String</code>, but this is not recommended - * from a performance perspective. - * <li> JDK collection types do not carry type information, so the only - * way to properly convert them is using an <code>xsi:type</code> - * attribute on the child elements. If this attribute is missing - * or cannot be interpreted, the element will be processed as if - * it is a <code>String</code>. - * <li> The converter will to pick an appropriate implementation class - * if given one of the JDK collections interfaces: <code> - * ArrayList</code> for <code>List</code> or <code>Collection</code>, - * <code>TreeSet</code> for <code>SortedSet</code>, <code>HashSet</code> - * for any other <code>Set</code>, and likewise <code>TreeMap</code> and - * <code>HashMap</code> for <code>SortedMap</code> and <code>Map</code>. - * </ul> */ public class Xml2BeanDriver { Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/package.html =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/package.html 2009-08-17 17:26:40 UTC (rev 110) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/package.html 2009-08-17 20:24:04 UTC (rev 111) @@ -1,6 +1,15 @@ <html> <body> This package contains classes to convert between XML and a variety of - other formats. + other formats. Each conversion has a top-level convenience class in + this package, which handles common conversion scenarios and provides + overall documentation on the conversion. Sub-packages contain the + actual conversion classes; you may need to use those classes directly + for "unusual" conversions. + <p> + Any problems during conversion (in either direction) are reported via + {@link ConversionException}, which is a runtime exception and will + wrap any actual exception. If appropriate, this exception will also + contain the XPath to the node failing conversion. </body> </html> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Auto-Generated S. C. M. <pra...@li...> - 2009-08-18 19:50:47
|
Revision: 118 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=118&view=rev Author: kdgregory Date: 2009-08-18 19:50:39 +0000 (Tue, 18 Aug 2009) Log Message: ----------- refactoring Modified Paths: -------------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java Added Paths: ----------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/internal/DomUtilToo.java Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-08-18 19:16:50 UTC (rev 117) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlAppenders.java 2009-08-18 19:50:39 UTC (rev 118) @@ -15,13 +15,11 @@ package net.sf.practicalxml.converter.bean; import java.util.EnumSet; - -import javax.xml.XMLConstants; - import org.w3c.dom.Element; import net.sf.practicalxml.DomUtil; import net.sf.practicalxml.converter.ConversionException; +import net.sf.practicalxml.converter.internal.DomUtilToo; /** @@ -95,7 +93,7 @@ protected void setType(Element elem, String type) { if (isOptionSet(Bean2XmlOptions.ADD_XSI_TYPE)) - elem.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type", type); + DomUtilToo.setXsiType(elem, type); } protected void setValue(Element elem, String value) @@ -103,7 +101,7 @@ if (value != null) DomUtil.setText(elem, value); else if (isOptionSet(Bean2XmlOptions.XSI_NIL)) - elem.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil", "true"); + DomUtilToo.setXsiNil(elem, true); } } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java 2009-08-18 19:16:50 UTC (rev 117) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Bean2XmlDriver.java 2009-08-18 19:50:39 UTC (rev 118) @@ -24,13 +24,12 @@ import java.util.EnumSet; import java.util.Map; -import javax.xml.XMLConstants; - import org.w3c.dom.Element; import net.sf.practicalxml.DomUtil; import net.sf.practicalxml.converter.ConversionException; import net.sf.practicalxml.converter.bean.Bean2XmlAppenders.*; +import net.sf.practicalxml.converter.internal.DomUtilToo; import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; @@ -145,7 +144,7 @@ if (_options.contains(Bean2XmlOptions.XSI_NIL) && !_options.contains(Bean2XmlOptions.ADD_XSI_TYPE)) { - root.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil", "false"); + DomUtilToo.setXsiNil(root, false); } } Modified: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java 2009-08-18 19:16:50 UTC (rev 117) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/bean/Xml2BeanDriver.java 2009-08-18 19:50:39 UTC (rev 118) @@ -33,10 +33,9 @@ import java.util.TreeMap; import java.util.TreeSet; -import javax.xml.XMLConstants; - import net.sf.practicalxml.DomUtil; import net.sf.practicalxml.converter.ConversionException; +import net.sf.practicalxml.converter.internal.DomUtilToo; import net.sf.practicalxml.converter.internal.PrimitiveConversionHelper; import net.sf.practicalxml.internal.StringUtils; @@ -121,9 +120,8 @@ if (_options.contains(Xml2BeanOptions.REQUIRE_XSI_NIL)) { - String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil"); - if (!attr.equals("true")) - throw new ConversionException("missing xsi:nil", elem); + if (!DomUtilToo.getXsiNil(elem)) + throw new ConversionException("missing/false xsi:nil", elem); } return true; @@ -235,19 +233,6 @@ /** - * Returns the <code>xsi:type</code> attribute value, <code>null</code> if - * it's not set. - */ - private String getXsiType(Element elem) - { - String xsiType = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type"); - return StringUtils.isEmpty(xsiType) - ? null - : xsiType; - } - - - /** * Examines an element's <code>xsi:type</code> attribute, if any, and * returns the Java class corresponding to it. Used when converting * collection types, which don't have type information that can be @@ -255,7 +240,7 @@ */ private Class<?> getClassFromXsiType(Element elem) { - String xsiType = getXsiType(elem); + String xsiType = DomUtilToo.getXsiType(elem); if (xsiType == null) return null; @@ -281,8 +266,8 @@ if (!_options.contains(Xml2BeanOptions.REQUIRE_XSI_TYPE)) return; - String xsiType = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type"); - if (StringUtils.isEmpty(xsiType)) + String xsiType = DomUtilToo.getXsiType(elem); + if (xsiType == null) throw new ConversionException("missing xsi:type", elem); if (xsiType.equals(_helper.getXsdType(klass))) Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/internal/DomUtilToo.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/internal/DomUtilToo.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/internal/DomUtilToo.java 2009-08-18 19:50:39 UTC (rev 118) @@ -0,0 +1,79 @@ +// Copyright 2008-2009 severally by the contributors +// +// Licensed 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 net.sf.practicalxml.converter.internal; + +import javax.xml.XMLConstants; + +import org.w3c.dom.Element; + +import net.sf.practicalxml.internal.StringUtils; + + +/** + * Contains static utility methods and constants used by the conversion routines. + * These are way too specific to go into the top-level <code>DomUtil</code>, and + * are not generally useful to anyone who isn't writing a converter. But if you + * are writing a converter, you'll probably use them a lot ... + * <p> + * Note: where methods in this class reference a namespaced element or attribute + * (eg, <code>xsi:type</code>), they do not use a prefix unless explicitly noted. + * This prevents the possibility of collisions, where the same prefix is used + * elsewhere in the DOM for elements not managed by the converter. A serializer + * will pick an appropriate prefix for output. + */ +public class DomUtilToo +{ + /** + * Sets the <code>xsi:type</code> attribute to the passed value. + */ + public static void setXsiType(Element elem, String xsiType) + { + elem.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type", xsiType); + } + + + /** + * Returns the value of the <code>xsi:type</code> attribute on the passed + * element, <code>null</code> if the attribute is not set. + */ + public static String getXsiType(Element elem) + { + String xsiType = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type"); + return StringUtils.isEmpty(xsiType) + ? null + : xsiType; + } + + + /** + * Sets the <code>xsi:nil</code> attribute to the passed value. + */ + public static void setXsiNil(Element elem, boolean isNil) + { + String value = isNil ? "true" : "false"; + elem.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil", value); + } + + + /** + * Returns the value of the <code>xsi:nil</code> attribute on the passed + * element, <code>false</code> if the attribute is not set. + */ + public static boolean getXsiNil(Element elem) + { + String attr = elem.getAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil"); + return attr.equals("true"); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |