By edort on Dec 02, 2008
Java Architecture for XML Binding (JAXB) provides a fast and convenient way to bind between XML schemas and Java representations, making it easy for Java developers to incorporate XML data and processing functions in Java applications. As part of this process, JAXB provides methods for unmarshalling XML instance documents into Java content trees that represent the structure and content of XML source documents, and then marshalling Java content trees back into XML instance documents. JAXB also provides a way to generate XML schema from Java objects. You can learn more about JAXB in Chapter 17: Binding between XML Schema and Java Classes in the Java EE5 Tutorial.
In this tip, you'll learn several ways of customizing or extending the default behavior of JAXB.
A samples package accompanies the tip. The package includes two files,
schema.xsd that demonstrate some of the techniques covered in this tip. The tip also points to resources that
more fully cover the topic.
The tip is based on JAXB 2.0 or later. You can download a nightly build of JAXB from the JAXB Download page. This tip shows the use of JAXB from a command line. However, JAXB is also available with the NetBeans IDE.
Customizing Namespace Prefixes During Marshalling
Marshalling is the act of creating an XML document from a JAXB-derived Java object tree. When you marshall an XML document
using JAXB 1.0, a
Marshaller object, a JAXB object that controls the process of marshalling, provides namespace
declarations in the resulting XML document. The
Marshaller does this only when necessary, that is, only when the
declared namespace prefixes are used in a program. Sometimes the
Marshaller produces a lot of namespace declarations
that look redundant, for example:
JAXB 2.0 changes this behavior. If you use JAXB 2.0 (or later) to marshal an XML document, the
Marshaller declares all statically known namespace Uniform Resource Identifiers (URIs), that is, those
URIs that are used as element or attribute names in JAXB annotations. JAXB may also declare additional namespaces in the
middle of an XML document, for example when a qualified name (QName) that is used as an attribute or element value
requires a new namespace URI, or when a Document Object Model (DOM) node in a content tree requires a new namespace URI.
This behavior might produce an XML document that has a lot of namespace declarations with automatically-generated
namespace prefixes. The problem is that automatically-generated namespace prefixes such as ns1, ns2, and ns3,
are not user friendly -- they typically do not help people understand the marshalled XML.
Fortunately, JAXB 2.0 (or later) provides a service provider interface (SPI) named
com.sun.xml.bind.marshaller.NamespacePrefixMapper that you can use to specify more
helpful namespace prefixes for marshalling. You implement the SPI and pass it to the
The main methods in the
NamespacePrefixMapper class are shown in Table 1.
||Returns a list of namespace URIs that should be declared at the root element.|
||Returns a list of namespace URIs or namespace prefix-namespace URI pairs that should be declared at the root element.|
||Returns a list of namespace prefix-namespace URI pairs that represent namespace bindings available on ancestor elements (that need not be repeated by JAXB.)|
||Returns a namespace prefix-namespace URI pair that should be declared at the root element.|
The program in the JAXBSample.java file illustrates the use of these methods. The program marshalls the same
XML document three times, first without the use of a
NamespacePrefixMapper class and then with two different
Follow these steps to build and run the program:
- Compile the
- Compile the binding classes generated in the previous step:
javac -cp $JAXB_HOME/lib/jaxb-impl.jar:. a/\*.java
$JAXB_HOMEis the directory where you installed JAXB.
Compile and execute the
javac -cp $JAXB_HOME/lib/jaxb-impl.jar:. JAXBSample.java java -cp $JAXB_HOME/lib/jaxb-impl.jar:. JAXBSample
Here's what you should see as output:
JAXBSampleprogram marshalls the XML document the first time, it does it without using a
NamespacePrefixMapperclass. As a result, the
Marshallerautomatically generates a namespace prefix, in this case,
The second marshalling done by the
JAXBSample program uses a
getPreferredPrefix() method in the
PreferredMapper class returns
the preferred prefix, in this case,
mappedNamespacea to be declared at the root element of the marshalled
The third marshalling done by the
JAXBSample program uses a
getPreDeclaredNamespaceUris() method in the
returns a list of namespace URIs, in this case,
b, that should be declared at the root element.
The fourth marshalling done by the
JAXBSample program uses a
getContextualNamespaceDecls() method in the
returns a namespace prefix and namespace URI, in this case,
mappedNamespacea, that should be declared
at the root element.
There are other ways to customize the way namespaces are handled in JAXB. In particular there are various ways to remove unwanted namespace declarations in marshalled XML. You'll find most of these in the Metro and JAXB forum. Additional techniques are documented on web sites such as Digital Karate and java.net - jaxb users on Nabble.
Also expect enhancements to
NamespacePrefixMapper, such as allowing namespace rejection.
If you have a specific use case with or without a solution, or a suggestion for improvement to JAXB, please post it to the
Metro and JAXB forum. You can
also submit suggestions for enhancements to JAXB through the
Customizing Schema Translation
The xjc schema compiler, also called the binding compiler, is an important part of a JAXB implementation. The compiler binds a source XML schema to a set of schema-derived program elements. The binding is described by an XML-based binding language in a binding file. The binding compiler produces a set of packages containing Java source files and JAXB property files.
In most cases, the default bindings generated by the binding compiler are sufficient. However, there are cases where you might want to modify the default bindings. For example, you might want to provide more meaningful package names than are generated by default. You can modify the default bindings by using custom binding declarations which are passed to the JAXB binding compiler. You can make these binding declarations as inline annotations in a source XML schema or declare them in an external binding customizations file.
In addition, you can define binding customizations in different scopes (although not all binding customizations can be defined in each scope). The scopes are:
- Global: A binding customization defined in global scope is applicable to all schema elements in which this customization is defined
and all other schemas that are imported into the schema. You specify a binding declaration in global scope with the
- Schema. A binding customization defined in schema scope is only applicable to the schema in which the customization is defined.
You specify a binding declaration in schema scope with the
- Definition: A customization value in binding declarations of a type definition and global declaration has definition scope. A definition scope covers all schema elements that reference the type definition or the global declaration.
- Component: A customization value in a binding declaration has component scope if the customization value applies only to the schema element that was annotated with the binding declaration.
See Customizing JAXB Bindings in the Java EE5 Tutorial for a fuller description of these scopes.
Binding customizations are defined in the JAXB specification -- you can rely on these no matter which JAXB implementation your
application runs with. However, specific JAXB implementations may provide additional customizations. For example, the JAXB
Reference Implementation (RI) provides additional customizations that are not defined by the JAXB specification. You can learn about
these in Java Architecture for XML Binding
Vendor Customizations. Note that to use vendor-specific extensions you need to launch the xjc binding compiler with
Customizing Through XJC Plugins
Using an xjc plugin is yet another way of customizing the default behavior of the binding compiler. You can use an existing plugin,
such as the
XJC Fluent API Plugin, which enables the binding
compiler to chain methods, or the XJC Camelcase
Always Plugin, which enables the binding compiler to generate names in camel case. You can find a list of xjc plugins for
JAXB 2.0 on the JAXB2 Commons page. There are some plugins, such
as the episode plugin, that are part of the JAXB RI. You can find these plugins in the
directory in jaxb sources. Note that you first need to join the
jaxb sources project, this gives you CVS access to the JAXB RI 2.0 source code.
To use any of these plugins, specify the classpath for the plugin when you launch the xjc compiler:
If none of the existing xjc plugins suits your needs, consider writing your own. It's more difficult than using an existing plugin, but it can give you more flexibility. However, beware of vendor lockin. For instructions on how to write an xjc plugin see the blog Writing a plug-in for the JAXB RI is really easy. In short, here's what you need to do:
- Extend the
- Put a service file in the
- Package everything in a JAR file.
For more information on customizing JAXB see the following resources:
In addition, the sample applications in the
samples directory of the
binary download can be helpful,
as well as the Using JAXB
chapter in The Java Web Services Tutorial, and
Chapter 17: Binding between XML Schema and Java Classes
in the Java EE5 Tutorial.
About the Author
Martin Grebac is a staff engineer at Sun Microsystems and the JAXB implementation lead. He is involved in tool-related activities such as Metro plugins for the NetBeans IDE or Eclipse IDE, and runtime integration such as the integration of the Grails framework in GlassFish v2. Read his blog.