users@jersey.java.net

Re: Collection serialization in RESTful service

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 23 Oct 2007 11:31:49 +0200

Hi Florian, James,

This is a tricky problem [*].

Some possible solutions:

1) We could provide a Collection type entity provider that checks if all
    of the objects are JAXB element objects, if so a root element is
    written out and then each JAXB element is marshalled.

2) A generic collection type class with an entity provider:

   class CollectionType<T> {
       Collection<T> c;

       CollectionType(Collection<T> c) { ... }
   }

   The entity provider can then create a JAXBElement instance:

   QName q = // work out root element name from c
   new JAXBElement(q, CollectionType.class, c)


2) is really a specialization of 1) that is more efficient (and we
anyway will have to implement something like this for 1), but we have to
do do this:

    public TypeCollection<Customer> findAllCustomers() {
        Collection<Customer> c = ...
        return new TypeCollection(c);
    }

instead of:

    public Collection<Customer> findAllCustomers() {
        Collection<Customer> c = ...
        return c;
    }

Utilizing 2) we could also support the returning of a JAXB element so
the root element could be specified by the application:

    class ElementCollection<T> extends JAXBElement<TypeCollection<T>> {
        ElementCollection(Collection<T> c) { ... }

        ElementCollection(QName root, Collection<T> c) { ... }
    }

    public JAXBElement<CollectionType<Customer>> findAllCustomers() {
        Collection<Customer> c = ...

        return new ElementCollection(new QName("root"), c);
    }


Which do you prefer?

Paul.

[*] Because of type erasure the generic type of the collection is not
available at runtime for the Collection<T> instance, a major flaw in
Java generics IMHO. Otherwise we could easily and efficiently do this.


Florian Rosenberg wrote:
> Hi James,
>
> On Mon, October 22, 2007 11:09, James Weir wrote:
>> Hi Florian,
>>
>> The way I solved this problem is to create another class called Customers
>>
>> for example:
>>
>> @XmlRootElement(name="Customers")
>> public class Customers{
>> private List<Customer> collection;
>> }
>>
>> and so...
>>
>> @HttpMethod("GET")
>> @ProduceMime("text/xml")
>> @UriTemplate("customers")
>> public Customers findAllCustomers() { }
>
>
> that's my current solution too, but I guess there should a "nicer" way to
> tell JAXB to serialize the collection of JAXB annotated classes, without
> writing an "extra" class for that.
>
> If anybody has an idea let me know. I tried to search in the JAXB docs,
> probably we need to add another JAXB provider for doing that. I'm not a
> JAXB expert, so maybe somebody can clarify on this issues.
>
> Thanks,
> -Florian
>
>> Florian Rosenberg wrote:
>>> hi folks,
>>>
>>> just found out about Jersey and I tried to hack my first example, it
>>> works
>>> great except some detail which I do not get to work.
>>>
>>> I want to create a RESTful service that implements a simple customer
>>> management where with the following operations in my CustomerResource
>>> class (I left out the impl for readability):
>>>
>>> @UriTemplate("/")
>>> public class CustomerService {
>>>
>>> @UriTemplate("customers/{id}")
>>> @HttpMethod("POST")
>>> public void addCustomer(@UriParam("id") String id, Customer data) { }
>>>
>>> @UriTemplate("customers/{id}")
>>> @HttpMethod("DELETE")
>>> public Customer deleteCustomer(@UriParam("id") String id) { }
>>>
>>> @UriTemplate("customers/{id}")
>>> @HttpMethod("GET")
>>> @ProduceMime("text/xml")
>>> public Customer findCustomer(@UriParam("id") String id) { }
>>>
>>> @HttpMethod("GET")
>>> @ProduceMime("text/xml")
>>> @UriTemplate("customers")
>>> public Collection<Customer> findAllCustomers() { }
>>>
>>> @UriTemplate("customers/{id}")
>>> @HttpMethod("PUT")
>>> public void updateCustomer(@UriParam("id") String id, Customer data) {
>>> }
>>>
>>> }
>>>
>>> The Customer class is annotated with JAXB annotations. The above works
>>> great except the "findAllCustomers" as HTTP GET method. The problem is
>>> that Jersey does not know how to serialize a collection of customer
>>> objects. Is there a way to tell Jersey to do that. I tried for hours,
>>> the
>>> only workaround is the create your own Collection class that has the
>>> XmlRootElement annotation. But this cannot be the way to go, I guess.
>>>
>>> The result of the "findAllCustomer" should be something like:
>>>
>>> <customers>
>>> <customer id="1">
>>> <!-- ... -->
>>> </customer>
>>> <customer id="2">
>>> <!-- ... -->
>>> </customer>
>>> </customers>
>>>
>>> Any help is appreciated.
>>>
>>> Thanks,
>>> -Florian
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109