Requirements

Definitions

Attribute
An attribute of an element in an XML document. Note that attributes in Java objects are referred to as properties, since they can only be read and changed via getters and setters
Converter
A converter is a pair of methods, one of which takes a String and parses it into a primative or object and another method which takes a primative or object and creates a string representation.
Element
A node in an XML document.
Object
An instance of a Java class.
Property
A getter and a setter method which, respectively, reads and changes an underlying attribute in Java object.
Tag
A node in an XML document. Synonymous with Element.

Requirements

  1. Reading XML

  2. The framework will parse XML and create an object graph representing the elements and attributes found.

    1. Parse data from XML into a single root object.
      1. Properties in objects which are primatives or which are objects that map directly to primatives will be converted from a String to the appropriate property type and the setter for that property will be called.
      2. Properties in objects which have complex object types (rather than primatives or objects that map directly to primatives) will cause other objects to be created. Those objects are then passed to the setter method for that property.
      3. There will be no limit on how deep the object graph representing the XML can be.
    2. XML attributes are processed as if they where elements. For example, <User name="foo"/> is functionally the same as <User><name>foo</name></User>
    3. Objects are instantiated by an ObjectFactory class. The default implementation of the ObjectFactory tries to create an object instance by calling a static getInstance() method on the object before trying Class.forName().newInstance()
    4. If XML tags are duplicated at the same level in the XML, setters should be implemented such that they add to a collection. For example, if a Stock object contains float values representing price bids, the setter setBid(float bid) should actually add the float to a List of bids { bids.add(bid); }
    5. Elements/attributes in the XML file can automatically be matched with objects and properties.
      1. A 'setter' method can start either with the word 'set' or the word 'add'. Either setAttribute or addAttribute would be called by the framework when parsing XML and coming across an <attribute> tag.
      2. Names of elements and attributes are mapped directly to property setters in an object, with a direct match between element name and property being assumed. For example, <someText>foobar</someText> would mean that the setSomeText() method (or addSomeText()) would be called.
      3. A setter can use the name of an Object's immediate super class instead of the name of the object as part of the setter. For example, if you had a SalesLot object which contained a list of all vehicles for sale, and you had three types of vehicles, Car, Motorbike and Boat that extended a Vehicle class, the SalesLot could have a addVehicle() method and all <Car>, <Motorbike> and <Boat> objects would be added to the SalesLot instance through the addVehicle() method.
    6. Elements/attributes in the XML file can optionally be matched to objects/properties of any name using mappings.
      1. Objects can be mapped from an xml tag/attribute name to a Java ojbect name.
      2. Properties of an object can be mapped from a specific tag/attribute name to a given Java property name, for that specific object.
      3. Properties can also be mapped from a tag/attribute name to a specific Java name on a global basis, so that those properties in ALL Java objects will get renamed.
    7. Java classes in different packages but with the same name will be supported.
      1. Elements which represent classes can use the fully qualified classname as element names. For example, the tags <com.foo.Cheese> <com.bar.Cheese> in XML will create two different kinds of Cheese objects (from the packages com.foo and com.bar).
      2. Tag names differentiated by a different namespace can be individually associated with a specific class by mapping the namespaces to specific packages. One might have the namespace urn:foobar-com-user mapped to the package com.foobar.user and the namespace urn:foobar-com-consumer mapped to the package com.foobar.consumer so that you can differentiate User objects found in both packages.
    8. A Converter will parse the XML string data and convert it into a specific type of object.
      1. Converters are defined for a specific Java data type (long, java.lang.Interger, java.util.Date, etc).
      2. A converter can optionally be associated with a specific property of a specific object by specifying the Converter in the PropertyMap.
  3. Writing XML

  4. The framework will write an object and all it's (javabean-like) properties, including complex data types, to String of XML.

    1. Take a single root object and serialize it to a string of XML.
      1. Properties of the object which are primatives or which are objects that map directly to primatives will be serialized to a String and added to the XML.
      2. Properties of the object which are complex objects (rather than primatives or objects that map directly to primatives) will actually generate a sub-element in the XML. The properties of that complex object will then be serialized inside of the sub-element. For example, if you have an object called Student which has a property that is another object called Teacher, a Teacher node will be created inside the Student node in the resulting XML.
      3. There will be no limit on how deep the object graph of the root object will be. All complex objects will be traversed and their primative properties will be serialized to the XML.
    2. Properties which return a List will actually be written out as a series of XML tags with the same name, existing at the same level in the XML hierarchy. For instance, a list of float primatives which indicate bid prices for the getter getBid would be serialized like:
      <Stock><name>foo</name><bid>1.23</bid><bid>1.25</bid><bid>1.33</bid></Stock>
      1. Note, at the moment, you should name getters that return a List with a name that is singular, not plural (as in the getBid() example above). More specifically, the property name of the getter must match the property name of the setter.
    3. Java object and property names, by default, will become the tag names used in the XML. Property names are derrived from the 'getter' methods of the Java object.
      1. A 'getter' method can start with either the word 'get' or the word 'is'. Either getAttribute or isAttribute would be called by the framework when generating XML. A getter that starts with 'is' does not have to return a boolean, though by convension it should.
      2. If the getter method returns a primative or an object that maps directly to a primative, the property name portion of the getter name will become the XML tag (with the first letter converted to lower case). For example, float getBid() will use the tag <bid>. Integer getNumberOfMiles will use the tag <numberOfMiles>.
      3. If the getter method returns a complex object, it is the the class name of the complex object which is used as the tag name. Note, you must set the includePackageName flag in XmlWriter to true if you want the class' fully qualified classname to be used (otherwise the package name is omitted).
    4. By default, objects and their properties are written out to XML elements. It is possible to specify on a property by property basis that a given property should be output as an XML attribute, rather than as an element.
      1. The PropertyMap object has a writeAsAttribute boolean flag which controls whether that property is written as an attribute or as an element.
      2. By default the writeAsAttribute flag is false
      3. The writeAsAttribute flag can be controlled either programatically or through an XML configuration file (see Configuring the Framework below).
      4. The property to be written must have a converter defined for its type.
      5. The property cannot be a List or an array.
      6. The property cannot have a null value.
    5. Java object/property names can optionally be associated with arbitrary XML tag/attribute names.
      1. Objects can be mapped to any tag name desired on an object by object basis
      2. Properties of a specific object can be mapped to a specific tag name on a per property basis for a specific object
      3. Properties can also be mapped to specific tag name regardless of which object they are found in using a 'global' property mapping
    6. You can specify a namespace mapping for Java packages so that Objects with the same name in different packages can be properly unmarshalled from the XML later. A namespace mapping will define a namespace URI and a prefix to use in the XML tag names for a give package.
    7. A Converter will convert a value from a getter to XML string data.
      1. Converters are defined for a specific Java data type (long, java.lang.Interger, java.util.Date, etc).
      2. A converter can optionally be associated with a specific property of a specific object by specifying the Converter in the PropertyMap.
  5. Configuring the Framework

  6. The framework will configure itself with some basic, useful options to begin with, but can be overridden and/or extended.

    1. The framework can be configured programatically by manipulating the 'singleton' XmlIOConfig object or by creating an instance of XmlIOConfig before you create an XmlReader or XmlWriter object. For instance:
        XmlIOConfig config = XmlIOConfig.getInstance();
        config.addConverter(...);
        config.addNamespaceMap(...);
        XmlWriter writer = new XmlWriter(...);
        ...
      
    2. The framework can be configured using an XML file which will define converters, XML tag/Java object mappings, XML attribute/Java setter mappings, and namespace/package name mappings.
  7. Extending the Framework

  8. You can currently extend the framework by replacing existing converters or by adding your own.

    1. Converters are defined for specific fully qualified classnames. To create a converter for com.company.Foo, the converter's type would be "com.company.Foo".
    2. Each converter currently needs two methods, both of which must be in the same class.
      1. The method which takes a string and returns an instance of the given class should start with parse (ie, parseString()).
      2. The method which takes an object and returns a string representation should start with print (ie, printString()).