Chapter 17. JAXB Providers
RESTEasy includes support for marshalling and unmarshalling JAXB annotated classes. Multiple JAXB Providers are included with RESTEasy to address the subtle differences between classes generated by XJC and classes that are annotated with
@XmlRootElement
, or work with JAXBElement
classes directly.
When using the JAX-RS API in development, the provider to be invoked is selected transparently. This chapter describes the providers best-suited for a variety of configurations if you want to access the providers directly.
RESTEasy selects a JAXB Provider when a parameter type (return type) is an object annotated with JAXB annotations (for example,
@XmlRootEntity
or @XmlType
), or a JAXBElement
. The resource class (resource method) will be annotated with either @Consumes
or @Produces
, and contain one or more of the following values:
text/*+xml
application/*+xml
application/*+fastinfoset
application/*+json
RESTEasy selects different providers based on the return type used in the resource. This section decribes the workings of the selection process.
Classes annotated with
@XmlRootElement
are handled with the JAXBXmlRootElementProvider
. This provider handles basic marshalling and unmarshalling of custom JAXB entities.
Classes that are generated by XJC do not usually contain an
@XmlRootElement
annotation. To be marshalled, they must be wrapped in an instance of JAXBElement
. This usually involves invoking a method named ObjectFactory
on the class, which serves as the XmlRegistry
.
The
JAXBXmlTypeProvider
provider is selected when the class is annotated with an XmlType
annotation and not an XmlRootElement
annotation. The provider attempts to locate the XmlRegistry
for the target class. By default, a JAXB implementation creates a class called ObjectFactory
and is located in the same package as the target class. ObjectFactory
contains a create
method that takes the object instance as a parameter. For example, if the target type is called Contact
, then the ObjectFactory
class will have a method:
public JAXBElement createContact(Contact value) {..
If your resource works with the
JAXBElement
class directly, the RESTEasy runtime will select the JAXBElementProvider
. This provider examines the ParameterizedType
value of the JAXBElement
in order to select the appropriate JAXBContext
.
17.1. JAXB Decorators
RESTEasy's JAXB providers can decorate
Marshaller
and Unmarshaller
instances. Add an annotation that triggers the decoration Marshaller
or Unmarshaller
. The decorators can perform tasks such as setting Marshaller
or Unmarshaller
properties and setting up validation.
As an example, say you want to create an annotation that will trigger pretty-printing of an XML document. In raw JAXB, we would set a property on the
Marshaller
of Marshaller.JAXB_FORMATTED_OUTPUT
. Instead, let us write a Marshaller decorator.
First, define an annotation:
import org.jboss.resteasy.annotations.Decorator; @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Decorator(processor = PrettyProcessor.class, target = Marshaller.class) public @interface Pretty {}
For this to work, you must annotate the
@Pretty
annotation with a meta-annotation named @Decorator
. The target()
attribute must be the JAXB Marshaller
class. Next, we will write the processor()
attribute class.
import org.jboss.resteasy.core.interception.DecoratorProcessor; import org.jboss.resteasy.annotations.DecorateTypes; import javax.xml.bind.Marshaller; import javax.xml.bind.PropertyException; import javax.ws.rs.core.MediaType; import javax.ws.rs.Produces; import java.lang.annotation.Annotation; /** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */ @DecorateTypes({"text/*+xml", "application/*+xml"}) public class PrettyProcessor implements DecoratorProcessor<Marshaller, Pretty> { public Marshaller decorate(Marshaller target, Pretty annotation, Class type, Annotation[] annotations, MediaType mediaType) { target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); } }
The
processor
implementation must implement the DecoratorProcessor
interface, and should also be annotated with @DecorateTypes
. This annotation specifies the media types that the processor can work with.
Now that we have defined our annotation and our
Processor
, we can use it on our JAX-RS resource methods or JAXB types like so:
@GET @Pretty @Produces("application/xml") public SomeJAXBObject get() {...}
If this is confusing, check the RESTEasy source code for information about implementing
@XmlHeader
.