|
Buscador
Secciones
Otras zonas
Registro
Foros
Recomendamos
|
Listado 1. Este DTD le dice al analizador XML cómo chequerar el XML del JavaBean para corregirlo antes de intentar procesarlo. Si usamos un analizador validante con este DTD, podemos estar seguro de que cualquier árbol XML que leamos desde un fichero sigue las reglas de un XMLBean bien formateado. El formato de fichero es un poco inflexible. Podríamos haber notado que nadie excepto nosotros usa este dialécto particular de "JavaBean XML." ¿Qué pasa si queremos analizar cualquier documento XML y convertirlo en un JavaBean? El nuevo paquete XMLBeans hace esto. Mientras que el lenguaje JavaBean XML definido arriba todavía funciona, la clase XMLBeanReader ahora acepta cualquier XML bien-formateado, e intenta construir un bean de lo que encuentra. Hace esto asumiendo que:
Por eso, por ejemplo, digamos que teníamos una clase JavaBean llamada Player (conocida de las páginas anteriores). Algunas de las propiedades son JavaBeans, que también tienen propiedades. Las clases JavaBean y las propiedades en nuestro ejemplo son las siguientes:
En nuestro dialecto XML original, usando el DTD en el Listado 1, las primeras líneas de un XMLBean se podrían parecer al Listado 2:
Listado 2. Codificar la misma información en el nuevo formato es mucho más claro, como en el Listado 3:
Listado 3. Observa que se han eliminado casi todas las marcas especificas del lenguaje específico XMLBeans. Lo único que queda es el atributo CLASS sobre la propiedad Name. El listado 3 ejemplifica todas las siguientes reglas para la nueva síntaxis excepto la quinta:
Un par de detalles menores sobre esta nueva síntaxis merecen una pequeña explicación. Primero, ¿Por qué mantenemos el atributo CLASS? ¿Por qué no requerir sólo que el nombre de la etiqueta sea el nombre de la clase? Hay dos razones para esta decisión. Primero, el atributo CLASS opcional proporciona una identificación no ambigüa de la clase de la propiedad. ¿Qué pasa si hubiera dos o más clases llamadas Player en nuestro CLASSPATH? ¿Cuál debería elegir el XMLBeanReader? Segundo, y más importante, el atributo class puede usarse para identificar qué subclase usar si un tipo de propiedad es abstracto. ¿Qué pasaría si PersonName fuera una clase base abstracta, con subclases de MarriedName, MaidenName, y NickName? ¿Qué clase debería usar XMLBeanReader cuando cree un nuevo JavaBean? El elemento <Properties> podría haber sido eliminado enteramente; y de hecho, es opcional. La razón por la que lo hemos dejado en la síntaxis es para futuras expansiones. Actualmente lo único almacenado sobre XMLBeans son las propiedades JavaBeans. En el futuro, podríamos querer almacenar conjuntos de eventos, datos cacheados, firmas digitales, u otra información sobre el bean que no está disponible desde las propiedades. El elemento <Properties> nos permite indicar qué subnodos del bean son propiedades. En este ejemplo, no lo necesitamos porque todo lo que realmente procesamos es la lista de propiedades. Ya hemos descrito las mejoras a XMLBeans. Ahora veamos algunos ejemplos.
|
816/** Read a bean's state from a character stream
817 * @param r The Reader from which to read the
* JavaBean's state.
818* @return Object The newly-created,
* initialized JavaBean.
819* @exception IOException
820* @exception ClassNotFoundException
821* @exception IntrospectionException
822*/
823public static Object readXMLBean(Reader r)
824 throws IOException, ClassNotFoundException,
IntrospectionException {
825
826 // Read document from XML file
827 String sParserClassname = "";
828 Parser parser = null;
829
830 // Create a SAX parser
831 try {
832 parser = ParserFactory.makeParser("com.ibm.xml.parsers.NonValidatingDOMParser");
833 } catch (Exception exc) {
834 System.err.println("Exception");
835 exc.printStackTrace();
836 }
837
838 P("Created parser");
839
840 // Run the SAX parser against the input stream
841 try {
842 parser.parse(new org.xml.sax.InputSource(r));
843 } catch (SAXException sx) {
844 System.err.println("Exception: " + sx.toString());
845 sx.printStackTrace();
846 } catch (Exception ex) {
847 System.err.println("Threw " + ex.getClass().getName());
848 ex.printStackTrace();
849 }
850
851 // Since we know the SAX parser is also
// a DOM parser,
852 // we can ask it for its resulting document.
853 Document d = ((NonValidatingDOMParser)parser).getDocument();
854 P("Got document " + isNull(d));
855
856 Element eJavaBean = d.getDocumentElement();
857 P("eJavaBean is " + isNull(eJavaBean));
858
859 Object o = instantiateBean(eJavaBean);
860
861 return o;
862 }
|
instantiateBean()
El método instantiateBean() (listado 5) simplemente obtiene el nombre de la clase del
Bean y luego carga el bean como si fuera un valor de propiedad y otro bean llamando a
loadValue(), el método real del paquete.
477/** Instantiate the JavaBean, and set all of
* its properties
478 * The element must be of type "JavaBean"
479 * @param eJavaBean The DOM Element object
* representing the JavaBean.
480 * It is the root of a DOM document tree that
* contains the information
481 * used to instantiate and initialize the
* JavaBean. The element's
482 * tag must be JavaBean.
483 * @return java.lang.Object
484 * @exception IOException
485 * @exception ClassNotFoundException
486 * @exception IntrospectionException
487 */
488 protected static Object instantiateBean( Element eJavaBean)
489 throws IOException, ClassNotFoundException,
IntrospectionException {
490
491 // Load the value from the node
492 Object jb = loadValue(classOfBean, eJavaBean, null);
494
495 // Return the newly-instantiated JavaBean.
496 return jb;
497 }
|
loadValue()
El método loadValue() (Listado 6) es responsable de cargar todas las propiedades del
JavaBean cuya clase recibe. Siempre recibe la clase del objeto a crear y un Element
qiue es la raíz de un subárbol DOM que codifica el valor. También hay un
PropertyDescriptor que podría contener información sobre el valor y cómo
seleccionarlo. Si el valor a devolver no es una propiedad de cualquier otro objeto (que es el caso sólo si es el JavaBean
de más alto nivel que está siendo codificado, ver la llamada en instantiateBean()
arriba), el PropertyDescriptor es null.
565 /**
566 * Load a value from an element node. The
* resulting value will either be a
567 * JavaBean or a primitive wrapper object;
* in either case, the result is almost
568 * always passed to a setter method. If the PropertyDescriptor is not null,
569 * then this object is a property of another
* object, and the descriptor describes it.
570 * @return boolean
571 * @param bean java.lang.Object
572 * @param node org.w3c.dom.Node
573 */
574 public static Object loadValue( Class objectType, Element element, PropertyDescriptor pd) {
575 Object value = null;
576 Pe("Loading element " + element.getTagName() + " for object " + objectType.getName());
577
578 // If this is a primitive property, we want to
// return an object
579 // of the appropriate type for the property
// descriptor's setter method
580 if (pd != null) {
581 if (objectType.isPrimitive()) {
582 value = getPrimitive(objectType, element);
583 return value;
584 }
585 }
586
587 // Create an instance of this bean. This
// will be our return value.
588 try {
589 value = Beans.instantiate(null, objectType.getName());
590 } catch (Exception ex) {
591 return null;
592 }
593
594 // First, find out if this object knows how to
// read itself
595 // from a DOM tree. If it does, we simply
// defer to the object
596 // itself, and we have no further work to do.
597 Method domSetter = getDOMSetter(value, null);
598 if (domSetter != null) {
599 try {
600 domSetter.invoke(value, new Object[] {element});
601 } catch (Exception ex) {
602 Pe("loadValue:");
603 Pe(ex.getClass().getName());
604 ex.printStackTrace();
605 }
606 return value;
607 }
608
609 // Get the first child of the element that
// is either nonwhite text (in
610 // which case we try to initialize the
// value from that); or a noncomment
611 // nonterminal node, in which case the value
// must be a bean.
612 Node n =Util.getFirstInterestingChild(element);
613
614 // If the syntax is <
// Property NAME="foo"><
// JavaBean CLASS="bar">...,
615 // then we want to look under the <
// JavaBean> node for properties,
616 // not under the <Property> node.
617 Element topElement = element;
618 if (n instanceof Element && ((Element)n).getTagName().equals("JavaBean")) {
619 topElement = (Element)n;
620 }
621
622 // If n is null, initialize value with a
// blank string.
623 // If n is Text, initialize value with the
// value of the text.
624 String scalarValue = null;
625 if (n == null) {
626 scalarValue = "";
627 } else {
628 if (n instanceof Text) {
629 scalarValue = ((Text) n).getData();
630 }
631 }
632
633 // If scalarValue is not null, then we want to
// set the value from
634 // a string. This makes it easy for objects to
// simply serialize
635 // themselves to flat strings, and then
// deserialize themselves
636 // back from those strings. Essentially, the
// PropertyEditor works
637 // as a tiny parser for the string value.
638 if (scalarValue != null && pd != null) {
639 // Use the property editor to initialize
// the value.
640 if ((value = loadValue(objectType, scalarValue, pd)) != null) {
641 return value;
642 }
643 Pe("loadValue() failed for property " + pd.getName() + ", value = '" + scalarValue + "'");
644 }
645
646 // Since the object didn't know how to set
// itself from a DOM,
647 // and the DOM that represents it contains
// multiple nodes, we're
648 // going to have to enumerate all of the
// properties. Assume that
649 // each subnode is a property, creating and
// initializing a value for
650 // each one, and then using the property
// setter to set that value.
651 // If a <Properties> node exists in my
// subnodes, that's the list of
652 // my properties, instead of all
// of my subnodes.
653 Node propertyList = topElement;
654 NodeList nl = topElement.getChildNodes();
655 int i;
656 for (i = 0; i < nl.getLength(); i++) {
657 if (nl.item(i) instanceof Element) {
658 Element e = (Element) (nl.item(i));
659 if (e.getTagName().equals("Properties")) {
660 propertyList = e;
661 break;
662 }
663 }
664 }
665
666 // Introspect object to get properties, then
// create a hash table
667 // with property names as keys and descriptors
// as contents
668 // Use the introspector to get the property
// descriptors
669 // for this bean.
670 PropertyDescriptor[] pds = getPropertyDescriptors(value.getClass());
671
672 // Create a hash table of property names
// and property descriptors
673 Hashtable htpd = new Hashtable();
674 for (i = 0; i < pds.length; i++) {
675 htpd.put(pds[i].getName().toLowerCase(), pds[i]);
676 }
677
678 // Now iterate through all of the properties
// in the propertyList,
679 // loading each one recursively, and
// passing the returned value
680 // to the setter method.
681 nl = propertyList.getChildNodes();
682 for (i = 0; i < nl.getLength(); i++) {
683
684 // Get the name of the property,
// ignoring rubbish
685 String propertyName =getPropertyName(nl.item(i));
686 if (propertyName == null)
687 continue;
688
689 p("Property name = '" + propertyName + "'");
690
691 // Must be an element, since it wouldn't
// have a propertyName if not
692 Element e = (Element) (nl.item(i));
693
694 // Get the property descriptor for the property,
// ignoring
695 // if there's no descriptor for it
696 PropertyDescriptor thispd = (PropertyDescriptor) (htpd.get(propertyName.toLowerCase()));
697 if (thispd == null) {
698 Pe("Couldn't get PropertyDescriptor for property " + propertyName);
699 continue;
700 }
701
702 // See if either the property descriptor or
// the bean knows how
703 // to set the value as a DOM tree
704 Method mDOMSetter = getDOMSetter(value, thispd);
705
706 if (mDOMSetter != null) {
707 P(" DOM Setter = "+ mDOMSetter.getName());
708 try {
709 mDOMSetter.invoke(value, new Object[] {e});
710 continue;
711 } catch (Exception ee) {
712 Pe("Exception occurred while setting " + propertyName + " as DOM: " + ee.getMessage());
713 ee.printStackTrace();
714 return null;
715 }
716 } else {
717 p(", no DOM setter");
718 }
719
720 // Call the setter directly. To do this,
// we have to get the setter method for
721 // the property, create an instance of its
// property type, and
722 // try to recursively loadValue() a value for it.
723 // That should handle both properties that are
// JavaBeans
724 // and properties that can somehow be
// constructed from a string.
725 Method mSetter = thispd.getWriteMethod();
726 if (mSetter != null) {
727 P(", Setter " + mSetter.getName());
728 try {
729 // Get the class of the property
730 Class cValue = getPropertyType(e, thispd);
731 Object setterArg = null;
732
733 // The setter argument is the object
// referred to by the
734 // current element e. Calling loadValue()
// recursively here
735 // returns the argument for the setter.
736 if ((setterArg = loadValue(cValue, e, thispd)) != null) {
737 mSetter.invoke(value, new Object[] {setterArg});
738 } else {
739 Pe("Couldn't set " + cValue.getName() + " " + thispd.getName());
740 }
741 } catch (Exception ex) {
742 Pe("Couldn't create or set " + thispd.getPropertyType().getName()
+ " for property " + pd.getName());
743 ex.printStackTrace();
744 }
745 } else {
746 P(", Setter null");
747 }
748 }
749
750 // Return the value we've just created.
751 return value;
752 }
|
Refierendose al código, loadValue() realiza las siguientes tareas:
| Líneas | Descripción |
|---|---|
| 578-585 | getPrimitive() codifica una propiedad primitiva (véase abajo). Una propiedad que no sea primitiva debe tener un constructor por defecto, así que usamos java.beans.Beans.instantiate() para crear un ejemplar para el resultado. (Usar este método no es enteramente correcto, puesto que el resultado puede ser un objeto no-bean. El código debe controlar si la clase del resultado es un bean o no, y usar new si no lo es. |
| 588-591 | Crear el "value" para ser incializado desde Element. El valor es simplemente un ejemplar del tipo de retorno. |
| 594-607 | Si el objeto conoce cómo inicializarse a sí mismo desde un árbol DOM (es decir, si la clase valor define setAsDOM()), simplemente pasa el árbol DOM al método "setter" DOM y se crea el Bean. El método getDOMSetter() devuelve un objeto Method que representa al "setter" DOM para la propiedad, o null si no se pudo encontrar ninguno. Si se encontró un "setter" DOM, esta sección lo llama y retorna. getDOMSetter() (ver el fichero fuente) encuentra un método de una de estas formas: (1) si pd es un XMLPropertyDescriptor, devuelve el "setter" DOM desde el descriptor (llamando al método getDOMWriteMethod() del descriptor); o (2) si la clase del valor define getPropertynameAsDOM(), se devuelve ese método. |
| 609-620 | Los contenidos del nodo valor podrían ser una de dos cosas. Podia ser una simple cadena de texto, en cuyo caso, el valor de la propiedad podría construirse desde un string como este: <Size>12</Size> o, podrían ser otros nodos Element definiendo una lista de propiedades, como esta: <Size>12</Size> <Color>Red</Color> Los espacios en blanco mostrados en la entrada crean nodos Text que contiene espacios en blanco, y también podrían ser nodos Comment que son saltados en el XML . getFirstInterestingChild() es un método de utilidad que encuentra el primer hijo que es un nodo Text no vacío, o cualquier otro tipo de nodo que no sea Comment. |
| 622-644 | Si el objeto que estamos creando va a ser inicializado desde un nodo Text (es decir, un String), llamamos desde otra forma de loadValue() que está especializada en la inicialización de un objeto desde un String: |
| 666-752 | Este código es el método estándar para crear XMLBean en ausencia de cualquier personalización. El objeto que está siendo creado es inspeccionado para conseguir una lista de sus propiedades, y entonces se crea una tabla que indexa los nombres de propiedades contra sus correspondientes descriptores. (Estas son las propiedades del valor creado.) Puesto que cada hijo del Element actual es una propiedad del valor que es siendo creado, el código busca entre todos los elementos hijos de este nodo, obteniendo un valor para cada uno (mediante una llamada recursiva a loadValue()), y después fijándolo con el método "setter" de esa propiedad, llamado sobre el ejemplar que estamos creando. Es un poco confuso al principio. Simplemente estamos llamando a loadValue() recursivamente para conseguir el valor de cada propiedad de valor que está siendo creada actualmente. El bean Player, por ejemplo, necesita llamar a loadValue() para conseguir los valores para sus propiedades stats, grades y name, y utiliza loadValue() para hacerlo. |
loadValue(), de nuevo
Las líneas 526-563 en
XMLBeanReader,
sólo concierne a la creacción de aquellos valores que pueden ser construidos desde objeto
String. Crea un nuevo ejemplar de la clase valor, usa el
PropertyEditor de la clase valor para inicializar el valor, y devolver el resultado.
getPrimitive()
Los tipos primitivos son un poco complicados porque necesitan una clase envoltura para pasarlos a un objeto
Method (que es nuestra única forma de acceder al "setter").
getPrimitive() acepta el objeto Class primitivo y
construye un objeto envoltura apropiado usando el String del árbol DOM para inicializar
el valor. La envoltura la crea getPrimitiveSetterArg(), que es interesante si queremos
ver cómo construir un objeto cuando incluso no conocemos la clase del objeto en el momento de la ejecución: simplemente
obtenemos el constructor y lo llamamos!
Los otros métodos de la clase XMLBeanReader son simples utilidades. Entendiendo la primera forma de loadValue(), no tendremos problemas en entender cómo funciona el resto de la clase.
XMLBeanWriterXMLBeanWriter crea un árbol DOM que representa un JavaBean. El árbol DOM resultante puede luego ser escrito en un fichero XML. XMLBeanWriter es más simple que XMLBeanReader. El único método que hace algún trabajo interesante es getAsDOM(), que viene en dos formas: una para un bean, y otra para las propiedades de un bean.
getAsDOM()
Listado 7 contiene el método getAsDOM() usado para beans enteros. La otra versión
de getAsDOM() devuelve un DocumentFragment que
codifica una propiedad y es usado por la primera versión. En el listado 8 podrás encontrar una descripción de la
segunda forma de getAsDOM().
022 /**
023 * Build a DOM DocumentFragment representing
* the class and properties of
024 * a JavaBean.
025 * @return org.w3c.dom.DocumentFragment -
* the document representing the JavaBean.
026 * @param doc Creates nodes using this
* document as a factory.
027 * @param bean The JavaBean for which we
* want the DOM tree
028 * @exception java.beans.IntrospectionException
* An error occurred during
029 * introspection of the JavaBean.
030 */
031 public static DocumentFragment getAsDOM(Document doc, Object bean) throws
IntrospectionException, InstantiationException, IllegalAccessException {
032
033 // Create the fragment we'll return
034 DocumentFragment dfResult = null;
035
036 // Analyze the bean
037 Class classOfBean = bean.getClass();
038
039 // See if the bean has a custom name for its
// DOM setter
040 String nameOfGetter = "getAsDOM";
041 try {
042 Method mNameGetter = classOfBean.getMethod("getDOMGetterName",new Class[] {});
043 nameOfGetter = (String) (mNameGetter.invoke(bean, new Object[] {}));
044 } catch (Exception ex) {
045 ; // Ignore exceptionsthis
// either works or it doesn't
046 }
047
048 // If the bean knows how to encode itself
// in XML, then
049 // use the DOM document it returns.
050 Method mGetAsDOM = null;
051 try {
052 mGetAsDOM =classOfBean.getMethod(nameOfGetter,new Class[] {org.w3c.dom.Document.class });
053 if (mGetAsDOM != null) {
054 dfResult =(DocumentFragment) (mGetAsDOM.invoke(bean,new Object[] {doc}));
055 return dfResult;
056 }
057 } catch (Exception e) {
058 ; // Ignore exceptions
059 }
060
061 // If we found a DOM read method, invoke it,
// and we're done.
062 if (mGetAsDOM != null) {
063 try {
064 dfResult = (DocumentFragment) mGetAsDOM.invoke(bean, new Object[] {doc});
065 return dfResult;
066 } catch (Exception e) {
067 ; // Ignore exceptions
068 }
069}
070
071 // Get a BeanInfo for the bean.
072 BeanInfo bi = Introspector.getBeanInfo(classOfBean);
073
074 // If the bean doesn't know how to encode
// itself in XML,
075 // then create a DOM document by
// introspecting the bean and
076 // inserting nodes that represent the
// bean's properties.
077 if (dfResult == null) {
078 dfResult = doc.createDocumentFragment();
079 PropertyDescriptor[] pds = bi.getPropertyDescriptors();
080
081 // Add an Element indicating that this
// is a JavaBean.
082 // The element has a single attribute,
// which is that Element's class.
083 Element eBean = doc.createElement("JavaBean");
084 dfResult.appendChild(eBean);
085 eBean.setAttribute("CLASS", classOfBean.getName());
086 Element eProperties = doc.createElement("Properties");
087 eBean.appendChild(eProperties);
088
089 // For each property of the bean, get a
// DocumentFragment that
090 // represents the individual property.
// Append that DocumentFragment
091 // to the Properties element of the document
092 for (int i = 0; i < pds.length; i++) {
093 PropertyDescriptor pd = pds[i];
094 DocumentFragment df = getAsDOM(doc, bean, pd);
095 if (df != null) {
096 // Create a Property element and add to
// Properties element
097 Element eProperty =doc.createElement("Property");
098 eProperties.appendChild(eProperty);
099
100 // Create NAME attribute, add it to
//Property element,
101 // and set it to name of property
102 eProperty.setAttribute("NAME", pd.getName());
103
104 // Append the DocumentFragment to the
//Property element
105 // This "splices" the entire
// DOM representation of the
106 // Property into the tree at this point.
107 eProperty.appendChild(df);
108 }
109 }
110 }
111 return dfResult;
112 }
|
La versión bean de getAsDOM() codifica un JavaBean completo como un DocumentFragment DOM.
| Líneas | Descripción |
|---|---|
| 33-69 | getAsDOM() primero obtiene la clase del bean y determina si esa clase define un método personalizado que codifique el bean como un árbol DOM. Busca un método cuyo nombre sea getAsDOM, a menos que la clase defina un método String getDOMGetterName(), en cuyo caso este método busca un método con ese nombre. (Por favor, no confundamos el método que vamos aquí, XMLBeanWriter.getAsDOM(), y el método que la clase del bean define para codificarse como un árbol DOM.) Si se encuentra un método "getter" DOM, se le llama, y lo que devuelve es el valor de retorno de este bean. Esto permite que un programador de beans tome un completo control sobre cómo la clase del bean se representa como un árbol DOM (y, por lo tanto, como un documento XML). |
| 74-110 | Si el bean no sabe cómo codificarse a sí mismo como un árbol DOM, getAsDOM codifica el bean creando un Element que representa el bean, y añadiendo los subnodos que representan las propiedades del bean. La obtención de las propiedades del bean como árbol DOM implica la lectura de todas las propiedades del bean, la codificación de cada propiedad como un subárbol DOM (representado por un DocumentFragment), y luego la inserción del subárbol de la propiedad en la lista de propiedades del bean. La línea 72 obtiene el objeto BeanInfo para el JavaBean desde el Introspector, y la línea 79 obtiene la lista de PropertyDescriptors que describe las propiedades del bean. Las líneas 83 a 87 creean el nodo superior del árbol DOM resultante. Las líneas 92 a 110 pasan a través de los PropertyDescriptor del bean, creando un Element por cada propiedad, codificando la propiedad del JavaBean como un subárbol (llamando a la segunda forma de getAsDOM(), e insertando el nuevo Element en la sección <Properties> del árbol resultante. Cuando se hayan codificado y añadido todas las propiedades al árbol, el árbol resultante vuelve a llamador en la forma de un objeto DocumentFragment (línea 111). |
Esto es todo lo que hace la forma del bean getAsDOM(). La forma del getAsDOM() que codifica propiedades aparece en el listado 8:
113 /**
114 * Return a DOM DocumentFragment representing a
* property of a JavaBean
115 * @return org.w3c.dom.DocumentFragment
116 * @param doc The document to use as a factory for
117 * subelements of the tree.
118 * @param bean The object that is the value of
* the property.
119 * This object must be a JavaBean.
120 * @param pd A property descriptor describing
121 * the property of which the object is a value.
122 * @exception IllegalAccessException
123 * @exception InstantiationException
124 * @exception IntrospectionException
125 */
126 public static DocumentFragment getAsDOM(Document doc, Object bean,
PropertyDescriptor pd) throws IntrospectionException,
InstantiationException, IllegalAccessException {
127 Class classOfBean = bean.getClass();
128 Class classOfProperty = pd.getPropertyType();
129 DocumentFragment dfResult = null;
130 String sValueAsText = null;
131 Class[] paramsNone = {};
132 Object[] argsNone = {};
133
134 // If the property is "class," and
// the type is java.lang.class, then
135 // this is the class of the bean, which
// we've already encoded.
136 // So, in this special case, return null.
137 if (pd.getName().equals("class") && classOfProperty.equals(java.lang.Class.class)) {
138 return null;
139 }
140
141 // 0. If pd is an XML property descriptor, and
// we can call its
142 // getter method, do so and return. If the
// programmer
143 // specifies a DOM getter method, we return
// what it returns, no questions asked.
144 if (pd instanceof XMLPropertyDescriptor) {
145 Method getter;
146 if ((getter = ((XMLPropertyDescriptor) pd).getDOMReadMethod()) != null) {
147 try {
148 Class[] params = {org.w3c.dom.Document.class};
149 Object[] args = {doc};
150 dfResult = (DocumentFragment) (getter.invoke(bean, args));
151 } catch (Exception ee) {
152 ; // Ignore... couldn't get the method
153 }
154 return dfResult;
155 }
156 }
157
158 // 1. Try to represent the property as XML.
159 // This bean may know how to describe itself,
// or parts of
160 // itself, as XML. There are two possibilities:
161 // [a] The bean has a method called
// get<Propname>AsDOM()
162 // [b] The property class has a method called
// getAsDOM()
163 // We'll try both of these, and the first
// (if any) that
164 // works will be the DocumentFragment we want
// to return.
165 // If none of these are true, then we try to
// find the object's
166 // value as text
167
168 // [1a] Does the bean have a method called
// get<Propname>AsDOM()?
169 // Capitalize property name
170 StringBuffer sPropname = new StringBuffer(pd.getName());
171 char c = sPropname.charAt(0);
172 if (c >= 'a' && c <= 'z') {
173 c += 'A' - 'a';
174 }
175 sPropname.setCharAt(0, c);
176 String sXMLGetterName = "get" + sPropname + "AsDOM";
177
178 // If both of these methods succeed, then
// dfResult will be set
179 // to non-null; that is, the method existed
// and returned a
180 // DocumentFragment
181 try {
182 Class[] params = {org.w3c.dom.Document.class};
183 Method mXMLGetter = classOfBean.getMethod(sXMLGetterName, params);
184 Object[] args = {doc};
185 dfResult = (DocumentFragment) (mXMLGetter.invoke(bean, args));
186 } catch (Exception ee) {
187 ; // Ignore... couldn't get the method
188 }
189
190 // Hereafter, we're trying to create a
// representation of the property
191 // based somehow on the property's value.
192 // The very first thing we need to do is get
// the value of the
193 // property as an object. If we can't do that,
// we can get no
194 // representation of the property at all.
195 Object oPropertyValue = null;
196 try {
197 Method getter = pd.getReadMethod();
198 if (getter != null) {
199 oPropertyValue = getter.invoke(bean, argsNone);
200 }
201 } catch (InvocationTargetException ex) {
202 ; // Couldn't get value. Probably
// should be an error.
203 }
204
205 // [1b] If we don't have a DocumentFragment,
// the previous block failed.
206 // So, let's find out if the property's
// class has a method called
207 // getAsDOM() and, if it does, call that instead.
208 if (dfResult == null) {
209 try {
210 Class[] params = {org.w3c.dom.Document.class};
211 Method mXMLGetter = classOfProperty.getMethod("getAsDOM", params);
212 Object[] args = {doc};
213 dfResult = (DocumentFragment) (mXMLGetter.invoke(oPropertyValue, args));
214 } catch (Exception ee) {
215 ; // Ignorewho cares why it failed?
216 }
217 }
218
219
220 // 2. Try to represent the property as a String.
221 // See if this property's value
222 // is something we can represent as Text, or if
// it's something
223 // that must be represented as a JavaBean.
// Let's assume that this
224 // object can be represented as text if:
225 // [a] it has a PropertyEditor associated with
// it, because
226 // PropertyEditors always have setAsText() and
// getAsText()
227 // If it can't be represented as text, then
// we pass it to
228 // getAsDOM(Document, Object) and return
// the result.
229
230 if (dfResult == null) {
231
232 // [2a] Can we get either a custom or
// built-in property editor?
233 // If the PropertyDescriptor returns an
// editor class, we
234 // create an instance of it; otherwise,
// we ask the system for
235 // a default editor for that class.
236 Class pedClass = pd.getPropertyEditorClass();
237 PropertyEditor propEditor = null;
238 if (pedClass != null) {
239 propEditor = (PropertyEditor) (pedClass.newInstance());
240 } else {
241 propEditor = PropertyEditorManager.findEditor(classOfProperty);
242 }
243
244 // If the property editor's not null, pass
// the property's
245 // value to the PropertyEditor, and then ask
// the PropertyEditor
246 // for a text representation of the object.
247 if (propEditor != null) {
248 propEditor.setValue(oPropertyValue);
249 sValueAsText = propEditor.getAsText();
250 }
251
252 // If somewhere above we found a string value,
// then create
253 // a DocumentFragment to return, and append
// to it
254 // a Text element.
255 if (sValueAsText != null) {
256 dfResult = doc.createDocumentFragment();
257 Text textValue = doc.createTextNode(sValueAsText);
258 dfResult.appendChild(textValue);
259 }
260 }
261
262 // 3. Try to represent the property value as a
// JavaBean
263 // If we don't have a DocumentFragment yet, we'll
264 // have to introspect the value of the object, because
265 // it's apparently something that can't be
// represented
266 // as flat text. We'll assume it's a JavaBean.
267 // If it isn't... oh, well.
268 //
269 if (dfResult == null && oPropertyValue != null) {
270 dfResult = getAsDOM(doc, oPropertyValue);
271 }
272 return dfResult;
273 }
|
| Líneas | Descripción |
|---|---|
| 127-128 | El método primero obtiene la clase del bean, y la clase de la propiedad dentro del bean. |
| 137-139 | Algunas veces, el Class class muestra una lista de propiedades, en cuyo caso es ignorada. |
| 141-156 | Si el PropertyDescriptor también es un XMLPropertyDescriptor, usamos el método read del DOM indicado por el XMLPropertyDescriptor para codificar la propiedad como un árbol DOM. |
| 158-188 | Si la clase bean define un método llamado getPropertynameAsDOM(), se utiliza un método para recuperar la propiedad como un árbol DOM. |
| 190-203 | Desde la línea 190, la única forma en la que podemos obtener una representación DOM de una propiedad es obteniendo el valor de la propiedad, formatear ese valor como un String y embeber ese String dentro de un elemento <Property>. Las líneas 190 a 203 recuperan el valor de la propiedad llamando al método "getter" tradicional de la propiedad indicado por el PropertyDescriptor. |
| 205-217 | Si la clase property tiene un método llamando getAsDOM(), llamamos a ese método sobre el valor que acabamos de recuperar, y el resultado será la propiedad codificada como un árbol DOM. Observa que esto es diferente a pedirle a la clase bean que codifique la propiedad como un árbol DOM. |
| 220-260 | Si aún no hemos tenido éxito en la creacción de un DocumentFragment para devolverlo, entonces tenemos que crear el nodo <Property> e insertarlo dentro del valor de la propiedad codificado como un String. Utilizamos el PropertyEditor del tipo de la propiedad para realizar esta conversión. |
| 262-271 | Si todo esto falla, usamos la primera verisión de getAsDOM() para codificar la propiedad como un JavaBean. Observa que esto significa que las dos versiones de getAsDOM() son mutuamente recursivas. Al final de esta sección de código, el DocumentFragment resultante representa la propiedad devuelta al llamador. |
Otras Clases XMLBeansEstas clases en el paquete XMLBeans las usan los programadores que quieren añadir funcionalidades XMLBeans a sus clases.
Clase XMLSimpleBeanInfo
La clase
XMLSimpleBeanInfo
existe sólo para corregir un bug en la implementación que IBM hace de java.beans.SimpleBeanInfo
(que ha sucedido cuando lo usamos para desarrollar el código de esta página).
XMLSimpleBeanInfo podría concebirse para extenderse y reportar más información sobre un
XMLBean al paquete XMLBeans, pero hacer esto requiere el re-desarrollo (o al menos subclasificación) de
java.beans.Introspector, que podría ser un tópico demasiado largo para esta página.
Clase XMLPropertyDescriptor
La clase
XMLPropertyDescriptor,
es un descriptor de propiedad XML, extiende java.beans.PropertyDescriptor permitiendo al
programador especificar los métodos "setter" y "getter" DOM para cada propiedad: Al igual que con los objetos
PropertyDescriptor tradicionales, los métodos podrían especifcarse por su nombre, o como
objetos Method. XMLBeans busca los accesores DOM, y los
usa preferiblemente sobre los accesores tradicionales, proporcionando, por lo tanto, la personalización XMLBeans descrita
arriba. Esta clase probablemente podría haberse hecho más pequeña teniendo el introspector en la clase bean, buscando por
getAsDOM(), etc., en lugar de mantener la lógica en las clases
XMLBeanReader y XMLBeanWriter; pero de nuevo, esto
requeriría subclasificar Introspector.
Clase Util
La clase
Util contiene un
conjunto de clases sencillas para codificaciones sencillas. Ninguna es lo suficientemene complicada como para merecer
una explicación aquí.
Trabajo PosteriorXMLBeanReader y XMLBeanWriter son simplemente un punto de partida adicional para las posibilidades existentes de experimentación después de todo lo leído hasta aquí.
Como hemos mencionado en estas páginas, este paquete no maneja propiedades indexadas de una forma general, aunque las propiedades indexadas específicas se pueden soportar si las codificamos a mano, como demuestra el ejemplo de Grades.
Hay algunas cosas menores que necesitamos añadir a este paquete para poder hacerlo real. En particular, el paquete XMLBeans no codifica los caracteres (<, > y &) como debería. Cada vez que se crea un elemento Text los datos añadidos al elemento Text deberíamos primero reemplazar cada caracter de mayor que (>) con la secuencia >, cada caracter de menor que (<) con <, y cada caracter ampersand con &. Esta tradución también necesitamos hacerla a la inversa cuando leemos datos desde elementos Text. Estas codificaciones son requirimientos duros-y-rápidos de XML, y son la mayor debilidad de este paquete en su implementación actual.
Otra modificación necesaria (quizas menor) es un cambio en el código que maneja secciones CDATA, que son formas especiales de incluir grandes bloques de texto pre-formateado en un fichero XML. Las secciones CDATA deberían permitirse en cualquier lugar en el que se permita un elemento Text.
Una última forma para mejorar el paquete sería modificar el paquete XMLBeanWriter para crear ficheros XMLBeans usando el nuevo formato XMLBeans, en lugar de usar el viejo formato
Esta implementación de XML JavaBeans realmente se precipita un poco cuando intenta convertir un objeto a un String. La última cosa que el XMLBeanWriter debería hacer es comprobar si el objeto implements Serializable. Si lo hace, XMLBeanWriter podría serializar el objeto a un array de bytes, y luego codificar el array como un string BDC o base64. La operación inversa tendría que ser realizada mientras se lee el JavaBean desde XML.
| Leer comentarios (15) | |
| Escribir comentario | |
| Puntuación: |
|
| Votar | |
| Recomendar este tutorial | |
| Estadísticas |
Copyright © 1999-2007
Programación en castellano.
Todos los derechos reservados.
Formulario de Contacto -
Datos legales -
Publicidad
Hospedaje web y servidores dedicados linux por Ferca Network
red internet: musica mp3 | logos y melodias | hospedaje web linux | registro de dominios | servidores dedicados
más internet: comprar | recursos gratis | posicionamiento en buscadores | tienda virtual | gifs animados