users@jersey.java.net

[Jersey] Sample for URI<--->JAXB replacement on the fly

From: Markus Karg <markus.karg_at_gmx.net>
Date: Fri, 18 Mar 2011 20:38:58 +0100

Hello Jersey Community,

 

this week I had been asked to publish a sample on "replacing URI by a JAXB
element (and vice versa) on the fly". So here it is. If anybody likes to put
this on the Jersey WIKI, please feel free to do so, but would be nice to
keep my name and a link to my web site http://www.headcrashing.eu). The
below code shall be treated as published under the terms of LGPL v2. :-)

 

Problem Scenario: You're using JAXB (typically using JAX-RS) to transport
data. You don't want to contain all referenced information inside of the XML
body, but instead want to have referencing URIs in the body instead. So you
want to replace Java references by URIs at marshalling, and URIs by Java
references at unmarshalling.

 

Solution Stereotype: Provide a custom adapter for marshalling /
unmarshalling and mark the respective references to use these adapters
instead of default marshalling / unmarshalling.

 

Example:

 

The following code snippets are published under the terms of the LGPL v2.

 

/*

* Copyright C 2011 Markus KARG http://www.headcrashing.eu

*/

 

/**

* Demonstrates optional usage of adapter.<br>

* {_at_code referencedBanana} is replaced by {_at_code URI} using the below
adapter.

* {_at_code containedBanana} is contained as usual.

* <FruitBox
referencedBanana="http://host:port/root/bananas/The%20Second%20Banana">

* <ContainedBanana id="The First Banana"/>

* </FruitBox>

*/

@XmlRootElement @XmlAccessorType(FIELD) @Entity public class FruitBox {

    Banana containedBanana;

    @XmlJavaTypeAdapter(BananaReplacer) @XmlAttribute Banana
referencedBanana;

}

 

/**

* Sample entity, *optionally* replaced by {_at_code URI} and vice versa.

*/

@XmlRootElement @XmlAccessorType(FIELD) @Entity public class Banana {

    @XmlAttribute @Id int id;

}

 

/**

* Replaces references by URIs and vice versa.

*

 * @author Markus KARG (markus_at_headcrashing.eu)

*/

public class BananaReplacer extends XmlAdapter<URI, Banana> {

    /**

     * Replace {_at_code URI} by {_at_code Banana}.

     */

    @Override public BoundType unmarshal(URI uri) throws Exception {

        return uri == null ? null : JAXB.unmarshal(uri, Banana.class);

    }

 

    /**

     * Replace {_at_code Banana} by {_at_code URI}.

     */

    @Override public URI marshal(Banana banana) throws Exception {

        return banana == null ? null :
UriBuilder.from(BananaResource.class).path(BananaResource.class,
"get").build(banana.id);

    }

}

 

/**

* Allows {_at_code BananaAdapter} to resolve {_at_code URI} by downloading a
{_at_code Banana}.

*/

@Path("bananas") public class BananaResource {

    @GET @Path("{id}") public Banana get(@PathParam("id") String id) {

        return em.find(Banana.class, id);

    }

}

 

Hope that it might be useful for anybody. Would be nice if JAX-RS would
support this out-of-the-box some day (without the need to write an adapter).
Note, if you want to use the adapter on the client side, you will need to
know the service's absolute root URI as typically you don't have the JAX-RS
to look it up from that using UriBuilder.from(.).

 

Regards

Markus