users@jaxb.java.net

Re: Complex references

From: Kohsuke Kawaguchi <Kohsuke.Kawaguchi_at_Sun.COM>
Date: Tue, 12 Jul 2005 10:01:45 -0700

Jeremy Haile wrote:
> Could I possibly make use of the XmlAdapter and @XmlJavaTypeAdapter
> mechanism to work around this problem? (solution #1) For example, the
> XmlAdapter could hand my AppleAdapter the string "myFruit". The
> AppleAdapter would know to retrieve the appropriate Apple object and
> return it.

Yes, that's the natural direction to go.

You first need to list up Apple objects that are unmarshalled. Today I
guess you do that by implementing ObjectLifeCycle interface by Apple
objects and use afterUnmarshalling hook to register itself to a Map.

class Apple implements ObjectLifeCycle {
   void afterUnmarshalling(Unmarshaller u,Object parent) {
     // register
     AppleAdapter.tls.get().put(this.id,this);
   }
}

class AppleAdapter extends XmlAdapter {
   // this map needs to be set to a new one every time you unmarshal.
   static ThreadLocal<Map<String,Apple>> tls = new ...;

   ...
}



> This isn't exactly ideal - in the example I gave previously the Apple
> object may not have been constructed by the time the XmlAdapter is
> invoked - therefore I would have to carefully load my objects in the
> appropriate order and there would still be limitations.

Right, there's a forward-reference problem. One way to work around this
is to resolve tokens to object lazily, perhaps like this:

interface Ref<T> {
   T resolve();
}

class AppleAdapter extends XmlAdapter {
   ...
   public Ref<Apple> unmarshal(final String s) {
     return new Ref<Apple>() {
       Map<String,Apple> map = tls.get();
       Apple resolve() {
         return map.get(s);
       }
     }
   }
}

So I guess it's possible today (except that it requires a lot of code.)

I think making this easier/shorter is the right direction to go.

> What would be ideal (solution #2) for my situation would be if JAXB
> basically kept a mapping from <class type, ID> to the object being
> constructed. Then if it was setting a property like setApple( Apple
> myApple ), it would know to only look in IDREF list under <Apple.class,
> "myFruit"> Of course, this doesn't exactly follow the ID/IDREF
> semantics, but other than the idea mentioned above I don't have many
> good ideas.

The problem with this is that it's too specific to your needs. It's not
general purpose enough.


> I guess another solution (solution #3) would be to build up an
> XML-specific tree and then convert that into a domain-specific tree.
> (as you mentioned) But this requires a separate processing layer in
> between the XML binding and application layer - a post-XML binding
> layer.

Right. You'd except a data-binding tool to do this.


-- 
Kohsuke Kawaguchi
Sun Microsystems                   kohsuke.kawaguchi_at_sun.com