[[_built_in_xml_bind_providers]]
== {xml-binding} providers

CAUTION: In {spec-name} 4.0 the {xml-binding} support was removed from specification. RESTEasy still plans on supporting
{xml-binding} for the time being. This may not be supported in a future release. Please plan on migrating to
<<_json_p,JSON>> or some other supported data type.

As required by the specification, RESTEasy includes support for (un)marshalling {xml-binding} annotated classes.
RESTEasy provides multiple providers to address some subtle differences between classes generated by XJC and classes which are simply annotated with @XmlRootElement, or working with JAXBElement classes directly.

For the most part, developers using the {spec-name} API, the selection of which provider is invoked will be completely transparent.
For developers wishing to access the providers directly (which most folks won't need to do), this document describes which provider is best suited for different configurations.

A {xml-binding} Provider is selected by RESTEasy when a parameter or return type is an object that is annotated with annotations {xml-binding} (such as `@XmlRootEntity` or `@XmlType`) or if the type is a JAXBElement.
Additionally, the resource class or resource method will be annotated with either a `@Consumes` or `@Produces` annotation and contain one or more of the following values:

* text/*+xml
* application/*+xml
* application/*+fastinfoset
* application/*+json

RESTEasy will select a different provider based on the return type or parameter type used in the resource.
This section describes how the selection process works.

`@XmlRootEntity` When a class is annotated with a `@XmlRootElement` annotation, RESTEasy will select the
`JAXBXmlRootElementProvider`.
This provider handles basic marshaling and unmarshalling of custom {xml-binding} entities.

`@XmlType` Classes which have been generated by XJC will most likely not contain an `@XmlRootEntity` annotation.
In order for these classes to marshalled, they must be wrapped within a `JAXBElement` instance.
This is typically accomplished by invoking a method on the class which serves as the `XmlRegistry` and is named `ObjectFactory`.

The `JAXBXmlTypeProvider` provider is selected when the class is annotated with an `XmlType` annotation and not an
`XmlRootElement` annotation.

This provider simplifies this task by attempting to locate the `XmlRegistry` for the target class.
By default, a {xml-binding} implementation will create a class called `ObjectFactory` and is located in the same package as the target class.
When this class is located, it will contain 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:

[source,java]
----
public JAXBElement<?> createContact(Contact value);
----

`JAXBElement<?>` 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`.

[[_decorators]]
=== {xml-binding} Decorators

Resteasy's {xml-binding} providers have a pluggable way to decorate Marshaller and Unmarshaller instances.
The way it works is that you can write an annotation that can trigger the decoration of a Marshaller or Unmarshaller.
Your decorators can do things like set Marshaller or Unmarshaller properties, set up validation, and the like.
Here's an example.
Say we want to have an annotation that will trigger pretty-printing, nice formatting, of an XML document.
If we were using raw {xml-binding}, we would set a property on the Marshaller of Marshaller.JAXB_FORMATTED_OUTPUT.
Let's write a Marshaller decorator.

First define an annotation:

[source,java]
----
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, we must annotate the `@Pretty` annotation with a meta-annotation called @Decorator.
The `target()` attribute must be the {xml-binding} Marshaller class.
The `processor()` attribute is a class we will write next.

[source,java]
----
import org.jboss.resteasy.core.interception.DecoratorProcessor;
import org.jboss.resteasy.annotations.DecorateTypes;

import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.PropertyException;
import jakarta.ws.rs.core.MediaType;
import jakarta.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 what media types the processor can be used with.
Now that we've defined our annotation and our Processor, we can use it on our {spec-name} resource methods or {xml-binding} types as follows:

[source,java]
----
@GET
@Pretty
@Produces("application/xml")
public SomeJAXBObject get() {}
----

Check the RESTEasy source code for the implementation of @XmlHeader for more detailed information

[[_pluggable_xml_bind_context_s_with_contextresolvers]]
=== Pluggable JAXBContext's with ContextResolvers

Do not use this feature unless you are knowledgeable about using it.

Based on the class being marshalling/unmarshalling, RESTEasy will, by default create and cache JAXBContext instances per class type.
If you do not want RESTEasy to create JAXBContexts, plug in your own by implementing an instance of `jakarta.ws.rs.ext.ContextResolver`

[source,java]
----
public interface ContextResolver<T> {
    T getContext(Class<?> type);
}

@Provider
@Produces("application/xml")
public class MyJAXBContextResolver implements ContextResolver<JAXBContext> {
    JAXBContext getContext(Class<?> type) {
        if (type.equals(WhateverClassIsOverridedFor.class)) return JAXBContext.newInstance();
        return null;
    }
}
----

A `@Produces` annotation must be provided to specify the media type the context is meant for.
An implementation of `ContextResolver<JAXBContext>` must be provided and that class must have the `@Provider` annotation.
This helps the runtime match to the correct context resolver.

There are multiple ways to make this ContextResolver available.

. Return it as a class or instance from a jakarta.ws.rs.core.Application implementation
. List it as a provider with resteasy.providers
. Let RESTEasy automatically scan for it within the WAR file. See Configuration Guide
. Manually add it via `ResteasyProviderFactory.getInstance().registerProvider(Class)` or `registerProviderInstance(Object)`

=== {xml-binding} + XML provider

RESTEasy is required to provide {xml-binding} provider support for XML.
It has a few extra annotations that can help code the application.

[[_xmlheader]]
==== @XmlHeader and @Stylesheet

Sometimes when outputting XML documents you may want to set an XML header.
RESTEasy provides the `@org.jboss.resteasy.annotations.providers.jaxb.XmlHeader` annotation for this.
For example:

[source,java]
----
@XmlRootElement
public static class Thing {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Path("/test")
public static class TestService {
    @GET
    @Path("/header")
    @Produces("application/xml")
    @XmlHeader("<?xml-stylesheet type='text/xsl' href='${baseuri}foo.xsl' ?>")
    public Thing get() {
        Thing thing = new Thing();
        thing.setName("bill");
        return thing;
    }
}
----

The `@XmlHeader` forces the XML output to have a xml-stylesheet header.
This header could also have been put on the Thing class to get the same result.
See the javadocs for more details on how to use substitution values provided by resteasy.

RESTEasy also has a convenience annotation for stylesheet headers.
For example:

[source,java]
----
@XmlRootElement
public static class Thing {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Path("/test")
public static class TestService {
    @GET
    @Path("/stylesheet")
    @Produces("application/xml")
    @Stylesheet(type="text/css", href="${basepath}foo.xsl")
    @Junk
    public Thing getStyle() {
        Thing thing = new Thing();
        thing.setName("bill");
        return thing;
    }
}
----

=== {xml-binding} + JSON provider

RESTEasy supports the marshalling of {xml-binding} annotated POJOs to and from JSON.
This provider wraps the Jackson2 library to accomplish this.

To use this integration with Jackson import the resteasy-jackson2-provider Maven module.

For example, consider this {xml-binding} class:

[source,java]
----
@XmlRootElement(name = "book")
public class Book {
    private String author;
    private String ISBN;
    private String title;

    public Book() {
    }

    public Book(String author, String ISBN, String title) {
        this.author = author;
        this.ISBN = ISBN;
        this.title = title;
    }

    @XmlElement
    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
    this.author = author;
    }

    @XmlElement
    public String getISBN() {
        return ISBN;
    }

    public void setISBN(String ISBN) {
        this.ISBN = ISBN;
    }

    @XmlAttribute
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
----

And we can write a method to use the above entity:

[source,java]
----
@Path("/test_json")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Book test_json() {
    Book book = new Book();
    book.setTitle("EJB 3.0");
    book.setAuthor("Bill Burke");
    book.setISBN("596529260");
    return book;
}
----

When making a requesting of the above method, the default Jackson2 marshaller would return JSON output that looked like this:

[source]
----
$ http localhost:8080/dummy/test_json
HTTP/1.1 200
...
Content-Type: application/json

{
"ISBN": "596529260",
"author": "Bill Burke",
"title": "EJB 3.0"
}
----

=== {xml-binding} + FastinfoSet provider

RESTEasy supports the FastinfoSet mime type with {xml-binding} annotated classes.
Fast infoset documents are faster to serialize and parse, and smaller in size, than logically equivalent XML documents.
Thus, fast infoset documents may be used whenever the size and processing time of XML documents is an issue.
It is configured the same way the provider is.

To use this integration with Fastinfoset import the resteasy-fastinfoset-provider Maven module.

[[_xml_bind_api_collections]]
=== Arrays and Collections of {xml-binding} Objects

RESTEasy will automatically marshal arrays, java.util.Set's, and java.util.List's of {xml-binding} objects to and from XML, JSON, Fastinfoset.

[source,java]
----
@XmlRootElement(name = "customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
    @XmlElement
    private String name;

    public Customer() {
    }

    public Customer(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

@Path("/")
public class MyResource {
    @PUT
    @Path("array")
    @Consumes("application/xml")
    public void putCustomers(Customer[] customers) {
        Assertions.assertEquals("bill", customers[0].getName());
        Assertions.assertEquals("monica", customers[1].getName());
    }

    @GET
    @Path("set")
    @Produces("application/xml")
    public Set<Customer> getCustomerSet() {
        return Set.of(new Customer("bill"), new Customer("monica"));
    }

    @PUT
    @Path("list")
    @Consumes("application/xml")
    public void putCustomers(List<Customer> customers) {
        Assertions.assertEquals("bill", customers.get(0).getName());
        Assertions.assertEquals("monica", customers.get(1).getName());
    }
}
----

The above resource can publish and receive {xml-binding} objects.
It is assumed they are wrapped in a collection element

[source,xml]
----
<collection>
    <customer><name>bill</name></customer>
    <customer><name>monica</name></customer>
<collection>
----

The namespace URI, namespace tag, and collection element name can be changed by using the
`@org.jboss.resteasy.annotations.providers.jaxb.Wrapped` annotation on a parameter or method

[source,java]
----
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Wrapped {
    String element() default "collection";

    String namespace() default "http://jboss.org/resteasy";

    String prefix() default "resteasy";
}
----

To output this XML

[source,xml]
----
<foo:list xmlns:foo="https://jboss.org">
    <customer><name>bill</name></customer>
    <customer><name>monica</name></customer>
</foo:list>
----

The `@Wrapped` annotation would be used as follows:

[source,java]
----
@GET
@Path("list")
@Produces("application/xml")
@Wrapped(element="list", namespace="https://jboss.org", prefix="foo")
public List<Customer> getCustomerSet() {
    return List.of(new Customer("bill"), new Customer("monica"));
}
----

[[_collections_on_client]]
==== Retrieving Collections on the client side

To retrieve a `List` or `Set` of {xml-binding} objects on the client side, the element type returned in the List or Set must be identified.
Below the call to `readEntity()` will fail because the class type, Customer has not been properly identified:

[source,java]
----
Response response = request.get();
List<Customer> list = response.readEntity(List.class);
----

Use `jakarta.ws.rs.core.GenericType` to declare the data type,`Customer`, returned within the List.

[source,java]
----
Response response = request.get();
GenericType<List<Customer>> genericType = new GenericType<>() {};
List<Customer> list = response.readEntity(genericType);
----

For more information about `GenericType`, please see its javadoc.

The same strategy applies to retrieving a `Set`:

[source,java]
----
Response response = request.get();
GenericType<Set<Customer>> genericType = new GenericType<>() {};
Set<Customer> set = response.readEntity(genericType);
----

`GenericType` is not necessary to retrieve an array of {xml-binding} objects:

[source,java]
----
Response response = request.get();
Customer[] array = response.readEntity(Customer[].class);
----

[[_json_list]]
==== JSON and {xml-binding} Collections/arrays

RESTEasy supports using collections with JSON.
It encloses List, Set, or arrays of returned XML objects within a simple JSON array.
For example:

[source,java]
----
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Foo {
    @XmlAttribute
    private String test;

    public Foo() {
    }

    public Foo(String test) {
        this.test = test;
    }

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }
}
----

A List or array of Foo class would be represented in JSON like this:

[source,json]
----
[{"foo":{"@test":"bill"}},{"foo":{"@test":"monica}"}}]
----

It also expects this format for input

[[_xml_map]]
=== Maps of XML Objects

RESTEasy automatically marshals maps of {xml-binding} objects to and from XML, JSON, Fastinfoset (or any other new {xml-binding} mapper).
The parameter or method return type must be a generic with a String as the key and the {xml-binding} object's type.

[source,java]
----
@XmlRootElement(namespace = "http://foo.com")
public static class Foo {
    @XmlAttribute
    private String name;

    public Foo() {
    }

    public Foo(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

@Path("/map")
public static class MyResource {
    @POST
    @Produces("application/xml")
    @Consumes("application/xml")
    public Map<String, Foo> post(Map<String, Foo> map) {
        Assertions.assertEquals(2, map.size());
        Assertions.assertNotNull(map.get("bill"));
        Assertions.assertNotNull(map.get("monica"));
        Assertions.assertEquals(map.get("bill").getName(), "bill");
        Assertions.assertEquals(map.get("monica").getName(), "monica");
        return map;
    }
}
----

The above resource can publish and receive XML objects within a map.
By default, they are wrapped in a "map" element in the default namespace.
Also, each "map" element has zero or more "entry" elements with a "key" attribute.

[source,xml]
----
<map>
    <entry key="bill" xmlns="http://foo.com">
        <foo name="bill"/>
    </entry>
    <entry key="monica" xmlns="http://foo.com">
        <foo name="monica"/>
    </entry>
</map>
----

The namespace URI, namespace prefix and map, entry, and key element and attribute names can be changed by using the
`@org.jboss.resteasy.annotations.providers.jaxb.WrappedMap` annotation on a parameter or method

[source,java]
----
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WrappedMap {
    /**
     * map element name
     */
    String map() default "map";

    /**
     * entry element name *
     */
    String entry() default "entry";

    /**
     * entry's key attribute name
     */
    String key() default "key";

    String namespace() default "";

    String prefix() default "";
}
----

To output this XML

[source,xml]
----
<hashmap>
    <hashentry hashkey="bill" xmlns:foo="http://foo.com">
        <foo:foo name="bill"/>
    </hashentry>
</map>
----

Use the `@WrappedMap` annotation as follows:

[source,java]
----
@Path("/map")
public static class MyResource {
    @GET
    @Produces("application/xml")
    @WrappedMap(map="hashmap", entry="hashentry", key="hashkey")
    public Map<String, Foo> get() {
        return Map.of("bill", new Foo("bill"));
    }
}
----

[[_maps_client_side]]
==== Retrieving Maps on the client side

To retrieve a `Map` of XML objects on the client side, the element types returned in the Map must be identified.
Below the call to `readEntity()` will fail because the class types, String and Customer have not been properly identified:

[source,java]
----
Response response = request.get();
Map<String, Customer> map = response.readEntity(Map.class);
----

Use `jakarta.ws.rs.core.GenericType` to declare the data types, `String` and `Customer`, returned within the Map.

[source,java]
----
Response response = request.get();
GenericType<Map<String, Customer> genericType = new GenericType<>() {};
Map<String, Customer> map = response.readEntity(genericType);
----

For more information about `GenericType`, please see its javadoc.

[[_json_map]]
==== JSON and XML maps

RESTEasy supports using maps with JSON.
It encloses maps returned XML objects within a simple JSON map.
For example:

[source,java]
----
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Foo {
    @XmlAttribute
    private String test;

    public Foo() {
    }

    public Foo(String test) {
        this.test = test;
    }

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }
}
----

A List or array of this Foo class would be represented in JSON like this:

[source,json]
----
{ "entry1" : {"foo":{"@test":"bill"}}, "entry2" : {"foo":{"@test":"monica}"}}}
----

It also expects this format for input

[[_xml_bind_interfaces]]
=== Interfaces, Abstract Classes, and {xml-binding}

Some objects models use abstract classes and interfaces heavily.
Unfortunately, {xml-binding} doesn't work with interfaces that are root elements and RESTEasy can't unmarshal parameters that are interfaces or raw abstract classes because it doesn't have enough information to create a JAXBContext.
For example:

[source,java]
----
public interface IFoo {}

@XmlRootElement
public class RealFoo implements IFoo {}

@Path("/xml")
public class MyResource {

    @PUT
    @Consumes("application/xml")
    public void put(IFoo foo) {}
}
----

In this example, RESTEasy will report error, "Cannot find a MessageBodyReader for...".
This is because RESTEasy does not know that implementations of IFoo are  {xml-binding} classes and doesn't know how to create a JAXBContext for it.
As a workaround, RESTEasy allows the use of {xml-binding} annotation @XmlSeeAlso on the interface to correct the problem.
(NOTE, this will not work with manual, hand-coded ).

[source,java]
----
@XmlSeeAlso(RealFoo.class)
public interface IFoo {}
----

The extra @XmlSeeAlso on IFoo allows RESTEasy to create a JAXBContext that knows how to unmarshal RealFoo instances.

=== Configuring {xml-binding} Marshalling

As a consumer of XML datasets, {xml-binding} is subject to a form of attack known as the XXE (Xml eXternal Entity) Attack (https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing), in which expanding an external entity causes an unsafe file to be loaded.
Preventing the expansion of external entities is discussed in <<_configuring_document_marshalling>>.
The same parameter, `resteasy.document.expand.entity.references`

applies to {xml-binding} unmarshallers.

<<_configuring_document_marshalling>> also discusses the prohibition of DTDs and the imposition of limits on entity expansion and the number of attributes per element.
The parameters `resteasy.document.secure.disableDTDs` and `resteasy.document.secure.processing.feature` discussed there,
and their default values, also apply to the representation of {xml-binding} objects.