Search |
||
Pluggable ID/IDREF handling in JAXB 2.0Posted by kohsuke on August 15, 2005 at 4:44 PM PDT
ID/IDREF has been with XML since its very first day. It works nicely with databinding tools, because it's easy to do a type analysis with ID/IDREF In this regard, key/keyref in XML Schema is much worse --- in general it's not even possible to determine how a given key/keyref constraint maps to which field/method of an object. ID/IDREF is great, but it is sometimes too simple. For example, people often want to:
It's just so convenient if you can tell a databinding implementation to do those for you. That is what I implemented in the JAXB RI 2.0. In JAXB 2.0, every ID and IDREF fields are marked with @XmlID and @XmlIDREF annotations. For example, if you have a schema that describes a document like this: Then you can have the schema compiler produce the following Java code:
@XmlRootElement
class Apple { @XmlID String id; }
@XmlRootElement
class AppleRef { @XmlIDREF Object ref; }
@XmlRootElement
class Orange { @XmlID String id; }
@XmlRootElement
class OrangeRef { @XmlIDREF Object ref; }
class Box {
@XmlElementRef
List fruits;
}
Supporting Distinctive Symbol SpacesSuppose you want to define distinctive symbol spaces between apples and oranges. That is, you'd want to allow XML documents like this: Where orangeRefs would only refer to oranges and appleRefs would only refer to apples. (Note that this document no longer validates with the original schema.) First, you'd have to modify the above classes to make it clear that AppleRef only refers to Apple:
@XmlRootElement
class AppleRef { @XmlIDREF Apple ref; }
@XmlRootElement
class OrangeRef { @XmlIDREF Orange ref; }
You can then implement a custom IDResolver, like this:
and then set this to the Unmarshaller like this:
Unmarshaller u = context.createUnmarshaller();
u.setProperty(IDResolver.class.getName(),new MyIDResolver());
u.unmarshal(new File("document.xml"));
The JAXB RI unmarshaller will delegate all its ID/IDREF works to MyIDResolver. You can see that it's allowing the same ID for apples and oranges. The change we made ealier to AppleRef and OrangeRef allows the JAXB RI to call the resolve method with the right target type. The Callable is used to support forward references. Supporting Scoped Symbol SpacesLet's extend this example so that we can handle documents like this: ... where references are only allowed within the same box. This can be done by combining IDResolver with a recent addition to the JAXB 2.0 spec, Unmarshaller.Listener.
When registered, a Listener gets notified for each object being unmarshalled. So the idea here is that every time the unmarshalling of a new Box object starts, we create a fresh symbol space. This guarantees that the resolve method always resolve within the same box. Note that we can't do Map.clear because that will cause the forward reference of orangeRef to fail (JAXB RI only process forward references at the very end of the document.) You can then set up the unmarshaller like this:
Unmarshaller u = context.createUnmarshaller();
MyIDResolver resolver = new MyIDResolver();
u.setProperty(IDResolver.class.getName(),resolver);
u.setListener(resolver.createListener());
u.unmarshal(new File("document.xml"));
ConclusionBy combining IDResolver and Unmarshaller.Listener, you can do much sophisticated reference integrity processing in the JAXB RI. For more details about the interfaces, see this. You can build the JAXB RI by yourself today, or wait for next Monday's weekly build to play with this. So Jeremy, I hope you like it, and sorry it took me a month to do this! »
Related Topics >>
Java Web Services and XML Comments
Comments are listed in date ascending order (oldest first)
|
||
|
|