JAXB Continued: Generating Schema from Object Model

As I mentioned in the previous post, I like to start with my Java object model first and then bind the XML as required. There are obviously countless opinions on both sides of this argument. The two sides of the argument are contract-first and contract-last. As you can probably guess this refers to whether we define the XSD before we create the Java objects, or after we already have our object model coded up.

Spring WS makes the most convincing argument for contract-first design. In their reference documentation they defend their decision to only offer the contract-first option. They make some good points, and I agree, for very complex schemas it may be better to have a contract first so that both parties can have a way to validate their generated results. However, for a simpler model, as I’m going to show you, it’s very quick and painless to have JAXB generate a schema for you.

Let’s assume we’re using the same Prison schema:

@XmlRootElement
public class Prison
{
	private Cell cell;
	private Guard guard;

        ...
}

public class Cell
{
	private String id;
	private Inmate inmate;

        ...
}

public class Inmate
{
	private String name;
	private String id;
	private String sentence;
	private String description;
	private String history;

        ...
}

public class Guard
{
	private String name;
	private String assignment;

        ...
}

I’m going to re-iterate again that it is a very simple schema, but that’s not really the point of this post. Now comes the COOL part! We generate the schema from the code by writing a quick unit test:

public void testSchema() throws JAXBException, IOException
{
	// grab the context

	JAXBContext context = JAXBContext.newInstance( Prison.class );

	final List results = new ArrayList();

	// generate the schema

	context.generateSchema(
            // need to define a SchemaOutputResolver to store to

			new SchemaOutputResolver()
			{
				@Override
				public Result createOutput( String ns, String file )
						throws IOException
				{
                    // save the schema to the list

					DOMResult result = new DOMResult();
					result.setSystemId( file );
					results.add( result );
					return result;
				}
			} );

    // output schema via System.out

	DOMResult domResult = results.get( 0 );
	Document doc = (Document) domResult.getNode();
	OutputFormat format = new OutputFormat( doc );
	format.setIndenting( true );
	XMLSerializer serializer = new XMLSerializer( System.out, format );
	serializer.serialize( doc );
}

As you can see, there a couple of tricks to this – credit given to Amis blog. The first is that you’ll need to implement the SchemaOutputResolver interface, done here with an anonymous class that creates the DOMResult. The second is that you’ll need to output the result to System.out (and format it nicely of course!). Here is the generated result:

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="prison" type="prison"/>
    <xs:complexType name="prison">
        <xs:sequence>
            <xs:element minOccurs="0" name="cell" type="cell"/>
            <xs:element minOccurs="0" name="guard" type="guard"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="cell">
        <xs:sequence>
            <xs:element minOccurs="0" name="id" type="xs:string"/>
            <xs:element minOccurs="0" name="inmate" type="inmate"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="inmate">
        <xs:sequence>
            <xs:element minOccurs="0" name="description" type="xs:string"/>
            <xs:element minOccurs="0" name="history" type="xs:string"/>
            <xs:element minOccurs="0" name="id" type="xs:string"/>
            <xs:element minOccurs="0" name="name" type="xs:string"/>
            <xs:element minOccurs="0" name="sentence" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="guard">
        <xs:sequence>
            <xs:element minOccurs="0" name="assignment" type="xs:string"/>
            <xs:element minOccurs="0" name="name" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

Pretty cool, right? Now you have an XSD schema! Obviously, the schema generator can’t guess the constraints for each field just from the Java code, so you’ll need to still modify this XSD. However, this can save you some work and will give you a great starting point for your XSD.

I’d love to hear some more feedback on the contract-first vs. contract-last last debate, so leave a comment!