BeanLDOM
BeanLDOM is a small Java package allowing a tree of Java Beans to be accessed via a DOM tree.
Aims and Assumptions
- Must be efficient (time and space) as performance is important in many applications of BeanLDOM.
- Simple self consistent mapping (avoid obscure mapping rules).
- Assume in many cases that the Bean tree will be accessed sparsely. ie many branches of the tree may never need to be translated. This also allows infinite trees (e.g. recursive) to be accessed.
- Should not try and produce a system capable of arbitrary mappings. Target applications are more concerned with having an efficient and simple mapping than a particular final XML schema.
- Presentation Objects will often be used to give the developer greater control over the information exposed. e.g. formatting certain fields, hiding/combining/splitting fields etc.
Mapping
The following example shows all the mapping rules. This article helped me feel better about the mapping I had already decided upon.
Constructing a tree of NameBean objects:
NameBean jane = new NameBean("Jane", "Smith"); NameBean john = new NameBean("John", "Smith"); NameBean daisy = new NameBean("Daisy", "Smith"); NameBean prince = new NameBean(null, "Prince"); NameBean[] children = {daisy, prince, null}; String[] aka = {"Janey", "", null}; jane.setChildren(children); jane.setPartner(john); jane.setAka(aka); john.setChildren(new NameBean[] {});
Creating a BeanLDOM document to translate the root bean jane:
// create a new document with root element named "root" DocumentImpl doc = new DocumentImpl("root"); // append a child element ("person") to the root element doc.appendObject("person", jane);
This all gives:
<root> <person firstName="Jane" lastName="Smith"> <aka> <entry>Janey</entry> <entry></entry> <null/> </aka> <partner firstName="John" lastName="Smith"> <children/> </partner> <children> <entry firstName="Daisy" lastName="Smith"/> <entry firstName="" lastName="Prince"/> <null/> </children> </person> </root>
Notes on mapping
- If root object is null / no root object is generated.
- Null attributes are mapped as empty strings. NB This implies that information is lost (null and "" translate to "") The problem is if attributes were removed when null it would mean all attribute values would have to be evaluated to check for null to work out full number of attributes. If this mapping is not acceptable one solution is to use presentation objects to provide an extra attribute or return a "magic" value when null (both are ugly solutions but best I can come up with).
- Empty array/list results in element with no children
- Null entries in arrays map to <null/>
- A field that returns a null Bean does not produce a child element for that field as it would if non null
- Fields of the following classes are treated as values suitable for translating as attributes: Integer.class, Integer.TYPE, Long.class, Long.TYPE, Float.class, Float.TYPE, Double.class, Double.TYPE, Boolean.class, Boolean.TYPE, Date.class, String.class, java.sql.Date.class, StringBuffer.class (Thanks to KB for pointing out the last two)
Requirements
- J2SDK 1.4 or higher (sorry I used assert)
- JUnit 3.7 or higher to run unit tests.
Known Problems and Limitations
- No handling of Collections. Seems like a good thing to add soon.
Im sure there are lots more but I cant think of them just now.
Related software
Some good software that does similar things (sorry if/when this gets out of date):
- Jaxen xpath over jdom/dom4j...
- jaxb - xml -> java from spec
- Maverick web publishing framework that includes a package that wraps Beans in a DOM tree.
- JATO language/imp to transform to/from xml