Overview | Package | Class | Tree | Deprecated | Index | Help
| J avolution v5.2 (J2SE 1.5+)
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES

## Package javolution.xml

Provides support for the encoding of objects, and the objects reachable from them, into `XML`; and the complementary reconstruction of the object graph from `XML`.

See:
Description

Interface Summary
XMLSerializable | This interface identifies classes supporting XML serialization (XML serialization is still possible for classes not implementing this interface through dynamic `XMLBinding` though).

Class Summary
XMLBinding | This class represents the binding between Java classes and their XML representation (`XMLFormat`); the binding may be shared among multiple `XMLObjectReader`/ `XMLObjectWriter` instances (thread-safe).
XMLFormat<T> | This class represents the format base class for XML serialization and deserialization.
XMLFormat.InputElement | This class represents an input XML element (unmarshalling).
XMLFormat.OutputElement | This class represents an output XML element (marshalling).
XMLObjectReader | This class restores objects which have been serialized in XML format using an `XMLObjectWriter`.
XMLObjectWriter | This class takes an object and formats it to XML; the resulting XML can be deserialized using a `XMLObjectReader`.
XMLReferenceResolver | This class represents a resolver for XML cross references during the marshalling/unmarshalling process.

## Package javolution.xml Description

Provides support for the encoding of objects, and the objects reachable from them, into `XML`; and the complementary reconstruction of the object graph from `XML`.

## XML marshalling/unmarshalling facility:

Key Advantages:

- Real-time characteristics with no adverse effect on memory footprint or garbage collection (e.g. it can be used for time critical communications). `XMLFormat` is basically a "smart" wrapper around our real-time StAX-like `XMLStreamReader` and `XMLStreamWriter`.
- Works directly with your existing Java classes, no need to create new classes or customize your implementation in any way.
- The XML representation can be high level and impervious to obfuscation or changes to your implementation.
- Performance on a par or better than default JavaTM Serialization/Deserialization (See bindmark for performance comparison).
- Runs on any platform including J2ME CLDC 1.0 It does not require reflection or or any interface (e.g. `Serializable`) to be implemented.
- The XML mapping can be defined for a top class (or interface) and is automatically inherited by all sub-classes (or all implementing classes).
- Supports object references (to avoid expanding objects already formatted).

The default XML mapping for a class and its sub-classes is typically defined using a `static final` `XMLFormat` instance. For example:``

          public abstract class Graphic implements XMLSerializable {
              private boolean _isVisible;
              private Paint _paint; // null if none.
              private Stroke _stroke; // null if none.
              private Transform _transform; // null if none.

              // Default XML format with name associations (members identified by an unique name).
              // See XMLFormat for examples of positional associations.
              protected static final XMLFormat<Graphic> XML = new XMLFormat<Graphic>(Graphic.class) {
                   public void write(Graphic g, OutputElement xml) throws XMLStreamException {
                       xml.setAttribute("isVisible", g._isVisible);
                       xml.add(g._paint, "Paint");
                       xml.add(g._stroke, "Stroke");
                       xml.add(g._transform, "Transform");
                   }
                   public void read(InputElement xml, Graphic g) throws XMLStreamException {
                       g._isVisible = xml.getAttribute("isVisible", true);
                       g._paint = xml.get("Paint");
                       g._stroke = xml.get("Stroke");
                       g._transform = xml.get("Transform");
                  }
              };
          }

Sub-classes may override the inherited XML format:`

          public class Area extends Graphic {
              private Shape _geometry;

              // Adds geometry to format.
              protected static final XMLFormat<Area> XML = new XMLFormat<Area>(Area.class) {
                  public void write(Area area, OutputElement xml) throws XMLStreamException {
                      Graphic.XML.write(area, xml); // Calls parent write.
                      xml.add(area._geometry, "Geometry");
                  }
                  public void read(InputElement xml, Area area) throws XMLStreamException {
                      Graphic.XML.read(xml, area); // Calls parent read.
                      area._geometry = xml.get("Geometry");
                  }
              };
          }

` The following writes a graphic area to a file, then reads it:`

          // Creates some useful aliases for class names.
          XMLBinding binding = new XMLBinding();
          binding.setAlias(Color.class, "Color");
          binding.setAlias(Polygon.class, "Polygon");
          binding.setClassAttribute("type"); // Use "type" instead of "class" for class attribute.

          // Writes the area to a file.
          XMLObjectWriter writer = XMLObjectWriter.newInstance(new FileOutputStream("C:/area.xml"));
          writer.setBinding(binding); // Optional.
          writer.setIndentation("\t"); // Optional (use tabulation for indentation).
          writer.write(area, "Area", Area.class);
          writer.close();

          // Reads the area back
          XMLObjectReader reader = XMLObjectReader.newInstance(new FileInputStream("C:/area.xml"));
          reader.setBinding(binding);
          Area a = reader.read("Area", Area.class);
          reader.close();

` Here is an example of valid XML representation for an area:`

          <Area isVisible="true">
              <Paint type="Color" rgb="#F3EBC6" />
              <Geometry type="Polygon">
                  <Vertex x="123" y="-34" />
                  <Vertex x="-43" y="-34" />
                  <Vertex x="-12" y="123" />
              </Geometry>
          </Area>

`

The following table illustrates the variety of XML representations supported (Foo class with a single String member named text):

XML FORMAT | XML DATA
`
    XMLFormat<Foo> XML = new XMLFormat<Foo>(Foo.class) {
        public void write(Foo foo, OutputElement xml) throws XMLStreamException {
            xml.setAttribute("text", foo.text);
        }
        public void read(InputElement xml, Foo foo) throws XMLStreamException {
            foo.text = xml.getAttribute("text", "");
        }
    };
` |
     <!-- Member as attribute -->
     <Foo text="This is a text"/>
`
    XMLFormat<Foo> XML = new XMLFormat<Foo>(Foo.class) {
        public void write(Foo foo, OutputElement xml) throws XMLStreamException {
            xml.add(foo.text);
        }
        public void read(InputElement xml, Foo foo) throws XMLStreamException {
            foo.text = xml.getNext();
        }
    };
` |
     <!-- Member as anonymous nested element -->
     <Foo>
         <java.lang.String value="This is a text"/>
     </Foo>
`
    XMLFormat<Foo> XML = new XMLFormat<Foo>(Foo.class) {
        public void write(Foo foo, OutputElement xml) throws XMLStreamException {
            xml.addText(foo.text);
            // or xml.getStreamWriter().writeCDATA(foo.text) to use CDATA block.
        }
        public void read(InputElement xml, Foo foo) throws XMLStreamException {
            foo.text = xml.getText().toString(); // Content of a text-only element.
        }
    };
` |
     <!-- Member as Character Data -->
     <Foo>This is a text</Foo>
`
    XMLFormat<Foo> XML = new XMLFormat<Foo>(Foo.class) {
        public void write(Foo foo, OutputElement xml) throws XMLStreamException {
            xml.add(foo.text, "Text");
        }
        public void read(InputElement xml, Foo foo) throws XMLStreamException {
            foo.text = xml.get("Text");
        }
    };
` |
     <!-- Member as named element of unknown type  -->
     <Foo>
         <Text class="java.lang.String" value="This is a text"/>
     </Foo>
`
    XMLFormat<Foo> XML = new XMLFormat<Foo>(Foo.class) {
        public void write(Foo foo, OutputElement xml) throws XMLStreamException {
            xml.add(foo.text, "Text", String.class);
        }
        public void read(InputElement xml, Foo foo) throws XMLStreamException {
            foo.text = xml.get("Text", String.class);
        }
    };
` |
     <!-- Member as named element of actual type known -->
     <Foo>
         <Text value="This is a text"/>
     </Foo>

The `XMLFormat` does not have to use the class public no-arg constructor, instances can be created using factory methods, private constructors (with constructor parameters set from the XML element) or even retrieved from a collection (if the object is shared or unique). For example:``

            public final class Point implements XMLSerializable {
                // Default XMLFormat can be private as the class cannot be extended.
                static final XMLFormat<Point> XML = new XMLFormat<Point>(Point.class) {
                    public boolean isReferencable() {
                        return false; // Always manipulates by value.
                    }
                    public Point newInstance(Class<Point> cls, InputElement xml) throws XMLStreamException {
                        return Point.valueOf(xml.getAttribute("x", 0), xml.getAttribute("y", 0));
                    }
                    public void write(Point point, OutputElement xml) throws XMLStreamException {
                        xml.setAttribute("x", point._x);
                        xml.setAttribute("y", point._y);
                    }
                    public void read(InputElement xml, Point point) throws XMLStreamException {
                        // Do nothing immutable.
                    }
                };
                private int _x;
                private int _y;
                private Point() {}; // No-arg constructor not visible.
                public static Point valueOf(int x, int y) { ... }
            }

Document cross-references are supported, including circular references. Let's take for example:``

            public class Polygon implements Shape, XMLSerializable {
                private Point[] _vertices;
                static final XMLFormat<Polygon> XML = new XMLFormat<Polygon>(Polygon.class) {
                    public void write(Polygon polygon, OutputElement xml) throws XMLStreamException {
                        xml.setAttibutes("count", _vertices.length);
                        for (int i=0; i < _vertices.length; i++) {
                            xml.add(_vertices[i], "Vertex", Point.class);
                        }
                    }
                    public void read(InputElement xml, Polygon polygon) throws XMLStreamException {
                        int count = xml.getAttributes("count", 0);
                        polygon._vertices = new Point[count];
                        for (int i=0; i < count; i++) {
                            _vertices[i] = xml.get("Vertex", Point.class);
                        }
                    }
                };
            }
            Polygon[] polygons = new Polygon[] {p1, p2, p1};
            ...
            TextBuilder xml = TextBuilder.newInstance();
            AppendableWriter out = new AppendableWriter().setOutput(xml)
            XMLObjectWriter writer = XMLObjectWriter.newInstance(out);
            writer.setXMLReferenceResolver(new XMLReferenceResolver()); // Enables cross-references.
            writer.write(polygons, "Polygons", Polygon[].class);
            writer.close();
            System.out.println(xml);

Prints the following (noticed that the first polygon and last one are being shared).`

          <Polygons length="3">
              <Polygon id="0" count="3">
                  <Vertex x="123" y="-34" />
                  <Vertex x="-43" y="-34" />
                  <Vertex x="-12" y="123" />
              </Polygon>
              <Polygon id="1" count="3">
                  <Vertex x="-43" y="-34" />
                  <Vertex x="123" y="-34" />
                  <Vertex x="-12" y="123" />
              </Polygon>
              <Polygon ref="0"/>
          </Polygons>

` ALGORITHMS:

Our `XMLObjectReader`/`XMLObjectWriter` are in fact simple wrappers around our Javolution high-performance StAX-like `XMLStreamReader` and `XMLStreamWriter` classes. The logic of these wrappers is described below:

    Marshalling:

    Input: object, referenceResolver, binding
    Output: outputElement

    1. class = object.getClass()

    2. outputElement.getStreamWriter().writeStartElement(name/uri)

       The new element name/uri is:

          a - Specified by caller, e.g. add(object, name, uri, class)
              If the class is not specified e.g. add(object, name, uri) a class attribute is written.

          b - binding.getLocalName(class)/binding.getURI(class), e.g add(object)

    3. isReference = referenceResolver.writeReference(object, outputElement)

    4. if (!isReference) binding.getFormat(class).write(object, outputElement)

    5. outputElement.getStreamWriter().writeEndElement()

    6. end

    Unmarshalling:

    Input: inputElement, referenceResolver, binding
    Output: object

    1. object = referenceResolver.readReference(inputElement)

    2. if (object != null) Goto 8 // Found reference

    3. class is either:

        a - Specified by caller, e.g. get("name", class)

        b - binding.getClass(class attribute value)

        c - binding.getClass(element name, element uri)

    4. format = binding.getFormat(class)

    5. object = format.newInstance(class, inputElement)

    6. referenceResolver.createReference(object, inputElement) // Done before parsing to support circular references.

    7. format.read(inputElement, object)

    8. inputElement.getStreamReader().nextTag()

    9. end

Overview | Package | Class | Tree | Deprecated | Index | Help
| J avolution v5.2 (J2SE 1.5+)
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES

Copyright © 2005 - 2007 Javolution.