users@jaxb.java.net

Thoughts on JAXB 'pattern'

From: Damon Maria <damon_at_mahuika.co.nz>
Date: Fri, 27 Dec 2002 11:58:58 +1300

Gary Gregory's post in the "Using existing classes" thread got me thinking, so I
thought I'd post to the list my current pattern/methodology for using JAXB to
get some constructive criticism.

Note: I'm not putting this forward as an 'all-prupose' methodology for using
JAXB, it's simply a way of using JAXB that I have found useful for my current
projects. Also note I've only bothered with unmarshalling, I've had no need to
marshall back into XML yet.

My projects are base libraries that I'd like to be extended by third parties for
which I use XML as the configuration and JAXB as the 'parser'. What I'd like to
focus on in this post is how I use (or intend to use) XML and JAXB as a
configuration mechanisim that is *extendable*.

So far all my work has been in the early-access version of JAXB, I haven't
gotten around to converting across to XML schema and the new JAXB due to my
disappointment in what was 'missing' from the latest JAXB releases (explaination
further below). I'll try and explain this using XML schema and but please be
aware this is only from what I've read, I've no actual experience with XML
schema or the latest version of JAXB - just what I've read in the spec's.

I'll describe how I'd like this all to work, and then explain the current issues
I have afterwards.

Enough with the blabbering, on with the show...

Lets say that I have a library that wants to instantiate a list of objects that
are configured from XML. Now these objects must all implement a specified
interface (lets say Foo), but the actual concrete classes of the objects may not
be known to the library at compile time.

In my base schema (that the library is aware of and uses) I declare a
complexType that has whatever attributes/elements are common to Foo and an
attribute specifiing the name of the concrete class to use - lets call it
concreteClassName. For example:

<xsd:complexType name="fooConfigurationType" abstract="true">
   ...
   <xsd:attribute name="concreteClassName" type="xsd:string" />
</xsd:complexType>
<xsd:element name="foos">
   <xsd:sequence>
     <xsd:element name="foo" type="fooConfigurationType"
                  maxOccurs="unbounded" />
   </xsd:sequence>
</xsd:element>

For the configuration of the concrete classes of Foo I write a new schema that
imports the base schema and declares complexTypes that are extensions of
fooConfigurationType. Elements are then declared for these complexTypes that
have a substitutionGroup of fooConfigurationType. For example:

<xsd:complexType name="barConfigurationType">
   <xsd:complexContext>
     <xsd:extension base="base:fooConfigurationType">
       ...
     </xsd:extension>
   </xsd:complexContext>
</xsd:complexType>
<xsd:element name="barConfiguration" type="barConfigurationType"
              substitutionGroup="base:fooConfigurationType" />

The base schema and the schemas that imports it are compiled with XJC.

An example configuration would then be:

<base:foos>
   <concreteA:bar concreteClassName="com.company.application.Bar">
     ...
   </concrete:bar>
   <concreteB:smeg concreteClassName="com.company.other.Smeg" />
   ...
</base:foos>

When the library wants to instantiate the objects specified in an XML
configuration it uses JAXB to unmarshall the XML into the configuration objects.
The library then iterates over the list of configuration objects (concreteA:foo
and concreteB:smeg in the example above) and for each one...

1. FooConfigurationType configObj = (FooConfigurationType) iterator.next();
2. Class class = Class.forName( configObj.getConcreteClassName() );
3. Search class.getConstructors() for a Constructor that takes a single
parameter that is assignableFrom( configObj.getClass() ).
4. return (Foo) constructor.newInstance( new Object[] { configObj } );

So a concrete class would have a definition something like...

public class Bar implements Foo {
   public Bar( BarConfigurationType configuration ) { ... }
   ...
}

In summary, for a new extension concrete class you define its element definition
in a schema (derived from the base complexType) and implement a class that takes
the JAXB binding of that element in its constructor. Easy, simple, elegant,
strongly typed.

Depending on the library, I sometimes pass in other parmeters to the
constructor, but that is obviously trivial to do.

Sometimes I also find it useful to add another level to it by having 'builder'
classes that are specified in the XML attribute instead of the
concreteClassName. The concrete builder classes implement an interface that has
a method that builds the Foo classes. For exmaple:

public interface FooBuilder {
   Foo buildFoo();
}

So that concrete FooBuilders have a constructor that takes in the configuration
object and are instantiated by the reflection code given above (as concrete Foos
are in the example above). I can then ask any of the instantiated FooBuilders to
buildFoo() whenever I need a Foo from them.

The only other trick is in passing the base schema package and the extension
packages that import it in the one call to JAXBContext.newInstance(). This needs
to be figured out dynamically depending on what extension jars are in the
classpath. I'm currently thinking of doing this by packaging a text file in a
specific location in the jar of each extension (maybe even put it under
META-INF). This file lists the schema packages to include in the newInstance()
call. I can find all these files with ClassLoader.getResources().

I quite like how this works out, all the library code is statically typed
(excluding the reflection code shown above) and it is infinately extendable by
third parties with no changes required in the base library.

However (here it comes), with the current version of JAXB this is not possible
due to substitutionGroup's not being allowed. The type hierarchy is all there
from the schema but you can't use it *polymorphically* even though XML schema
and java both support it. Grrrrr. I have seen emails go through this list
regarding why this has been left for the next version of JAXB but I must admit I
was very disappointed. The only way I can see of getting around this is to drop
all substitutionGroups and specify in the base schema a xsd:choice of all the
concrete configuration elemnts. But this then totally breaks the extendability
of it all. I can see no other way around this. Can anyone else think of any
other tricks?

The only other issue I have has to do with XML schema. I would like to be able
to specify a default value for the *ClassName attribute in the derived types in
the XML schema. But I can only do this through xsd:restriction, which is damn
ugly if there is other content in the base type (it all has to be repeated
verbatim in the derived type). In most cases there is an obvious default to use
(in the example configuration XML given above I doubt the values given for
concreteClassName would ever differ for each element type). But I guess this is
something I can live with since it saves a heap of typing when it comes to
writting the configuration XML files.

Anyway, I hope that makes some sense to someone. Comments, thoughts and
suggestions?

regards,
Damon.