All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.run.xml.XmlBean Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

package com.tangosol.run.xml;


import com.tangosol.io.ExternalizableLite;

import com.tangosol.util.ClassHelper;
import com.tangosol.util.SafeHashMap;
import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.Externalizable;
import java.io.IOException;
import java.io.NotActiveException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import java.math.BigDecimal;
import java.math.BigInteger;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;

import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;


/**
* This is a base class for building XmlSerializable value objects.
* 

* The following property types are supported using standard property * adapters: *

*   1)  XmlValue types:
*           TYPE_BOOLEAN  - boolean, java.lang.Boolean
*           TYPE_INT      - byte, char, short, int, java.lang.Byte,
*                           java.lang.Character, java.lang.Short,
*                           java.lang.Integer
*           TYPE_LONG     - long, java.lang.Long
*           TYPE_DOUBLE   - float, double, java.lang.Float, java.lang.Double
*           TYPE_DECIMAL  - java.math.BigDecimal, java.math.BigInteger
*           TYPE_STRING   - java.lang.String
*           TYPE_BINARY   - com.tangosol.util.Binary, byte[]
*           TYPE_DATE     - java.sql.Date
*           TYPE_TIME     - java.sql.Time
*           TYPE_DATETIME - java.sql.Timestamp, java.util.Date
*
*   2)  Objects implementing XmlSerializable (including XmlBean subclasses)
*
*   3)  Objects implementing Serializable
*
*   4)  Collections of any of the above:
*           Java arrays
*           java.util.Collection
*           java.util.Set
*           java.util.List
*           java.util.Map
*           java.util.SortedSet
*           java.util.SortedMap
* 
* * Each XmlBean must have a corresponding XML declaration file that provides * the necessary information to parse XML into the XML bean and to format the * XML bean into XML. The declaration file should be located in the same package * (directory) as the class itself. *

* For example, here is an XmlBean subclass with an int property "Id" and a * String property "Name": *


* public class Person extends XmlBean {
*   public Person(int nId, String sName) {...}
*   public int getId() {...}
*   public void setId(int nId) {...}
*   public String getName() {...}
*   public void setName(String sName) {...}
* }
* 
* * The Person XML bean example above would have an XML declaration file that * resembles the following: *

* <xml-bean>
*   <name>person</name>
*   <property>
*     <name>Id</name>
*     <xml-name>person-id</xml-name>
*   </property>
*   <property>
*     <name>Name</name>
*     <xml-name>full-name</xml-name>
*   </property>
* </xml-bean>
* 
* * Consider the following code: *
System.out.println(new Person(15, "John Smith").toString());
* * The output would be: *

* <person>
*   <person-id>15</person-id>
*   <full-name>John Smith</full-name>
* </person>
* 
* * To specify namespace information for an XML bean, add an "xmlns" element to * the bean's descriptor: * *

* <xml-bean>
*   <name>person</name>
*   <xmlns>
*     <uri>the-schema-URI-goes-here</uri>
*     <prefix>the-default-namespace-prefix-goes-here</prefix>
*   <xmlns>
*   <property>
*     ...
*   </property>
* </xml-bean>
* 
* * @version 1.2 * * @author cp 2000.11.10 * @author gg 2002.05.17 anonymous element and XML Namespaces support * @author cp 2003.03.27 ExternalizableLite support */ public abstract class XmlBean extends ExternalizableHelper implements Cloneable, Externalizable, ExternalizableLite, XmlSerializable { // ----- constructors --------------------------------------------------- /** * Construct a value object. */ protected XmlBean() { } // ----- accessors ------------------------------------------------------ /** * Obtain the XmlBean that contains this XmlBean. * * @return the containing XmlBean, or null if there is none */ public XmlBean getParentXmlBean() { return m_parent; } /** * Specify the XmlBean that contains this XmlBean. * * @param parent the XmlBean that contains this XmlBean */ protected void setParentXmlBean(XmlBean parent) { XmlBean parentOrig = m_parent; if (parentOrig != null && parentOrig != parent) { throw new IllegalStateException("ParentXmlBean is immutable."); } m_parent = parent; } /** * Helper to adopt a Map of XmlBean objects. * * @param map a Map that may contain keys and/or values that are XmlBeans */ protected void adopt(Map map) { if (map != null && !map.isEmpty()) { adopt(map.keySet()); adopt(map.entrySet()); } } /** * Helper to adopt a Collection of XmlBean objects. * * @param coll a Collection that may contain XmlBeans */ protected void adopt(Collection coll) { if (coll != null && !coll.isEmpty()) { adopt(coll.iterator()); } } /** * Helper to adopt a collection of XmlBean objects. * * @param iter an Iterator that may contain XmlBeans */ protected void adopt(Iterator iter) { if (iter != null) { while (iter.hasNext()) { Object o = iter.next(); if (o instanceof XmlBean) { adopt((XmlBean) o); } } } } /** * Helper to adopt a collection of XmlBean objects. * * @param ao an array that may contain XmlBeans */ protected void adopt(Object[] ao) { if (ao != null) { for (int i = 0, c = ao.length; i < c; ++i) { Object o = ao[i]; if (o instanceof XmlBean) { adopt((XmlBean) o); } } } } /** * When an XmlBean adds a contained XmlBean, it should invoke this method * to relate the contained XmlBean with this XmlBean. * * @param child the XmlBean that is being contained within this XmlBean */ protected void adopt(XmlBean child) { child.setParentXmlBean(this); } /** * Determine if this value can be modified. If the value can not be * modified, all mutating methods are required to throw an * UnsupportedOperationException. * * @return true if this value can be modified, otherwise false to * indicate that this value is read-only */ public boolean isMutable() { return m_fMutable; } /** * Specify whether this value can be modified or not. * * @param fMutable true to allow this value to be modified, otherwise false * to indicate that this value is read-only */ protected void setMutable(boolean fMutable) { m_fMutable = fMutable; } /** * Make sure that this XML bean is mutable. * * @return this XmlBean if it is mutable, otherwise a mutable copy of this * XmlBean */ public XmlBean ensureMutable() { if (isMutable()) { return this; } XmlBean that = (XmlBean) this.clone(); azzert(that.isMutable()); return that; } /** * Make sure that this value is read-only (immutable). */ public void ensureReadOnly() { setMutable(false); } /** * Verify that this XmlBean is mutable. This method is designed to be * called by all mutator methods of an XmlBean to ensure that the bean * fulfills the contract provided by the Mutable property. */ protected void checkMutable() { if (!isMutable()) { throw new IllegalStateException(getBeanInfo().getName() + " is immutable"); } // a child XmlBean is immutable if its parent is immutable XmlBean parent = getParentXmlBean(); if (parent != null) { parent.checkMutable(); } } /** * Get the cached hash code. Value objects whose hash code is supposed * to change must override the hashCode implementation. * * @return the cached hash code */ protected int getHashCode() { return m_nHash; } /** * Set the cached hash code. Value objects whose hash code is supposed * to change must override the hashCode implementation. * * @param nHash the hash code */ protected void setHashCode(int nHash) { m_nHash = nHash; } /** * Obtain the BeanInfo for this XmlBean object, or create and configure * a BeanInfo if one does not exist. * * @return the BeanInfo that describes this XmlBean */ public BeanInfo getBeanInfo() { BeanInfo info = m_info; if (info == null) { info = findBeanInfo(); azzert(info != null); m_info = info; } return info; } /** * Obtain the PropertyAdapter objects for this XmlBean. * * @return the PropertyAdapter objects that handle the properties of * this XmlBean */ public PropertyAdapter[] getAdapters() { return getBeanInfo().getAdapters(); } // ----- Object methods ------------------------------------------------- /** * Determine if this value object is equal to the passed value object. * * @param o the other value object to compare to * * @return true if the other value object is equal to this */ public boolean equals(Object o) { // optimization: incompatible class if (!(o instanceof XmlBean)) { return false; } // optimization: same object XmlBean that = (XmlBean) o; if (this == that) { return true; } // optimization: check cached hash codes int nThis = this.getHashCode(); int nThat = that.getHashCode(); if (nThis != 0 && nThat != 0 && nThis != nThat) { return false; } // no optimization available; check each property for inequality PropertyAdapter[] aAdapter = getAdapters(); for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; Object oThis = adapter.get(this); Object oThat = adapter.get(that); if (!adapter.equalsValue(oThis, oThat)) { return false; } } // no inequality found; objects are equal return true; } /** * Determine a hash code for this value object. For value objects with * multiple properties, the hash code is calculated from the xor of the * hash codes for each property. * * @return a hash code for this value object */ public int hashCode() { // check to see if the hashcode is cached int n = getHashCode(); if (n == 0) { // calculate the hash code as the xor of the hashcode of each // property PropertyAdapter[] aAdapter = getAdapters(); for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; n ^= adapter.hash(adapter.get(this)); } // don't allow a hash of zero because it would be recalculated // on every call if (n == 0) { n = -1; } // cache the hash code setHashCode(n); } return n; } /** * To assist in debugging, provide a clear indication of the key's * state. * * @return a String representing this key object */ public String toString() { // default implementation of toString is to convert the XML bean to // an XML format and return that as a String return XmlHelper.toString(this); } /** * Clone the value object. * * @return a clone of this object */ public Object clone() { // start with a shallow clone XmlBean that; try { that = (XmlBean) super.clone(); } catch (CloneNotSupportedException e) { throw ensureRuntimeException(e); } // the clone is not automatically a child of this XmlBean's parent that.m_parent = null; that.setMutable(true); // clone any properties that need to be deep cloned; if no deep // cloning is required, this step is skipped entirely BeanInfo info = getBeanInfo(); if (info.requiresDeepClone()) { PropertyAdapter[] aAdapter = info.getAdapters(); for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; if (adapter.isCloneRequired() && adapter.getMutator() != null) { Object o = adapter.get(this); if (o != null) { adapter.set(that, adapter.clone(o)); } } } } return that; } // ----- XmlSerializable methods ---------------------------------------- /** * Serialize the object into an XmlElement. * * @return an XmlElement that contains the serialized form of the object */ public XmlElement toXml() { BeanInfo info = getBeanInfo(); PropertyAdapter[] aAdapter = info.getAdapters(); String sName = info.getName(); if (sName.length() == 0) { // the name must be discarded by the caller XmlElement xml = new SimpleElement( ClassHelper.getSimpleName(info.getType())); for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; Object o = adapter.get(this); if (!adapter.isEmpty(o)) { adapter.writeXml(xml, o); // not more then one property for an anonymous [choice] element // (see http://www.w3.org/TR/xmlschema-0/#element-choice) break; } } return xml; } else { String sNmsPrefix = info.getNamespacePrefix(); XmlElement xml; if (sNmsPrefix == null) { xml = new SimpleElement(sName); } else { xml = new SimpleElement(sNmsPrefix + ':' + sName); XmlHelper.ensureNamespace(xml, sNmsPrefix, info.getNamespaceUri()); } for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; Object o = adapter.get(this); // adapters decide whether or not to process null values adapter.writeXml(xml, o); } if (sNmsPrefix != null) { XmlHelper.purgeChildrenNamespace(xml); } return xml; } } /** * Deserialize the object from an XmlElement. * * This method can throw one of several RuntimeExceptions. * * @param xml an XmlElement that contains the serialized form of the * object * * @throws UnsupportedOperationException if the operation is not supported * @throws IllegalStateException if this is not an appropriate state * @throws IllegalArgumentException if there is an illegal argument */ public void fromXml(XmlElement xml) { BeanInfo info = getBeanInfo(); PropertyAdapter[] aAdapter = info.getAdapters(); String sName = info.getName(); if (sName.length() == 0) { // for anonymous elements one and only one adapter may fit for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; if (adapter.getMutator() != null && (adapter.isAnonymous() || adapter.isElementMatch(xml))) { XmlElement xmlParent = new SimpleElement( ClassHelper.getSimpleName(getClass())); xmlParent.getElementList().add(xml); // plug the dummy parent into the xml tree // to preserve a Namespace context List list = xml.getElementList(); list.add(xmlParent); try { Object o = adapter.readXml(xmlParent); if (o != null) { adapter.set(this, o); } } finally { list.remove(xmlParent); } break; } } } else { for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; if (adapter.getMutator() != null) { Object o = adapter.readXml(xml); if (o != null) { adapter.set(this, o); } } } } } // ----- Externalizable interface --------------------------------------- /** * The object implements the readExternal method to restore its * contents by calling the methods of DataInput for primitive * types and readObject for objects, strings and arrays. The * readExternal method must read the values in the same sequence * and with the same types as were written by writeExternal. * * @param in the stream to read data from in order to restore the object * * @exception IOException if I/O errors occur * @exception ClassNotFoundException if the class for an object being * restored cannot be found. */ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { readExternal((DataInput) in); } /** * The object implements the writeExternal method to save its contents * by calling the methods of DataOutput for its primitive values or * calling the writeObject method of ObjectOutput for objects, strings, * and arrays. * * @serialData Overriding methods should use this tag to describe * the data layout of this Externalizable object. * List the sequence of element types and, if possible, * relate the element to a public/protected field and/or * method of this Externalizable class. * * @param out the stream to write the object to * @exception IOException includes any I/O exceptions that may occur */ public void writeExternal(ObjectOutput out) throws IOException { writeExternal((DataOutput) out); } // ----- ExternalizableLite interface ----------------------------------- /** * Restore the contents of this object by loading the object's state from * the passed DataInput object. * * @param in the DataInput stream to read data from in order to restore * the state of this object * * @exception IOException if an I/O exception occurs * @exception NotActiveException if the object is not in its initial * state, and therefore cannot be deserialized into */ public void readExternal(DataInput in) throws IOException { boolean fMutable = in.readBoolean(); BeanInfo info = getBeanInfo(); PropertyAdapter[] aAdapter = info.getAdapters(); // the stream "in" is packed with accessor-index/value pairs, // and terminated with a -1 index (with no corresponding value) int i; while ((i = readInt(in)) >= 0) { PropertyAdapter adapter = aAdapter[i]; Object o = adapter.readExternal(in); if (o != null && adapter.getMutator() != null) { adapter.set(this, o); } } // now that everything is set up, configure the read-only versus // mutable attribute of the XML bean m_fMutable = fMutable; } /** * Save the contents of this object by storing the object's state into * the passed DataOutput object. * * @param out the DataOutput stream to write the state of this object to * * @exception IOException if an I/O exception occurs */ public void writeExternal(DataOutput out) throws IOException { out.writeBoolean(m_fMutable); BeanInfo info = getBeanInfo(); PropertyAdapter[] aAdapter = info.getAdapters(); for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; if (adapter.getMutator() != null) // only save what can be restored { Object o = adapter.get(this); if (!adapter.isEmpty(o)) { writeInt(out, i); adapter.writeExternal(out, o); } } } writeInt(out, -1); // "EOF" aka "end of properties" marker } // ----- internal ------------------------------------------------------- /** * For backwards compatibility only - loads reflection info. * * This method is intended to be called by the static initializer of each * concrete sub-class. * * @param clz the class to initialize * @param sName the name of the value object * @param asProp the property names that make up the value object */ protected static void init(Class clz, String sName, String[] asProp) { XmlElement xml = new SimpleElement("xml-bean"); xml.addElement("name").setString(sName); for (int i = 0, c = asProp.length; i < c; ++i) { XmlElement xmlProp = xml.addElement("property"); String sProp = asProp[i]; xmlProp.addElement("name") .setString(sProp); xmlProp.addElement("xml-name").setString(sProp); } s_mapXml.put(clz, xml); } /** * Obtain the BeanInfo object for this XML bean. * * @return the BeanInfo for this Object */ private BeanInfo findBeanInfo() { Class clz = getClass(); BeanInfo info = (BeanInfo) s_mapInfo.get(clz); if (info == null) { info = initBeanInfo(); s_mapInfo.put(clz, info); } return info; } /** * Initialize the Object, loading the XML Bean design information if * necessary. * * @return a BeanInfo object */ protected BeanInfo initBeanInfo() { Class clzBean = getClass(); XmlElement xml = null; Class clz = clzBean; while (clz != null) { XmlElement xmlClz = (XmlElement) s_mapXml.get(clz); if (xmlClz == null) { xmlClz = XmlHelper.loadXml(clz); } if (xml == null) { xml = xmlClz; } else if (xmlClz != null) { // insert the super class properties List list = xml.getElementList(); int ix = 0; for (Iterator iter = xmlClz.getElements("property"); iter.hasNext();) { XmlElement xmlProp = (XmlElement) iter.next(); String sProp = xmlProp.getElement("name").getName(); // check if a sub-class defined (over-rode) the // property; if so, put it in the order defined by the // superclass by removing it from its current position // and re-inserting it with the other superclass // properties XmlElement xmlSub = XmlHelper.findElement(xml, "/property/name", sProp); if (xmlSub != null) { xmlProp = xmlSub.getParent(); list.remove(xmlProp); } list.add(ix++, xmlProp); } } clz = clz.getSuperclass(); } azzert(xml != null, "Cannot find bean info for " + clzBean); return new BeanInfo(clzBean, xml); } /** * A BeanInfo contains information about the XML bean and its properties. * One BeanInfo will be created for each specific class of XmlBean. */ public static class BeanInfo { /** * Construct a BeanInfo. * * @param clzBean the class of the bean * @param xml the xml descriptor */ protected BeanInfo(Class clzBean, XmlElement xml) { // store the class of the specific XML bean m_clzBean = clzBean; // determine the XML element name to use for the XML bean String sName; XmlElement xmlName = xml.getElement("name"); if (xmlName == null) { xmlName = xml.getElement("xml-name"); } if (xmlName == null) { // default: use class name as XML element name sName = ClassHelper.getSimpleName(clzBean); } else { sName = xmlName.getString(); } azzert(sName != null); m_sName = sName; // determine the XML namespace URI and default prefix, if any XmlElement xmlNms = xml.getElement("xmlns"); if (xmlNms != null) { m_sNmsUri = xmlNms.getSafeElement("uri") .getString(null); m_sNmsPrefix = xmlNms.getSafeElement("prefix").getString(null); } // obtain a PropertyAdapter for each of the XML beans' properties List list = new ArrayList(); for (Iterator iter = xml.getElements("property"); iter.hasNext(); ) { XmlElement xmlProp = (XmlElement) iter.next(); String sProp = xmlProp.getSafeElement("name").getString(); azzert(sProp != null && sProp.length() > 0); XmlElement xmlXmlName = xmlProp.getElement("xml-name"); String sXmlName = xmlXmlName == null ? sProp : xmlXmlName.getString(); Class clzProp; String sClass = xmlProp.getSafeElement("type").getString(); if (sClass != null && sClass.length() > 0) { clzProp = resolveClass(sClass); } else { // use reflection to find the property's type Method method = null; try { method = clzBean.getMethod("get" + sProp, NOPARAMS); } catch (NoSuchMethodException e) { try { method = clzBean.getMethod("is" + sProp, NOPARAMS); } catch (NoSuchMethodException e2) { } } if (method == null) { throw new RuntimeException("Unable to find accessor for " + sProp + " on " + clzBean.getName()); } clzProp = method.getReturnType(); } list.add(makeAdapter(clzProp, sProp, sXmlName, xmlProp)); } PropertyAdapter[] aAdapter = (PropertyAdapter[]) list.toArray(new PropertyAdapter[list.size()]); m_aAdapter = aAdapter; // determine whether any of the properties causes the XML bean to // require "deep" cloning for (int i = 0, c = aAdapter.length; i < c; ++i) { PropertyAdapter adapter = aAdapter[i]; if (adapter.isCloneRequired() && adapter.getMutator() != null) { m_fDeepClone = true; break; } } if (USE_XMLBEAN_CLASS_CACHE) { m_nBeanId = XMLBEAN_CLASS_CACHE.getClassId(clzBean); } } // ----- accessors ---------------------------------------- /** * Get the class of the specific XML bean implementation. * * @return the type of the XML bean */ public Class getType() { return m_clzBean; } /** * Get the serialization ID for the specific XML bean implementation. * * @return the XmlBean ID used by ExternalizableHelper, or -1 if this * XmlBean does not have an ID assigned or if the ID * optimization is not being used */ public int getBeanId() { return m_nBeanId; } /** * Determine the element name that the XML bean will use when * serializing to XML. * * @return the local XmlElement name for the bean */ public String getName() { return m_sName; } /** * Obtain the namespace URI for this XML bean. * * @return the URI that qualifies the default Namespace for this bean */ public String getNamespaceUri() { return m_sNmsUri; } /** * Obtain the default namespace prefix for this XML bean. * * @return the default Namespace prefix for this bean */ public String getNamespacePrefix() { return m_sNmsPrefix; } /** * Set the default Namespace prefix for this XML bean. * * @param sPrefix the default namespace prefix */ public void setNamespacePrefix(String sPrefix) { m_sNmsPrefix = sPrefix; } /** * Obtain the PropertyAdapter objects for the properties of this XML bean. * * @return the property adapters for this bean */ public PropertyAdapter[] getAdapters() { return m_aAdapter; } /** * Determine if a clone of the XmlBean should be a deep clone, which * typically means that at least one property value is mutable * reference type. * * @return true if any of the property values must be "deep" cloned * when the XmlBean is cloned */ public boolean requiresDeepClone() { return m_fDeepClone; } // ----- helpers ---------------------------------------------------- /** * Generate a property adapter instance that will work on this bean class * and will adapt for a property of the specified class and of the * specified name. * * @param clz the class of the property * @param sName the property name * @param sXmlName the corresponding element name * @param xml additional XML information * * @return an adapter that will handle the specified property */ protected PropertyAdapter makeAdapter(Class clz, String sName, String sXmlName, XmlElement xml) { // check if the adapter implementation is specified String sAdapter = xml.getSafeElement("adapter").getString(); Class clzAdapter = sAdapter != null && sAdapter.length() > 0 ? resolveClass(sAdapter) : (Class) s_mapClassAdapters.get(clz); if (clzAdapter == null) { if (XmlElement.class.isAssignableFrom(clz)) { clzAdapter = XmlElementAdapter.class; } else if (XmlSerializable.class.isAssignableFrom(clz)) { clzAdapter = XmlSerializableAdapter.class; } else if (Object[].class.isAssignableFrom(clz)) { clzAdapter = ArrayAdapter.class; } else if (Collection.class.isAssignableFrom(clz)) { clzAdapter = CollectionAdapter.class; } else if (Map.class.isAssignableFrom(clz)) { clzAdapter = MapAdapter.class; } else if (Serializable.class.isAssignableFrom(clz)) { clzAdapter = SerializableAdapter.class; } } if (clzAdapter == null) { throw new RuntimeException("XmlBean: No suitable adapter for: " + clz.getName()); } try { // instantiate the adapter Constructor constructor = clzAdapter.getConstructor(ADAPTER_INIT_PARAMS); Object[] aoParams = new Object[] {this, clz, sName, sXmlName, xml}; return (PropertyAdapter) constructor.newInstance(aoParams); } catch (Exception e) { throw ensureRuntimeException(e, "Instantiating adapter: " + clzAdapter.getName()); } } /** * Find a property adapter instance for the specified property. * * @param sName the property name * * @return an adapter that handles the specified property; * null if none could be found */ public PropertyAdapter findAdapter(String sName) { PropertyAdapter[] aAdapter = getAdapters(); for (int i = 0, c = aAdapter.length; i < c; i++) { PropertyAdapter adapter = aAdapter[i]; if (adapter.getName().equals(sName)) { return adapter; } } return null; } /** * Resolve a Class name into a Class object. * * @param sClass the Class name * * @return the Class object */ public Class resolveClass(String sClass) { Class clz = (Class) s_mapClassNames.get(sClass); if (clz != null) { return clz; } if (sClass.endsWith("[]")) { clz = resolveClass(sClass.substring(0, sClass.length() - 2)); if (clz.isArray()) { sClass = '[' + clz.getName(); } else if (clz.isPrimitive()) { sClass = "[" + s_mapPrimitiveNames.get(clz); } else { sClass = "[L" + clz.getName() + ';'; } } try { ClassLoader loader = m_clzBean.getClassLoader(); if (loader == null) { loader = ClassLoader.getSystemClassLoader(); } return Class.forName(sClass, false, loader); } catch (Exception e) { throw ensureRuntimeException(e); } } // ----- Object methods ------------------------------------------------- /** * Debugging support. * * @return a String description of this Info object */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append("BeanInfo for ") .append(getName()) .append(", type=") .append(getType().getName()) .append(", requiresDeepClone=") .append(requiresDeepClone()) .append(", NamespaceUri=") .append(getNamespaceUri()) .append(", NamespacePrefix=") .append(getNamespacePrefix()); return sb.toString(); } // ----- data members ----------------------------------------------- /** * The class of the specific XML bean. */ protected Class m_clzBean; /** * The XML element name for the XML bean. */ protected String m_sName; /** * The property adapters for the XML bean. */ protected PropertyAdapter[] m_aAdapter; /** * Specifies whether the XML bean requires a deep clone. */ protected boolean m_fDeepClone; /** * Namespace URI. */ protected String m_sNmsUri; /** * Namespace prefix. */ protected String m_sNmsPrefix; /** * Serialization ID for the XmlBean class. */ protected int m_nBeanId = -1; // ----- constants -------------------------------------------------- /** * Parameters for finding no-parameter methods. */ protected static final Class[] NOPARAMS = new Class[0]; /** * Parameters for finding the default adapter constructor. */ protected static Class[] ADAPTER_INIT_PARAMS = new Class[] { BeanInfo .class, Class .class, String .class, String .class, XmlElement.class, }; /** * Map from type name / short class name to actual class instance. */ protected static final Map s_mapClassNames = new HashMap(); static { Map map = s_mapClassNames; map.put("boolean" , boolean .class); map.put("byte" , byte .class); map.put("char" , char .class); map.put("short" , short .class); map.put("int" , int .class); map.put("long" , long .class); map.put("float" , float .class); map.put("double" , double .class); map.put("Boolean" , Boolean .class); map.put("Byte" , Byte .class); map.put("Character" , Character .class); map.put("Short" , Short .class); map.put("Integer" , Integer .class); map.put("Long" , Long .class); map.put("Float" , Float .class); map.put("Double" , Double .class); map.put("BigDecimal", BigDecimal .class); map.put("BigInteger", BigInteger .class); map.put("String" , String .class); map.put("Date" , Date .class); map.put("Time" , Time .class); map.put("Timestamp" , Timestamp .class); } /** * Map from the class of a property type to the class of the adapter * that handles the type. */ protected static final Map s_mapClassAdapters = new HashMap(); static { Map map = s_mapClassAdapters; map.put(boolean.class , SimpleAdapter.BooleanAdapter.class); map.put(byte .class , SimpleAdapter.ByteAdapter .class); map.put(char .class , SimpleAdapter.CharAdapter .class); map.put(short .class , SimpleAdapter.ShortAdapter .class); map.put(int .class , SimpleAdapter.IntAdapter .class); map.put(long .class , SimpleAdapter.LongAdapter .class); map.put(float .class , SimpleAdapter.FloatAdapter .class); map.put(double .class , SimpleAdapter.DoubleAdapter .class); map.put(Boolean .class , SimpleAdapter.BooleanAdapter.class); map.put(Byte .class , SimpleAdapter.ByteAdapter .class); map.put(Character.class , SimpleAdapter.CharAdapter .class); map.put(Short .class , SimpleAdapter.ShortAdapter .class); map.put(Integer .class , SimpleAdapter.IntAdapter .class); map.put(Long .class , SimpleAdapter.LongAdapter .class); map.put(Float .class , SimpleAdapter.FloatAdapter .class); map.put(Double .class , SimpleAdapter.DoubleAdapter .class); map.put(boolean[].class , PrimitiveArrayAdapter.BooleanArrayAdapter.class); map.put(byte [].class , PrimitiveArrayAdapter.ByteArrayAdapter .class); map.put(char [].class , PrimitiveArrayAdapter.CharArrayAdapter .class); map.put(short [].class , PrimitiveArrayAdapter.ShortArrayAdapter .class); map.put(int [].class , PrimitiveArrayAdapter.IntArrayAdapter .class); map.put(long [].class , PrimitiveArrayAdapter.LongArrayAdapter .class); map.put(float [].class , PrimitiveArrayAdapter.FloatArrayAdapter .class); map.put(double [].class , PrimitiveArrayAdapter.DoubleArrayAdapter .class); map.put(String .class, SimpleAdapter.StringAdapter .class); map.put(BigDecimal .class, SimpleAdapter.BigDecimalAdapter.class); map.put(BigInteger .class, SimpleAdapter.BigIntegerAdapter.class); map.put(Date .class, SimpleAdapter.DateAdapter .class); map.put(Time .class, SimpleAdapter.TimeAdapter .class); map.put(Timestamp .class, SimpleAdapter.TimestampAdapter .class); map.put(java.util.Date.class, SimpleAdapter.OldDateAdapter .class); } /** * Map from class of an intrinsic type to its JVM signature. */ protected static final Map s_mapPrimitiveNames = new HashMap(); static { Map map = s_mapPrimitiveNames; map.put(boolean.class , "Z"); map.put(byte .class , "B"); map.put(char .class , "C"); map.put(short .class , "S"); map.put(int .class , "I"); map.put(long .class , "J"); map.put(float .class , "F"); map.put(double .class , "D"); } } // ----- data members --------------------------------------------------- /** * For backwards compatibility -- caches XML descriptors that wrap the * old-style data used for XmlBean initialization. */ private static Map s_mapXml = new SafeHashMap(); /** * Cache by class of reflection information. */ private static Map s_mapInfo = new SafeHashMap(); /** * If this XmlBean is contained by another XmlBean, then the containing * bean reference is held by this XmlBean. */ private transient XmlBean m_parent; /** * Mutable/read-only setting. */ private boolean m_fMutable = true; /** * Cached hash value. */ private transient int m_nHash; /** * Cached bean info (for this bean). */ private transient BeanInfo m_info; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy