- Starting a project with Hyperjaxb3
- What was generated?
- Working with JAXB and JPA
- Generated database
- Customizing the generated mappings
This is a simple tutorial which is intended to help you get started with Hyperjaxb3. The tutorial illustrates how to carry out the following basic tasks:
- Start a Hyperjaxb3 project.
- Compile the XML schema and use Hyperjaxb3 to annotate the generated classes.
- Parse an XML sample and save the parsed object the relational database.
- Load object from the database and marshall it back to XML.
- Apply basic customizations - customize column names.
XML Schema Primer also provides a sample XML file:
Starting a project with Hyperjaxb3
After unzipping you will get the following directory structure:
Maven users will recognize the usual Maven project structure:
src/main/resources- main java code and resources.
src/test/resources- java code and resources used for testing.
- There is also an additional
src/test/samplesdirectory which will contain XML samples we will use for testing.
After this step you have a functional project. To build it just run:
You'll see a few log statements displayed by the build system and at the end there'll be a JAR generated in
target directory. Behind the curtains, the build system did a complex job of cleaning, generating and compiling the code, running the tests (roundtrip test in this case) and packaging the compile code, but what you finally get is a neat JAR artifact and a message that everything worked.
What was generated?
If you browse the
target/generated-sources/xjc directory, you'll find few generated
java files, for instance
PurchaseOrderType.java. Let's take a closer look into this file:
As you see, apart from the JAXB
@Xml... annotations, this class also contains
@ManyToOne and few other annotations generated by the Hyperjaxb3 plugin. These annotations turn this class into an entity which can be persisten with JPA. This entity is a part of the persistence unit defined by the
META-INF/persistence.xml descriptor in
As you may guess, this file was also generated by Hyperjaxb3.
To sum it up, what we got produced from the XJC schema compiler and Hyperjaxb3 plugin is:
- persistence unit description in
- a set of Java files containing both JAXB and JPA annotations.
This is may be not too much, but this is enough to:
- unmarshall objects from XML and marshall them back with JAXB;
- or to persist objects into the database and to load them back with JPA.
Next sections of this tutorial demonstrates these operations.
Working with JAXB and JPA
Unmarshalling, marshalling and validating with JAXB
This section illustrates basic JAXB operations: unmarshalling, marshalling and validating. Source code for the unit tests can be found here.
First of all, what we need to work with JAXB is an instance of JAXB context. This can be obtained by the
JAXBContext.newInstance(...) call with the context path. Context path is typically the package name of the generated classes (our schema-derived classes were generated into the
generated package hence
generated context path). We will also need an instance of the generated
ObjectFactory to help us creating objects (this surely optional):
Let's start with unmarshalling. To unmarshall, we'll need an
Unmarshalling itself is just one line of code:
Now just cast an check that unmarshalling really worked:
Marshalling is not more complex. First of all all, let's create a structure we want to marshal:
Then create a marshaller and use it to marshall the object into the desired target, for instance into a DOM result:
Finally, let's check we've got what we wanted:
po.xsd schema is place in
src/main/resources, it will be available as a resource in the runtime. For instance, we could use it to validate data during marshalling or unmarshalling. This section illustrates validation on marshalling.
Let's start by composing an invalid structure:
Next step is creating an instance of schema:
Now all you need to do to validate on marshal is to provide the created schema to the marshaller:
To receive notifications of validation events, register an appropriate event handler:
Since out structure is invalid, we may check that the the list of validation events is not empty:
Persisting objects with JPA
This section considers basic JPA operations: persisting an object into a relational database and retrieving it back. Source code for the unit tests can be found here.
In order to work with JPA we first need to create an entity manager factory. The easiest way to do this is to simply pass the name of persistence unit (see
META-INF/persistence.xml above) to the
However, this method assumes that your database connection is configured in the persistence unit itself. I usually do not recommend specifying any database-specific properties in
persistence.xml. ORM mappings should be generic, database properties are case-specific and therefore must be kept separately.
For this reason I usually define such specific properties in the resource
persistence.properties. This can be placed in
src/main/resources or in
src/test/resources depending on wether you use it to define your main database connection - or just something for testing. We're testing so our
persistence.properties will be placed in
Reading the additional
persistence.properties make the initialization of the entity manager factory slightly more complicated:
Properties contained in the
persistence.properties are database and JPA provider specific. For instance, basic project template is preconfigured for Hibernate and HSQLDB:
This configuration uses HSQLDB in standalone (in-process) mode. The database will be automatically created in the
target/test-database folder, there is no set-up database necessary.
Saving the object into the database
First let's create an object structure to test with:
To save out object into the database we'll need o get an entity manager from the factory:
After the object is saved, we can get the generated id:
Loading the object from the database
On the last step we've got the generated id of the object we saved. We'll need this id to retrieve out object back:
Combining JAXB and JPA
Now it comes to the core point of Hyperjaxb. Since our schema-derived classes are both JAXB-enabled (thanks to the JAXB schema compiler) and JPA-enabled (thanks to the Hyperjaxb3 plugin), there is not problem to go XML-objects-database or the other way round. Let's demonstrate it.
The complete unit test can be found here.
At this point you might be curious what does the generated database look like. Below is the DDL for the HSQL database schema:
As you can recognize, this database schema reflects our XML Schema precisely, including types and associations. For our
po.xml XML sample these table will contain the following data:
Customizing the generated mappings
In the previous sections you have seen how easy it is to implement an XML-persistence solution with Hyperjaxb3. It is indeed a very powerful tool, but now the question is if this power can be controlled. That is, if generated mappings can be customized.
Hyperjaxb3 is built with focus on customizations. When generating mappings, Hyperjaxb3 assumes certain reasonable default generation strategy so that mappings will work even if you don't customize a single thing. But if you do need to change the generated expression of a certain field, you usually can.
This section demonstrates few very simple customizations that will be applied to the purchase order schema: we will customize table and column names, length of one of the columns. We'll also mark one of the
partNum attribute of the
Items complex type as primary identifier.
There are two possibilities to customize your schema: place your customization elements directly in the schema in
xs:annotation/xs:appinfo elements or place them externally in binding files. We'll consider both possibilities.
Customizing in schema
In order to use Hyperjaxb3 customization elements in the schema you first need to declare customziation namespaces and to list the corresponding prefixes in the
jaxb:extensionBindingPrefixes attribute. You typically need
xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" namespaces, here's how it looks in the schema:
Now we're ready to customize.
When customizing elements, attributes or types directly in schema all you have to do is to add the customiziation elements in
xsd:annotation/xsd:appinfo. For instance, imagine we need long (up to 1024 characters) product names:
Customizing in external binding files
Another possibility is to define your customizations in external binding files. This is very handy if you can't modify the schema. To do this, create a
bindings.xjb file in the schema directory
Binding elements in the example above associate customization elements with XML Schema constructs using XPath expression. Consider, for example the following definition:
The inner binding associates the
hj:entity customization element with the
USAddress complex element of the
po.xsd schema (via the XPath
/xs:schema/xs:complexType[@name='USAddress']). This definition is equivalent to the following in-schema version:
The effect of customization
If you take a look at the database schema generated for this customized version of po example, you'll see that few tables and columns are changed:
For instance, note that
USADDRESS was renamed to
PRODUCTNAME has now a length of 1024.
Customizations shown here are really primitive, but Hyperjaxb3 is not limited to that. There is a whole lot more you can do with customizations. For example, you can swith between
@ManyToMany modes for associations, map your classes as
@Embeddable instead of
@Entity, choose inheritance strategies and so on.
There are also "global" customizations which can influence the default behavior of Hyperjaxb3. For instance, Hyperjaxb3 generates
join-column mappings for
one-to-many associations per default:
This causes a conflict with TopLink. In order to overcome this problem you can change the default
one-to-many join mapping strategy to
This tutorial gave the primary introduction for Hyperjaxb3. You have seen how to start a Hyperjaxb3 project, how to use JAXB and JPA APIs together and how to customize the generated mappings.
You can find the source code for this tutorial in SVN: