BeanReader
BeanReader is a tool for quickly extracting Java objects from XML documents using annotations and XPath expressions to indicate where in the document to look for attributes and other objects. The most important parts of this API are the class BeanReader and the annotation-type MatchBean.
About the Creator
BeanReader was created by C. Dylan Shearer (i.e., me). If you would like to contact me about BeanReader, you can email me at dshearer2[[AT]]sourceforge.net or post to the forums.
How to Use BeanReader
BeanReader can extract instances of classes that conform to Sun’s JavaBeans specification. To use it, annotate the class whose instances you want to extract with the annotation-type MatchBean, and, as necessary, annotate the class with IDAttrib and IDREFAttrib and its methods with MatchSingularProperty and MatchPluralProperty. Then, at the place in your code where you want to extract instances from XML documents, create an instance of the class BeanReader, passing your class to the constructor, and then call the appropriate method.
An Example
For example, suppose we are writing a Java program that keeps track of cats in a kitty-kennel. Specifically, we are writing an expert-system that will help us assign rooms to cats so that they will tend to be given roommates with whom they are friends. We have defined a class called “Cat” with two attributes, “name” and “friends”. “name”, of course, is a single-valued String attribute. “friends” is a multi-valued attribute of type Cat.
Because we want to run our expert-system against a database that stores information about cats, our program needs to be able to unmarshal instances of class Cat from serialized data. Assume that this data is in the form of XML documents, and that these documents can contain either a single cat or a list of cats. For example, a document with just one cat (namely, Uzu) looks like this:
<?xml version="1.0" encoding="UTF-8"?> <cat xmlns="http://cat"> <name>Uzu</name> <coloring>Tortoise shell</coloring> <friends> <cat> <name>Snurd</name> <coloring>Russian blue</coloring> <friends> <cat> <name>Dylan</name> <coloring>Pink</coloring> </cat> </friends> </cat> <cat> <name>Makiko</name> <coloring>Pink</coloring> </cat> </friends> </cat>
Using BeanReader, we don’t have to write a custom XML parser or run a bunch of XPath expressions to create an instance of Cat from the data in this document. Instead, we add annotations to our (already existing) class Cat:
@MatchBean(path="cat | element()/cat", defaultNamespace="http://cat")
@IDAttrib(name="id")
@IDREFAttrib(name="ref")
public class Cat
{
// define instance vars
...
@MatchSingularProperty(path="name")
public String getName()
{ ... }
public void setName(String name)
{ ... }
@MatchPluralProperty(path="friends", type=Cat.class)
public Set<Cat> getFriends()
{ ... }
public void setFriends(Set<Cat> friends)
{ ... }
}
Now, we use BeanReader to unmarshal the cat:
// read the XML document into an InputSource org.xml.sax.InputSource xmlSource = ...; // create a BeanReader for class Cat and extract the cat from the document BeanReader<Cat> extractor = new BeanReader<Cat>(Cat.class); Cat cat = extractor.extract(xmlSource);
What about extracting a list of cats? A document with a list of cats looks like this:
<?xml version="1.0" encoding="UTF-8"?> <cats xmlns="http://cat"> <cat> <name>Uzu</name> <coloring>Tortoise shell</coloring> <friends> <cat ref="myst"/> <cat> <name>Makiko</name> <coloring>Pink</coloring> </cat> </friends> </cat> <cat> <name>Snurd</name> <coloring>Russian blue</coloring> <friends> <cat ref="dylan"/> </friends> </cat> <cat id="myst"> <name>Mystery</name> <coloring>Gray</coloring> <friends> <cat ref="dylan"/> </friends> </cat> <cat id="dylan"> <name>Dylan</name> <coloring>Pink</coloring> </cat> </cats>
To extract a list of instances, we need to tell BeanReader where in the document to find the element that contains all the elements representing these instances. For this example, we call method extractList and pass it an XPath expression, “cat”, that points to the document’s root element. We also pass a map of prefixes and namespaces that BeanReader will use to interpret this expression.
// read the XML document into an InputSource org.xml.sax.InputSource xmlSource = ...; // create a BeanReader for the class Cat BeanReader<Cat> extractor = new BeanReader<Cat>(Cat.class); // define the namespaces (just one, the default) to use to interpret the path we pass to the extractor Map<String, String> namespaces = new HashMap<String, String>(); namespaces.put(null, "http://cat"); // extract the list of cats ListcatList = extractor.extractList(xmlSource, "cats", namespaces);