You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Dan Check <ch...@catalist.us> on 2009/06/29 23:41:55 UTC

Handling Collection returns via JAX-RS

Hi,

I'm writing a JAX-RS app and using CXF as the implementation.  I was having
trouble wiring up some of my methods -- specifically, one that was to return
a list of people:

@GET
@Path("/list")
List<Person> getPersons();

Trying to run that, I got NPEs, as List can't be written out as a root
element by default.

A lot of the advice that I saw involved adding extra collections, and
changing the method signature to return the JAXBtized collection wrapper.
Since this isn't strictly a REST call, this either means that everybody
using the service call will have to unwrap the collection, or that I will
have to code two methods every time I want to return a collection.

Instead, I'd like to actually fix this in the providers at the core of CXF.
I created a collection object of my own:

    <complexType name="Collection">
        <sequence>
            <any minOccurs="0" maxOccurs="unbounded"></any>
        </sequence>
    </complexType>

... And then overrode the JAXBElementProvider.writeTo method:

package us.XXXXXXXXX.iotool.jaxrs;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;

import org.apache.cxf.jaxrs.provider.JAXBElementProvider;

import us.XXXXXXXXX.iotool.model.Collection;

public class CollectionJAXBElementProvider extends JAXBElementProvider {

@Override
public void writeTo(Object obj, Class<?> cls, Type genericType,
     Annotation[] anns, MediaType m,
      MultivaluedMap<String, Object> headers, OutputStream os)
        throws IOException {
 try {
  Object actualObject = checkAdapter(obj, anns, true);
  // if it's a java.util.Collection, wrap it in our collection object
  if (actualObject instanceof java.util.Collection) {
    us.XXXXXXXXX.iotool.model.Collection collection = new Collection();
    java.util.List list  =
      new java.util.ArrayList<Object>((java.util.Collection)actualObject);
    collection.setAnies(list);
    actualObject = collection;
  }

  // now pass to the superclass
  super.writeTo(actualObject, cls, genericType, anns, m, headers, os);
  }  catch (WebApplicationException e) {
   throw e;
  } catch (Exception e) {
   throw new WebApplicationException(e);
  }
 }

}


This works fine -- any java.util.Collection will get wrapped in a
<Collection> tag.

There are a couple of downsides here:

(1) Doing it in this provider means that it doesn't apply to my JSON
provider.
(2) I don't think that I have a great way to consume this on the client side
as anything other than a wrapped collection (if that even works).

Two sets of questions:
(1) Can I get to my desired end -- transparently handling
java.util.Collection objects -- without all this mucking about?  Can I do
this with a XmlJavaTypeAdapter?

(2) Is there a different spot in the chain where I can put this that would
change the objects prior to their being consumed by any providers?  The
documentation on the JAX-RS filters wasn't totally clear to me on this
point.

Thanks in advance,
Dan


-----
CONFIDENTIALITY NOTICE: The information contained in this message
may be privileged and confidential and protected from disclosure.
 If the reader of this message is not the intended recipient, or
responsible for delivering it to the intended recipient, please
be advised that any distribution, dissemination, copying or other
transmission or use of the information contained in this message
or its enclosed attachments is strictly prohibited.  Please
notify us immediately if you have received this message in error
by replying to the sender of the message and deleting it from
your computer.  Thank you. 
 


RE: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <se...@iona.com>.
Hi Kiran

Yes, it is only JSONProvider that can not *read* explicit collections like
List<Customer> so Customers wrapper would be needed.
With JAXB it should work, please see

http://svn.apache.org/repos/asf/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java

testGetBookCollection()
testGetBookArray()
 
base Collection and Sets are also supported

I'll also add the test using WebClients

cheers, Sergey


kiran.sidhu wrote:
> 
> Hi Sergey,
>                Yes, I meant using CXF JAX-RS Client API.
> I was wondering if JAXB can read the xml in the response and generate
> the collection of Customer objects.
> 
> Thanks
> Kiran
> 
> -----Original Message-----
> From: users-return-16671-kiran.sidhu=asipay.com@cxf.apache.org
> [mailto:users-return-16671-kiran.sidhu=asipay.com@cxf.apache.org] 
> Sent: Tuesday, August 11, 2009 3:41 AM
> To: users@cxf.apache.org
> Subject: RE: Handling Collection<JAXBElement> returns via JAX-RS
> 
> 
> Hi
> 
> Do you mean 'using CXF JAXRS client API' ?
> At the moment explicit collections can not be read by JSONProvider
> (Jettison) - I will look into it; otherwise, Sam's message explains how
> collections can be serialized and then read manually by some JSON-aware
> utils. If it is an option and in case you did refer to a client api then
> you
> may be able to do it like this :
> 
> WebClient client = WebClient.create(address);
> InputStream is = client.get(InputStream.class);
> // read JSON collection
> 
> but as I said, we may be able get it fixed
> 
> 
> cheers, Sergey 
> 
> 
> kiran.sidhu wrote:
>> 
>> Has anybody tried getting the collection out from the Response on the
>> client side ?
>> 
>> -----Original Message-----
>> From: users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org
>> [mailto:users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org] 
>> Sent: Friday, August 07, 2009 12:28 AM
>> To: users@cxf.apache.org; users@cxf.apache.org
>> Subject: RE: Handling Collection<JAXBElement> returns via JAX-RS
>> 
>> Hi Gabo
>> 
>> Yeah, I agree, in some cases names like 'Historys' do no look right
> :-)
>> but it can be tricky to come with the universally acceptable
> collection
>> name, as CXF supports now explicit arrays, lists, base collections and
>> sets. 
>> One can override it by setting a global 'collectionWrapperName' or
>> 'collectionWrapperMap' property on
>> a JAXBElementProvider bean. 'collectionWrapperMap' is a map property,
>> keys are collectionWrapperNames and values are class names, or ex, if
> a
>> given service returns History and Datum then one would use this
>> property.
>> 
>> CollectionWrapperName can be a simple name like 'ListOfHistory' or an
>> expanded QName like
>> '{http://history}ListOfHistory'. In the latter case a 'ns1' prefix
> will
>> be bound to an {http://history} namespace. 
>> 
>> By the way, I've been working on updating the JAX-RS docs for the last
> 2
>> days, so it's all documented now :
>> 
>>
> http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Handlingexplicitcoll
>> ections
>> 
>> but I'm going to spend more time on improving the docs.
>> 
>> thanks, Sergey
>> 
>> -----Original Message-----
>> From: Gabo Manuel [mailto:kmanuel@solegysystems.com]
>> Sent: Fri 8/7/2009 1:28 AM
>> To: users@cxf.apache.org
>> Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS
>>  
>> Hi Sergey,
>> 
>>> By default, pluralized XMLRootElement name attribute will be used as
> a
>>> wrapper, namespace-prefixed if needed, if no name attribute is there
>> then a
>>> lower-case pluralized class name will be used. 
>> Just tested the latest release 2.2.3. The rest services handle the 
>> collections. Just a comment though, I think it would be better to use 
>> 'ArrayOf_<XMLRootElement name attribute>'. It just looks weird to have
> a
>> 
>> tag like 'Historys' or 'Datums' (along with other words that have 
>> special case of plurality) or maybe adding an attribute to the 
>> annotation to specify the plural term to be used.
>> 
>> Gabo
>> 
>> 
>> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> _ _
>> _
>> 
>> Notice: This information is intended only for the person(s) or
> entity(ies)
>> to which it is addressed. This information may contain information
> that is
>> confidential or otherwise protected from disclosure. If you are not
> the
>> intended recipient of this message, or if this message has been
> addressed
>> to you in error, please immediately alert the sender by reply e-mail
> and
>> then delete this message, including any attachments. Any
> dissemination,
>> distribution or other use of the contents of this message by anyone
> other
>> than the intended recipient is strictly prohibited.
>> 
>> 
>> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/Handling-Collection%3CJAXBElement%3E-returns-via-J
> AX-RS-tp24262522p24915229.html
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> 
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> _
> 
> Notice: This information is intended only for the person(s) or entity(ies)
> to which it is addressed. This information may contain information that is
> confidential or otherwise protected from disclosure. If you are not the
> intended recipient of this message, or if this message has been addressed
> to you in error, please immediately alert the sender by reply e-mail and
> then delete this message, including any attachments. Any dissemination,
> distribution or other use of the contents of this message by anyone other
> than the intended recipient is strictly prohibited.
> 
> 
> 

-- 
View this message in context: http://www.nabble.com/Handling-Collection%3CJAXBElement%3E-returns-via-JAX-RS-tp24262522p24931544.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: Handling Collection returns via JAX-RS

Posted by ki...@asipay.com.
Hi Sergey,
               Yes, I meant using CXF JAX-RS Client API.
I was wondering if JAXB can read the xml in the response and generate
the collection of Customer objects.

Thanks
Kiran

-----Original Message-----
From: users-return-16671-kiran.sidhu=asipay.com@cxf.apache.org
[mailto:users-return-16671-kiran.sidhu=asipay.com@cxf.apache.org] 
Sent: Tuesday, August 11, 2009 3:41 AM
To: users@cxf.apache.org
Subject: RE: Handling Collection<JAXBElement> returns via JAX-RS


Hi

Do you mean 'using CXF JAXRS client API' ?
At the moment explicit collections can not be read by JSONProvider
(Jettison) - I will look into it; otherwise, Sam's message explains how
collections can be serialized and then read manually by some JSON-aware
utils. If it is an option and in case you did refer to a client api then
you
may be able to do it like this :

WebClient client = WebClient.create(address);
InputStream is = client.get(InputStream.class);
// read JSON collection

but as I said, we may be able get it fixed


cheers, Sergey 


kiran.sidhu wrote:
> 
> Has anybody tried getting the collection out from the Response on the
> client side ?
> 
> -----Original Message-----
> From: users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org
> [mailto:users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org] 
> Sent: Friday, August 07, 2009 12:28 AM
> To: users@cxf.apache.org; users@cxf.apache.org
> Subject: RE: Handling Collection<JAXBElement> returns via JAX-RS
> 
> Hi Gabo
> 
> Yeah, I agree, in some cases names like 'Historys' do no look right
:-)
> but it can be tricky to come with the universally acceptable
collection
> name, as CXF supports now explicit arrays, lists, base collections and
> sets. 
> One can override it by setting a global 'collectionWrapperName' or
> 'collectionWrapperMap' property on
> a JAXBElementProvider bean. 'collectionWrapperMap' is a map property,
> keys are collectionWrapperNames and values are class names, or ex, if
a
> given service returns History and Datum then one would use this
> property.
> 
> CollectionWrapperName can be a simple name like 'ListOfHistory' or an
> expanded QName like
> '{http://history}ListOfHistory'. In the latter case a 'ns1' prefix
will
> be bound to an {http://history} namespace. 
> 
> By the way, I've been working on updating the JAX-RS docs for the last
2
> days, so it's all documented now :
> 
>
http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Handlingexplicitcoll
> ections
> 
> but I'm going to spend more time on improving the docs.
> 
> thanks, Sergey
> 
> -----Original Message-----
> From: Gabo Manuel [mailto:kmanuel@solegysystems.com]
> Sent: Fri 8/7/2009 1:28 AM
> To: users@cxf.apache.org
> Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS
>  
> Hi Sergey,
> 
>> By default, pluralized XMLRootElement name attribute will be used as
a
>> wrapper, namespace-prefixed if needed, if no name attribute is there
> then a
>> lower-case pluralized class name will be used. 
> Just tested the latest release 2.2.3. The rest services handle the 
> collections. Just a comment though, I think it would be better to use 
> 'ArrayOf_<XMLRootElement name attribute>'. It just looks weird to have
a
> 
> tag like 'Historys' or 'Datums' (along with other words that have 
> special case of plurality) or maybe adding an attribute to the 
> annotation to specify the plural term to be used.
> 
> Gabo
> 
> 
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _
> _
> 
> Notice: This information is intended only for the person(s) or
entity(ies)
> to which it is addressed. This information may contain information
that is
> confidential or otherwise protected from disclosure. If you are not
the
> intended recipient of this message, or if this message has been
addressed
> to you in error, please immediately alert the sender by reply e-mail
and
> then delete this message, including any attachments. Any
dissemination,
> distribution or other use of the contents of this message by anyone
other
> than the intended recipient is strictly prohibited.
> 
> 
> 

-- 
View this message in context:
http://www.nabble.com/Handling-Collection%3CJAXBElement%3E-returns-via-J
AX-RS-tp24262522p24915229.html
Sent from the cxf-user mailing list archive at Nabble.com.


_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Notice: This information is intended only for the person(s) or entity(ies) to which it is addressed. This information may contain information that is confidential or otherwise protected from disclosure. If you are not the intended recipient of this message, or if this message has been addressed to you in error, please immediately alert the sender by reply e-mail and then delete this message, including any attachments. Any dissemination, distribution or other use of the contents of this message by anyone other than the intended recipient is strictly prohibited.


RE: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <se...@iona.com>.
Hi

Do you mean 'using CXF JAXRS client API' ?
At the moment explicit collections can not be read by JSONProvider
(Jettison) - I will look into it; otherwise, Sam's message explains how
collections can be serialized and then read manually by some JSON-aware
utils. If it is an option and in case you did refer to a client api then you
may be able to do it like this :

WebClient client = WebClient.create(address);
InputStream is = client.get(InputStream.class);
// read JSON collection

but as I said, we may be able get it fixed


cheers, Sergey 


kiran.sidhu wrote:
> 
> Has anybody tried getting the collection out from the Response on the
> client side ?
> 
> -----Original Message-----
> From: users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org
> [mailto:users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org] 
> Sent: Friday, August 07, 2009 12:28 AM
> To: users@cxf.apache.org; users@cxf.apache.org
> Subject: RE: Handling Collection<JAXBElement> returns via JAX-RS
> 
> Hi Gabo
> 
> Yeah, I agree, in some cases names like 'Historys' do no look right :-)
> but it can be tricky to come with the universally acceptable collection
> name, as CXF supports now explicit arrays, lists, base collections and
> sets. 
> One can override it by setting a global 'collectionWrapperName' or
> 'collectionWrapperMap' property on
> a JAXBElementProvider bean. 'collectionWrapperMap' is a map property,
> keys are collectionWrapperNames and values are class names, or ex, if a
> given service returns History and Datum then one would use this
> property.
> 
> CollectionWrapperName can be a simple name like 'ListOfHistory' or an
> expanded QName like
> '{http://history}ListOfHistory'. In the latter case a 'ns1' prefix will
> be bound to an {http://history} namespace. 
> 
> By the way, I've been working on updating the JAX-RS docs for the last 2
> days, so it's all documented now :
> 
> http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Handlingexplicitcoll
> ections
> 
> but I'm going to spend more time on improving the docs.
> 
> thanks, Sergey
> 
> -----Original Message-----
> From: Gabo Manuel [mailto:kmanuel@solegysystems.com]
> Sent: Fri 8/7/2009 1:28 AM
> To: users@cxf.apache.org
> Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS
>  
> Hi Sergey,
> 
>> By default, pluralized XMLRootElement name attribute will be used as a
>> wrapper, namespace-prefixed if needed, if no name attribute is there
> then a
>> lower-case pluralized class name will be used. 
> Just tested the latest release 2.2.3. The rest services handle the 
> collections. Just a comment though, I think it would be better to use 
> 'ArrayOf_<XMLRootElement name attribute>'. It just looks weird to have a
> 
> tag like 'Historys' or 'Datums' (along with other words that have 
> special case of plurality) or maybe adding an attribute to the 
> annotation to specify the plural term to be used.
> 
> Gabo
> 
> 
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> _
> 
> Notice: This information is intended only for the person(s) or entity(ies)
> to which it is addressed. This information may contain information that is
> confidential or otherwise protected from disclosure. If you are not the
> intended recipient of this message, or if this message has been addressed
> to you in error, please immediately alert the sender by reply e-mail and
> then delete this message, including any attachments. Any dissemination,
> distribution or other use of the contents of this message by anyone other
> than the intended recipient is strictly prohibited.
> 
> 
> 

-- 
View this message in context: http://www.nabble.com/Handling-Collection%3CJAXBElement%3E-returns-via-JAX-RS-tp24262522p24915229.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: Handling Collection returns via JAX-RS

Posted by "Sam.Wang" <Bi...@ge.com>.
Hi Kiran:

I have test version2.2.3, it supports outputting collection now.

following is a demo code:

	@GET
	@Path("/customers/")
	public List<Customer> getCustomers() {
		List<Customer> list = new ArrayList<Customer>();
		Customer c = new Customer();

		c.setName("John1");
		c.setId(123);
		list.add(c);

		c.setName("John2");
		c.setId(234);
		list.add(c);
		Customers cs = new Customers();
		cs.setCustomer(list);
		return list;
	}

So I use the Ajax request to get the response and it will be:

{"Customer":[{"id":234,"name":"John2"},{"id":234,"name":"John2"}]}


kiran.sidhu wrote:
> 
> Has anybody tried getting the collection out from the Response on the
> client side ?
> 
> -----Original Message-----
> ...
> 

-- 
View this message in context: http://www.nabble.com/Handling-Collection%3CJAXBElement%3E-returns-via-JAX-RS-tp24262522p24910154.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: Handling Collection returns via JAX-RS

Posted by ki...@asipay.com.
Has anybody tried getting the collection out from the Response on the
client side ?

-----Original Message-----
From: users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org
[mailto:users-return-16606-kiran.sidhu=asipay.com@cxf.apache.org] 
Sent: Friday, August 07, 2009 12:28 AM
To: users@cxf.apache.org; users@cxf.apache.org
Subject: RE: Handling Collection<JAXBElement> returns via JAX-RS

Hi Gabo

Yeah, I agree, in some cases names like 'Historys' do no look right :-)
but it can be tricky to come with the universally acceptable collection
name, as CXF supports now explicit arrays, lists, base collections and
sets. 
One can override it by setting a global 'collectionWrapperName' or
'collectionWrapperMap' property on
a JAXBElementProvider bean. 'collectionWrapperMap' is a map property,
keys are collectionWrapperNames and values are class names, or ex, if a
given service returns History and Datum then one would use this
property.

CollectionWrapperName can be a simple name like 'ListOfHistory' or an
expanded QName like
'{http://history}ListOfHistory'. In the latter case a 'ns1' prefix will
be bound to an {http://history} namespace. 

By the way, I've been working on updating the JAX-RS docs for the last 2
days, so it's all documented now :

http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Handlingexplicitcoll
ections

but I'm going to spend more time on improving the docs.

thanks, Sergey

-----Original Message-----
From: Gabo Manuel [mailto:kmanuel@solegysystems.com]
Sent: Fri 8/7/2009 1:28 AM
To: users@cxf.apache.org
Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS
 
Hi Sergey,

> By default, pluralized XMLRootElement name attribute will be used as a
> wrapper, namespace-prefixed if needed, if no name attribute is there
then a
> lower-case pluralized class name will be used. 
Just tested the latest release 2.2.3. The rest services handle the 
collections. Just a comment though, I think it would be better to use 
'ArrayOf_<XMLRootElement name attribute>'. It just looks weird to have a

tag like 'Historys' or 'Datums' (along with other words that have 
special case of plurality) or maybe adding an attribute to the 
annotation to specify the plural term to be used.

Gabo


_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Notice: This information is intended only for the person(s) or entity(ies) to which it is addressed. This information may contain information that is confidential or otherwise protected from disclosure. If you are not the intended recipient of this message, or if this message has been addressed to you in error, please immediately alert the sender by reply e-mail and then delete this message, including any attachments. Any dissemination, distribution or other use of the contents of this message by anyone other than the intended recipient is strictly prohibited.


RE: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Gabo

Yeah, I agree, in some cases names like 'Historys' do no look right :-) but it can be tricky to come with the universally acceptable collection name, as CXF supports now explicit arrays, lists, base collections and sets. 
One can override it by setting a global 'collectionWrapperName' or 'collectionWrapperMap' property on
a JAXBElementProvider bean. 'collectionWrapperMap' is a map property, keys are collectionWrapperNames and values are class names, or ex, if a given service returns History and Datum then one would use this property.

CollectionWrapperName can be a simple name like 'ListOfHistory' or an expanded QName like
'{http://history}ListOfHistory'. In the latter case a 'ns1' prefix will be bound to an {http://history} namespace. 

By the way, I've been working on updating the JAX-RS docs for the last 2 days, so it's all documented now :

http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Handlingexplicitcollections

but I'm going to spend more time on improving the docs.

thanks, Sergey

-----Original Message-----
From: Gabo Manuel [mailto:kmanuel@solegysystems.com]
Sent: Fri 8/7/2009 1:28 AM
To: users@cxf.apache.org
Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS
 
Hi Sergey,

> By default, pluralized XMLRootElement name attribute will be used as a
> wrapper, namespace-prefixed if needed, if no name attribute is there then a
> lower-case pluralized class name will be used. 
Just tested the latest release 2.2.3. The rest services handle the 
collections. Just a comment though, I think it would be better to use 
'ArrayOf_<XMLRootElement name attribute>'. It just looks weird to have a 
tag like 'Historys' or 'Datums' (along with other words that have 
special case of plurality) or maybe adding an attribute to the 
annotation to specify the plural term to be used.

Gabo



Re: Handling Collection returns via JAX-RS

Posted by Gabo Manuel <km...@solegysystems.com>.
Hi Sergey,

> By default, pluralized XMLRootElement name attribute will be used as a
> wrapper, namespace-prefixed if needed, if no name attribute is there then a
> lower-case pluralized class name will be used. 
Just tested the latest release 2.2.3. The rest services handle the 
collections. Just a comment though, I think it would be better to use 
'ArrayOf_<XMLRootElement name attribute>'. It just looks weird to have a 
tag like 'Historys' or 'Datums' (along with other words that have 
special case of plurality) or maybe adding an attribute to the 
annotation to specify the plural term to be used.

Gabo


RE: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <se...@iona.com>.
Hi

The initial support for reading/writing collections is on the trunk now.
Writing/reading collections/arrays is supported for plain JAXB, only writing
is currently supported for JSON.
I'll be looking at fixing a JSON reading issue and optimizing it all.

By default, pluralized XMLRootElement name attribute will be used as a
wrapper, namespace-prefixed if needed, if no name attribute is there then a
lower-case pluralized class name will be used. This can be customized by
using setCollectionWrapperName on JAXB/JSON providers

thanks, Sergey
 

Sergey Beryozkin-2 wrote:
> 
> Hi Dan,
> 
> I'm doing 2) now, though it does now work quite well for JSON, but it's
> a good start. Will definitely look into using ASM as well...
> 
> Cheers, Sergey
> 
> -----Original Message-----
> From: Daniel Kulp [mailto:dkulp@apache.org] 
> Sent: 15 July 2009 19:23
> To: users@cxf.apache.org
> Cc: Sergey Beryozkin
> Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS
> 
> 
> Well, on the JAX-WS side of things, if a method returns something like 
> List<Foo> getFoos(), one of two things happens depending on if ASM is
> found on 
> the classpath:
> 
> If ASM is found:
> At startup time, we use ASM to generate a wrapper bean in memory that
> would 
> basically be:
> @XmlRootElement(....)
> @XmlType(....)
> public class  GetFoos {
>    @XmlElement(...)
>     List<Foo> foo;
>    ...
> }
> that is then put into the JAXBContext along with Foo.   Since this can
> be 
> determined up front that we need to do it, that works fine.
> 
> 
> 2) If ASM is NOT found, we cannot do that above.   Thus, it becomes a
> runtime 
> thing.   In THAT case, we manually write a wrapper element out to the 
> XMLStreamWriter and then literally do the equiv of:
> 
> for(Foo f : foos) {
>    marshaller.marshal(f, writer);
> }
> 
> and then close off the wrapper element.    I think you should be able to
> do 
> something similar to the latter within the JAXB provider.
> 
> 
> Dan
> 
> 
> 
> 
> On Tue July 14 2009 8:18:14 am Sergey Beryozkin wrote:
>> Hi Dan
>>
>> I've started doing some work in this area and at the moment some
> manual 
>> top-level element start/end serialization is being done. I'd like to
>> experiment a bit with using a generated Collection wrapper, for the
>> deserailzation to work too, but I'm kind of stuck a bit as JAXB
> complains,
>> while serializing this generated Collection instance that no context
> is
>> available for say Foo.class, for ex :
>>
>> List foos = new ArrayList();
>> foos.add(new Foo());
>> Collection c = new Collection();
>> c.getAny().addAll(foos);
>> // marshal this collection instance
>>
>> perhaps the solution is to create a shared JAXBContext for both Foo &
>> Collection, but is it the right approach ? My concern is that given
> that in
>> JAX-RS we don't know in advance all the types we may have to deal with
> due
>> to the dynamic subresource resolution, we may end up with contexts for
> Foo
>> & Collection, Bar & Collection, etc - though may be it's unlikely to
> happen
>> in practice... Dan K, Benson - is there any trick I may need to be
> aware to
>> make it work in the most efficient way ? thanks, Sergey
>>
>> > Hi,
>> >
>> > I'm writing a JAX-RS app and using CXF as the implementation.  I was
>> > having trouble wiring up some of my methods -- specifically, one
> that was
>> > to return a list of people:
>> >
>> > @GET
>> > @Path("/list")
>> > List<Person> getPersons();
>> >
>> > Trying to run that, I got NPEs, as List can't be written out as a
> root
>> > element by default.
>> >
>> > A lot of the advice that I saw involved adding extra collections,
> and
>> > changing the method signature to return the JAXBtized collection
> wrapper.
>> > Since this isn't strictly a REST call, this either means that
> everybody
>> > using the service call will have to unwrap the collection, or that I
> will
>> > have to code two methods every time I want to return a collection.
>> >
>> > Instead, I'd like to actually fix this in the providers at the core
> of
>> > CXF. I created a collection object of my own:
>> >
>> >    <complexType name="Collection">
>> >        <sequence>
>> >            <any minOccurs="0" maxOccurs="unbounded"></any>
>> >        </sequence>
>> >    </complexType>
>> >
>> > ... And then overrode the JAXBElementProvider.writeTo method:
>> >
>> > package us.XXXXXXXXX.iotool.jaxrs;
>> >
>> > import java.io.IOException;
>> > import java.io.OutputStream;
>> > import java.lang.annotation.Annotation;
>> > import java.lang.reflect.Type;
>> >
>> > import javax.ws.rs.WebApplicationException;
>> > import javax.ws.rs.core.MediaType;
>> > import javax.ws.rs.core.MultivaluedMap;
>> >
>> > import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
>> >
>> > import us.XXXXXXXXX.iotool.model.Collection;
>> >
>> > public class CollectionJAXBElementProvider extends
> JAXBElementProvider {
>> >
>> > @Override
>> > public void writeTo(Object obj, Class<?> cls, Type genericType,
>> >     Annotation[] anns, MediaType m,
>> >      MultivaluedMap<String, Object> headers, OutputStream os)
>> >        throws IOException {
>> > try {
>> >  Object actualObject = checkAdapter(obj, anns, true);
>> >  // if it's a java.util.Collection, wrap it in our collection object
>> >  if (actualObject instanceof java.util.Collection) {
>> >    us.XXXXXXXXX.iotool.model.Collection collection = new
> Collection();
>> >    java.util.List list  =
>> >      new
> java.util.ArrayList((java.util.Collection)actualObject);
>> >    collection.setAnies(list);
>> >    actualObject = collection;
>> >  }
>> >
>> >  // now pass to the superclass
>> >  super.writeTo(actualObject, cls, genericType, anns, m, headers,
> os);
>> >  }  catch (WebApplicationException e) {
>> >   throw e;
>> >  } catch (Exception e) {
>> >   throw new WebApplicationException(e);
>> >  }
>> > }
>> >
>> > }
>> >
>> >
>> > This works fine -- any java.util.Collection will get wrapped in a
>> > <Collection> tag.
>> >
>> > There are a couple of downsides here:
>> >
>> > (1) Doing it in this provider means that it doesn't apply to my JSON
>> > provider.
>> > (2) I don't think that I have a great way to consume this on the
> client
>> > side as anything other than a wrapped collection (if that even
> works).
>> >
>> > Two sets of questions:
>> > (1) Can I get to my desired end -- transparently handling
>> > java.util.Collection objects -- without all this mucking about?  Can
> I do
>> > this with a XmlJavaTypeAdapter?
>> >
>> > (2) Is there a different spot in the chain where I can put this that
>> > would change the objects prior to their being consumed by any
> providers? 
>> > The documentation on the JAX-RS filters wasn't totally clear to me
> on
>> > this point.
>> >
>> > Thanks in advance,
>> > Dan
>> >
>> >
>> > -----
>> > CONFIDENTIALITY NOTICE: The information contained in this message
>> > may be privileged and confidential and protected from disclosure.
>> > If the reader of this message is not the intended recipient, or
>> > responsible for delivering it to the intended recipient, please
>> > be advised that any distribution, dissemination, copying or other
>> > transmission or use of the information contained in this message
>> > or its enclosed attachments is strictly prohibited.  Please
>> > notify us immediately if you have received this message in error
>> > by replying to the sender of the message and deleting it from
>> > your computer.  Thank you.
> 
> -- 
> Daniel Kulp
> dkulp@apache.org
> http://www.dankulp.com/blog
> 
> 

-- 
View this message in context: http://www.nabble.com/Handling-Collection%3CJAXBElement%3E-returns-via-JAX-RS-tp24262522p24517386.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Dan,

I'm doing 2) now, though it does now work quite well for JSON, but it's
a good start. Will definitely look into using ASM as well...

Cheers, Sergey

-----Original Message-----
From: Daniel Kulp [mailto:dkulp@apache.org] 
Sent: 15 July 2009 19:23
To: users@cxf.apache.org
Cc: Sergey Beryozkin
Subject: Re: Handling Collection<JAXBElement> returns via JAX-RS


Well, on the JAX-WS side of things, if a method returns something like 
List<Foo> getFoos(), one of two things happens depending on if ASM is
found on 
the classpath:

If ASM is found:
At startup time, we use ASM to generate a wrapper bean in memory that
would 
basically be:
@XmlRootElement(....)
@XmlType(....)
public class  GetFoos {
   @XmlElement(...)
    List<Foo> foo;
   ...
}
that is then put into the JAXBContext along with Foo.   Since this can
be 
determined up front that we need to do it, that works fine.


2) If ASM is NOT found, we cannot do that above.   Thus, it becomes a
runtime 
thing.   In THAT case, we manually write a wrapper element out to the 
XMLStreamWriter and then literally do the equiv of:

for(Foo f : foos) {
   marshaller.marshal(f, writer);
}

and then close off the wrapper element.    I think you should be able to
do 
something similar to the latter within the JAXB provider.


Dan




On Tue July 14 2009 8:18:14 am Sergey Beryozkin wrote:
> Hi Dan
>
> I've started doing some work in this area and at the moment some
manual 
> top-level element start/end serialization is being done. I'd like to
> experiment a bit with using a generated Collection wrapper, for the
> deserailzation to work too, but I'm kind of stuck a bit as JAXB
complains,
> while serializing this generated Collection instance that no context
is
> available for say Foo.class, for ex :
>
> List<Object> foos = new ArrayList<Object>();
> foos.add(new Foo());
> Collection c = new Collection();
> c.getAny().addAll(foos);
> // marshal this collection instance
>
> perhaps the solution is to create a shared JAXBContext for both Foo &
> Collection, but is it the right approach ? My concern is that given
that in
> JAX-RS we don't know in advance all the types we may have to deal with
due
> to the dynamic subresource resolution, we may end up with contexts for
Foo
> & Collection, Bar & Collection, etc - though may be it's unlikely to
happen
> in practice... Dan K, Benson - is there any trick I may need to be
aware to
> make it work in the most efficient way ? thanks, Sergey
>
> > Hi,
> >
> > I'm writing a JAX-RS app and using CXF as the implementation.  I was
> > having trouble wiring up some of my methods -- specifically, one
that was
> > to return a list of people:
> >
> > @GET
> > @Path("/list")
> > List<Person> getPersons();
> >
> > Trying to run that, I got NPEs, as List can't be written out as a
root
> > element by default.
> >
> > A lot of the advice that I saw involved adding extra collections,
and
> > changing the method signature to return the JAXBtized collection
wrapper.
> > Since this isn't strictly a REST call, this either means that
everybody
> > using the service call will have to unwrap the collection, or that I
will
> > have to code two methods every time I want to return a collection.
> >
> > Instead, I'd like to actually fix this in the providers at the core
of
> > CXF. I created a collection object of my own:
> >
> >    <complexType name="Collection">
> >        <sequence>
> >            <any minOccurs="0" maxOccurs="unbounded"></any>
> >        </sequence>
> >    </complexType>
> >
> > ... And then overrode the JAXBElementProvider.writeTo method:
> >
> > package us.XXXXXXXXX.iotool.jaxrs;
> >
> > import java.io.IOException;
> > import java.io.OutputStream;
> > import java.lang.annotation.Annotation;
> > import java.lang.reflect.Type;
> >
> > import javax.ws.rs.WebApplicationException;
> > import javax.ws.rs.core.MediaType;
> > import javax.ws.rs.core.MultivaluedMap;
> >
> > import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
> >
> > import us.XXXXXXXXX.iotool.model.Collection;
> >
> > public class CollectionJAXBElementProvider extends
JAXBElementProvider {
> >
> > @Override
> > public void writeTo(Object obj, Class<?> cls, Type genericType,
> >     Annotation[] anns, MediaType m,
> >      MultivaluedMap<String, Object> headers, OutputStream os)
> >        throws IOException {
> > try {
> >  Object actualObject = checkAdapter(obj, anns, true);
> >  // if it's a java.util.Collection, wrap it in our collection object
> >  if (actualObject instanceof java.util.Collection) {
> >    us.XXXXXXXXX.iotool.model.Collection collection = new
Collection();
> >    java.util.List list  =
> >      new
java.util.ArrayList<Object>((java.util.Collection)actualObject);
> >    collection.setAnies(list);
> >    actualObject = collection;
> >  }
> >
> >  // now pass to the superclass
> >  super.writeTo(actualObject, cls, genericType, anns, m, headers,
os);
> >  }  catch (WebApplicationException e) {
> >   throw e;
> >  } catch (Exception e) {
> >   throw new WebApplicationException(e);
> >  }
> > }
> >
> > }
> >
> >
> > This works fine -- any java.util.Collection will get wrapped in a
> > <Collection> tag.
> >
> > There are a couple of downsides here:
> >
> > (1) Doing it in this provider means that it doesn't apply to my JSON
> > provider.
> > (2) I don't think that I have a great way to consume this on the
client
> > side as anything other than a wrapped collection (if that even
works).
> >
> > Two sets of questions:
> > (1) Can I get to my desired end -- transparently handling
> > java.util.Collection objects -- without all this mucking about?  Can
I do
> > this with a XmlJavaTypeAdapter?
> >
> > (2) Is there a different spot in the chain where I can put this that
> > would change the objects prior to their being consumed by any
providers? 
> > The documentation on the JAX-RS filters wasn't totally clear to me
on
> > this point.
> >
> > Thanks in advance,
> > Dan
> >
> >
> > -----
> > CONFIDENTIALITY NOTICE: The information contained in this message
> > may be privileged and confidential and protected from disclosure.
> > If the reader of this message is not the intended recipient, or
> > responsible for delivering it to the intended recipient, please
> > be advised that any distribution, dissemination, copying or other
> > transmission or use of the information contained in this message
> > or its enclosed attachments is strictly prohibited.  Please
> > notify us immediately if you have received this message in error
> > by replying to the sender of the message and deleting it from
> > your computer.  Thank you.

-- 
Daniel Kulp
dkulp@apache.org
http://www.dankulp.com/blog

Re: Handling Collection returns via JAX-RS

Posted by Daniel Kulp <dk...@apache.org>.
Well, on the JAX-WS side of things, if a method returns something like 
List<Foo> getFoos(), one of two things happens depending on if ASM is found on 
the classpath:

If ASM is found:
At startup time, we use ASM to generate a wrapper bean in memory that would 
basically be:
@XmlRootElement(....)
@XmlType(....)
public class  GetFoos {
   @XmlElement(...)
    List<Foo> foo;
   ...
}
that is then put into the JAXBContext along with Foo.   Since this can be 
determined up front that we need to do it, that works fine.


2) If ASM is NOT found, we cannot do that above.   Thus, it becomes a runtime 
thing.   In THAT case, we manually write a wrapper element out to the 
XMLStreamWriter and then literally do the equiv of:

for(Foo f : foos) {
   marshaller.marshal(f, writer);
}

and then close off the wrapper element.    I think you should be able to do 
something similar to the latter within the JAXB provider.


Dan




On Tue July 14 2009 8:18:14 am Sergey Beryozkin wrote:
> Hi Dan
>
> I've started doing some work in this area and at the moment some manual 
> top-level element start/end serialization is being done. I'd like to
> experiment a bit with using a generated Collection wrapper, for the
> deserailzation to work too, but I'm kind of stuck a bit as JAXB complains,
> while serializing this generated Collection instance that no context is
> available for say Foo.class, for ex :
>
> List<Object> foos = new ArrayList<Object>();
> foos.add(new Foo());
> Collection c = new Collection();
> c.getAny().addAll(foos);
> // marshal this collection instance
>
> perhaps the solution is to create a shared JAXBContext for both Foo &
> Collection, but is it the right approach ? My concern is that given that in
> JAX-RS we don't know in advance all the types we may have to deal with due
> to the dynamic subresource resolution, we may end up with contexts for Foo
> & Collection, Bar & Collection, etc - though may be it's unlikely to happen
> in practice... Dan K, Benson - is there any trick I may need to be aware to
> make it work in the most efficient way ? thanks, Sergey
>
> > Hi,
> >
> > I'm writing a JAX-RS app and using CXF as the implementation.  I was
> > having trouble wiring up some of my methods -- specifically, one that was
> > to return a list of people:
> >
> > @GET
> > @Path("/list")
> > List<Person> getPersons();
> >
> > Trying to run that, I got NPEs, as List can't be written out as a root
> > element by default.
> >
> > A lot of the advice that I saw involved adding extra collections, and
> > changing the method signature to return the JAXBtized collection wrapper.
> > Since this isn't strictly a REST call, this either means that everybody
> > using the service call will have to unwrap the collection, or that I will
> > have to code two methods every time I want to return a collection.
> >
> > Instead, I'd like to actually fix this in the providers at the core of
> > CXF. I created a collection object of my own:
> >
> >    <complexType name="Collection">
> >        <sequence>
> >            <any minOccurs="0" maxOccurs="unbounded"></any>
> >        </sequence>
> >    </complexType>
> >
> > ... And then overrode the JAXBElementProvider.writeTo method:
> >
> > package us.XXXXXXXXX.iotool.jaxrs;
> >
> > import java.io.IOException;
> > import java.io.OutputStream;
> > import java.lang.annotation.Annotation;
> > import java.lang.reflect.Type;
> >
> > import javax.ws.rs.WebApplicationException;
> > import javax.ws.rs.core.MediaType;
> > import javax.ws.rs.core.MultivaluedMap;
> >
> > import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
> >
> > import us.XXXXXXXXX.iotool.model.Collection;
> >
> > public class CollectionJAXBElementProvider extends JAXBElementProvider {
> >
> > @Override
> > public void writeTo(Object obj, Class<?> cls, Type genericType,
> >     Annotation[] anns, MediaType m,
> >      MultivaluedMap<String, Object> headers, OutputStream os)
> >        throws IOException {
> > try {
> >  Object actualObject = checkAdapter(obj, anns, true);
> >  // if it's a java.util.Collection, wrap it in our collection object
> >  if (actualObject instanceof java.util.Collection) {
> >    us.XXXXXXXXX.iotool.model.Collection collection = new Collection();
> >    java.util.List list  =
> >      new java.util.ArrayList<Object>((java.util.Collection)actualObject);
> >    collection.setAnies(list);
> >    actualObject = collection;
> >  }
> >
> >  // now pass to the superclass
> >  super.writeTo(actualObject, cls, genericType, anns, m, headers, os);
> >  }  catch (WebApplicationException e) {
> >   throw e;
> >  } catch (Exception e) {
> >   throw new WebApplicationException(e);
> >  }
> > }
> >
> > }
> >
> >
> > This works fine -- any java.util.Collection will get wrapped in a
> > <Collection> tag.
> >
> > There are a couple of downsides here:
> >
> > (1) Doing it in this provider means that it doesn't apply to my JSON
> > provider.
> > (2) I don't think that I have a great way to consume this on the client
> > side as anything other than a wrapped collection (if that even works).
> >
> > Two sets of questions:
> > (1) Can I get to my desired end -- transparently handling
> > java.util.Collection objects -- without all this mucking about?  Can I do
> > this with a XmlJavaTypeAdapter?
> >
> > (2) Is there a different spot in the chain where I can put this that
> > would change the objects prior to their being consumed by any providers? 
> > The documentation on the JAX-RS filters wasn't totally clear to me on
> > this point.
> >
> > Thanks in advance,
> > Dan
> >
> >
> > -----
> > CONFIDENTIALITY NOTICE: The information contained in this message
> > may be privileged and confidential and protected from disclosure.
> > If the reader of this message is not the intended recipient, or
> > responsible for delivering it to the intended recipient, please
> > be advised that any distribution, dissemination, copying or other
> > transmission or use of the information contained in this message
> > or its enclosed attachments is strictly prohibited.  Please
> > notify us immediately if you have received this message in error
> > by replying to the sender of the message and deleting it from
> > your computer.  Thank you.

-- 
Daniel Kulp
dkulp@apache.org
http://www.dankulp.com/blog

Re: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Dan

I've started doing some work in this area and at the moment some manual  top-level element start/end serialization is being done.
I'd like to experiment a bit with using a generated Collection wrapper, for the deserailzation to work too, but I'm kind of stuck a
bit as JAXB complains, while serializing this generated Collection instance that no context is available for say Foo.class, for ex :

List<Object> foos = new ArrayList<Object>();
foos.add(new Foo());
Collection c = new Collection();
c.getAny().addAll(foos);
// marshal this collection instance

perhaps the solution is to create a shared JAXBContext for both Foo & Collection, but is it the right approach ? My concern is that 
given that in JAX-RS we don't know in advance all the types we may have to deal with due to the dynamic subresource resolution, we 
may end up with contexts for Foo & Collection, Bar & Collection, etc - though may be it's unlikely to happen in practice...
Dan K, Benson - is there any trick I may need to be aware to make it work in the most efficient way ?
thanks, Sergey

> Hi,
>
> I'm writing a JAX-RS app and using CXF as the implementation.  I was having
> trouble wiring up some of my methods -- specifically, one that was to return
> a list of people:
>
> @GET
> @Path("/list")
> List<Person> getPersons();
>
> Trying to run that, I got NPEs, as List can't be written out as a root
> element by default.
>
> A lot of the advice that I saw involved adding extra collections, and
> changing the method signature to return the JAXBtized collection wrapper.
> Since this isn't strictly a REST call, this either means that everybody
> using the service call will have to unwrap the collection, or that I will
> have to code two methods every time I want to return a collection.
>
> Instead, I'd like to actually fix this in the providers at the core of CXF.
> I created a collection object of my own:
>
>    <complexType name="Collection">
>        <sequence>
>            <any minOccurs="0" maxOccurs="unbounded"></any>
>        </sequence>
>    </complexType>
>
> ... And then overrode the JAXBElementProvider.writeTo method:
>
> package us.XXXXXXXXX.iotool.jaxrs;
>
> import java.io.IOException;
> import java.io.OutputStream;
> import java.lang.annotation.Annotation;
> import java.lang.reflect.Type;
>
> import javax.ws.rs.WebApplicationException;
> import javax.ws.rs.core.MediaType;
> import javax.ws.rs.core.MultivaluedMap;
>
> import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
>
> import us.XXXXXXXXX.iotool.model.Collection;
>
> public class CollectionJAXBElementProvider extends JAXBElementProvider {
>
> @Override
> public void writeTo(Object obj, Class<?> cls, Type genericType,
>     Annotation[] anns, MediaType m,
>      MultivaluedMap<String, Object> headers, OutputStream os)
>        throws IOException {
> try {
>  Object actualObject = checkAdapter(obj, anns, true);
>  // if it's a java.util.Collection, wrap it in our collection object
>  if (actualObject instanceof java.util.Collection) {
>    us.XXXXXXXXX.iotool.model.Collection collection = new Collection();
>    java.util.List list  =
>      new java.util.ArrayList<Object>((java.util.Collection)actualObject);
>    collection.setAnies(list);
>    actualObject = collection;
>  }
>
>  // now pass to the superclass
>  super.writeTo(actualObject, cls, genericType, anns, m, headers, os);
>  }  catch (WebApplicationException e) {
>   throw e;
>  } catch (Exception e) {
>   throw new WebApplicationException(e);
>  }
> }
>
> }
>
>
> This works fine -- any java.util.Collection will get wrapped in a
> <Collection> tag.
>
> There are a couple of downsides here:
>
> (1) Doing it in this provider means that it doesn't apply to my JSON
> provider.
> (2) I don't think that I have a great way to consume this on the client side
> as anything other than a wrapped collection (if that even works).
>
> Two sets of questions:
> (1) Can I get to my desired end -- transparently handling
> java.util.Collection objects -- without all this mucking about?  Can I do
> this with a XmlJavaTypeAdapter?
>
> (2) Is there a different spot in the chain where I can put this that would
> change the objects prior to their being consumed by any providers?  The
> documentation on the JAX-RS filters wasn't totally clear to me on this
> point.
>
> Thanks in advance,
> Dan
>
>
> -----
> CONFIDENTIALITY NOTICE: The information contained in this message
> may be privileged and confidential and protected from disclosure.
> If the reader of this message is not the intended recipient, or
> responsible for delivering it to the intended recipient, please
> be advised that any distribution, dissemination, copying or other
> transmission or use of the information contained in this message
> or its enclosed attachments is strictly prohibited.  Please
> notify us immediately if you have received this message in error
> by replying to the sender of the message and deleting it from
> your computer.  Thank you.
>
>
>


Re: []Re: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Dan

>>
>> @CollectionElement(name="persons", ns=http://persons)
>> List<Person> getPersons() {}
>>
>> MessageBodyWriters get the method annotations passed to it, so :
>>
>> Produces("application/xml, text/xml, application/*+xml")
>> public class CollectionsProvider implements MessageBodyWriter<Object> {
>>
>>    public boolean isWriteable(...) {return true if Collection }
>>    public void writeTo(Object obj, Class<?> cls, Type genericType,
>> Annotation[] anns, MediaType m,
>>           MultivaluedMap<String, Object> headers, OutputStream os)  throws
>> IOException {
>>
>>           CollectionElement root =
>> AnnotationUtils.getAnnotation(CollectionElement.class, anns);
>>           os.write(getStartTag(root));
>>
>>           // get class of the first element or use genericType
>>           Collection<Object> collection = (Collection<Object>)obj;
>>           Class<?> elementClass = ...
>>           MessageBodyWriter bodyWriter =
>> Providers.getMessageBodyWriter(elementClass, ....);
>>           for (Object o : collection) {
>>                bodyWriter.writeTo(o, ..., os);
>>           }
>>
>>           os.write(getEndTag(root));
>>    }
>>
>> }
>>
>> I think this should work seamlessly for all XML-based collections, even those
>> not relying on JAXB. I was prototyping it when working
>> on 0.8 support but for some reasons I decided not to go ahead then - may be
>> there's some flaw above but it appears it should work.
>
> That sounds great.  Would this work for JSON providers as well?  Let me know
> if you need help testing or anything.

Hmm... Probably not. Unless we can support multiple CollectionElement annotations on a method, one per media type, or may be use a 
single one :

@CollectionElement({"{http://people}people", "application/xml"},
                                  "jsonCollectionRoot", "application/json"})

so CollectionsProvider will output the media type specific start/end tags/sequences in its writeTo... It's a bit hairy though in 
that with XMl one might want to say if it's a default namespace or not, and if nor then what prefix to use, so may be we should have 
@CollectionXmlElement for XML based collections and @CollectionRoot for all other ones, so

@CollectionXmlElement({"{http://people}", "people", "prefix:"}
@CollectionRoot({""jsonCollectionStart"", ""jsonCollectionEnd"", ""application/json"",
                            {""textCollectionStart"", ""textCollectionEnd"", "separator", "text/plain""}


>
>> We can also make the use of @CollectionElement optional - but then we'd need
>> to use some default wrapper element like <result> or
>> <collection> which may make the actual xml instance fail the validation on the
>> other end. Deducing the namespace from the collection
>> elements may end up be too brittle/ineffective or unreliable if it's non-JAXB.
>>
>> What do you think ? Let me know please...
>
> I agree that the deduced namespacing may be too brittle in a non-JAXB
> environment.  The @CollectionElement sounds good to me.  How would all this
> work for non-cxf-based clients?  Do you put a Collection of "any" elements
> in the xsd and let them figure it out?

Not sure actually : I think the wadl generation utility may have to be  smart enough to put some information into wadl for clients 
to figure it out...

>
> Ideally, I'd like it if enunciate could still generate documentation for me.
> I recognize that this may not be realistic.

can you explain a bit more ?

>>
>> with filters you can do :
>>
>> public interface MyResponseHandler {
>>
>>     Response handleResponse(Message outputMessage,
>>                            OperationResourceInfo invokedOperation,
>>                            Response response) {
>>            // this method is not minimally effective as you can get
>> invokedOperation/response from
>>            // outputMessage - but you might need to deal directly with the
>> message
>>            // 1 - using response
>>            ResponseBuilder builder = Response.status(response.getStatus());
>>            // next, copy response headers into the builder
>>            // finally
>>            return builder.entity(new MyWrapper(response.getEntity())).build();
>>
>>            // 2. Using message - this can be done in CXF out interceptor too
>>            MessageContentsList objs =
>> MessageContentsList.getContentsList(message);
>> if (objs !== null && objs.size() == 1) {
>>     Object responseObj = objs.remove(0);
>>     obj.add(new MyWrapper(responseObj));
>> }
>>     }
>>
>> }
>
> I will give that a shot.  It looks like the filters will get me JSON support
> as well.  Thanks again for the detailed response.

give a try please

thanks, Sergey

>
> Thanks,
> Dan
>
>
>
> -----
> CONFIDENTIALITY NOTICE: The information contained in this message
> may be privileged and confidential and protected from disclosure.
> If the reader of this message is not the intended recipient, or
> responsible for delivering it to the intended recipient, please
> be advised that any distribution, dissemination, copying or other
> transmission or use of the information contained in this message
> or its enclosed attachments is strictly prohibited.  Please
> notify us immediately if you have received this message in error
> by replying to the sender of the message and deleting it from
> your computer.  Thank you.
>
> 


Re: []Re: Handling Collection returns via JAX-RS

Posted by Dan Check <ch...@catalist.us>.
Hi Sergey,

Thanks for the response!  I'm glad to hear that this is on roadmap.

...snip...

>> 
>> This works fine -- any java.util.Collection will get wrapped in a
>> <Collection> tag.
> 
> interesting solution...
> 

It was definitely the quickest path for me.  I was impressed that it could
be implemented by overriding a single method, with no additional bad
effects.  Kudos on the code design.

...snip...
 
> I've been thinking about introducing a @CollectionElement annotation and a
> Collections message body writer :
> 
> @CollectionElement(name="persons", ns=http://persons)
> List<Person> getPersons() {}
> 
> MessageBodyWriters get the method annotations passed to it, so :
> 
> Produces("application/xml, text/xml, application/*+xml")
> public class CollectionsProvider implements MessageBodyWriter<Object> {
> 
>    public boolean isWriteable(...) {return true if Collection }
>    public void writeTo(Object obj, Class<?> cls, Type genericType,
> Annotation[] anns, MediaType m,
>           MultivaluedMap<String, Object> headers, OutputStream os)  throws
> IOException {
> 
>           CollectionElement root =
> AnnotationUtils.getAnnotation(CollectionElement.class, anns);
>           os.write(getStartTag(root));
> 
>           // get class of the first element or use genericType
>           Collection<Object> collection = (Collection<Object>)obj;
>           Class<?> elementClass = ...
>           MessageBodyWriter bodyWriter =
> Providers.getMessageBodyWriter(elementClass, ....);
>           for (Object o : collection) {
>                bodyWriter.writeTo(o, ..., os);
>           }
> 
>           os.write(getEndTag(root));
>    }
> 
> }
> 
> I think this should work seamlessly for all XML-based collections, even those
> not relying on JAXB. I was prototyping it when working
> on 0.8 support but for some reasons I decided not to go ahead then - may be
> there's some flaw above but it appears it should work.

That sounds great.  Would this work for JSON providers as well?  Let me know
if you need help testing or anything.

> We can also make the use of @CollectionElement optional - but then we'd need
> to use some default wrapper element like <result> or
> <collection> which may make the actual xml instance fail the validation on the
> other end. Deducing the namespace from the collection
> elements may end up be too brittle/ineffective or unreliable if it's non-JAXB.
> 
> What do you think ? Let me know please...

I agree that the deduced namespacing may be too brittle in a non-JAXB
environment.  The @CollectionElement sounds good to me.  How would all this
work for non-cxf-based clients?  Do you put a Collection of "any" elements
in the xsd and let them figure it out?

Ideally, I'd like it if enunciate could still generate documentation for me.
I recognize that this may not be realistic.

>> (2) Is there a different spot in the chain where I can put this that would
>> change the objects prior to their being consumed by any providers?  The
>> documentation on the JAX-RS filters wasn't totally clear to me on this
>> point.
> 
> Yes, you can do with CXF out interceptors or JAX-RS response filters or even
> with custom invokers, they all have access to the
> response object. With custom invokers you just wrap the response object as you
> need, for ex see :
> http://svn.apache.org/repos/asf/cxf/trunk/systests/src/test/java/org/apache/cx
> f/systest/jaxrs/CustomJAXRSInvoker.java
> 
> so you do
> 
> return new MyWrapper(super.invoke(...));
> 
> with filters you can do :
> 
> public interface MyResponseHandler {
> 
>     Response handleResponse(Message outputMessage,
>                            OperationResourceInfo invokedOperation,
>                            Response response) {
>            // this method is not minimally effective as you can get
> invokedOperation/response from
>            // outputMessage - but you might need to deal directly with the
> message
>            // 1 - using response
>            ResponseBuilder builder = Response.status(response.getStatus());
>            // next, copy response headers into the builder
>            // finally
>            return builder.entity(new MyWrapper(response.getEntity())).build();
> 
>            // 2. Using message - this can be done in CXF out interceptor too
>            MessageContentsList objs =
> MessageContentsList.getContentsList(message);
> if (objs !== null && objs.size() == 1) {
>     Object responseObj = objs.remove(0);
>     obj.add(new MyWrapper(responseObj));
> }
>     }
> 
> }

I will give that a shot.  It looks like the filters will get me JSON support
as well.  Thanks again for the detailed response.

Thanks,
Dan  



-----
CONFIDENTIALITY NOTICE: The information contained in this message
may be privileged and confidential and protected from disclosure.
 If the reader of this message is not the intended recipient, or
responsible for delivering it to the intended recipient, please
be advised that any distribution, dissemination, copying or other
transmission or use of the information contained in this message
or its enclosed attachments is strictly prohibited.  Please
notify us immediately if you have received this message in error
by replying to the sender of the message and deleting it from
your computer.  Thank you. 
 


Re: Handling Collection returns via JAX-RS

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Dan



> Hi,
>
> I'm writing a JAX-RS app and using CXF as the implementation.  I was having
> trouble wiring up some of my methods -- specifically, one that was to return
> a list of people:
>
> @GET
> @Path("/list")
> List<Person> getPersons();
>
> Trying to run that, I got NPEs, as List can't be written out as a root
> element by default.

There've been quite a few requests recently about supporting explicit collections and I'm committed to fixing it,
I might get a chance to do something around it before CXF 2.2.3 gets released in the end of July or so...If not then it will 
definitely be in 2.3

>
> A lot of the advice that I saw involved adding extra collections, and
> changing the method signature to return the JAXBtized collection wrapper.
> Since this isn't strictly a REST call, this either means that everybody
> using the service call will have to unwrap the collection, or that I will
> have to code two methods every time I want to return a collection.
>
> Instead, I'd like to actually fix this in the providers at the core of CXF.

+1

> I created a collection object of my own:
>
>    <complexType name="Collection">
>        <sequence>
>            <any minOccurs="0" maxOccurs="unbounded"></any>
>        </sequence>
>    </complexType>
>
> ... And then overrode the JAXBElementProvider.writeTo method:
>
> package us.XXXXXXXXX.iotool.jaxrs;
>
> import java.io.IOException;
> import java.io.OutputStream;
> import java.lang.annotation.Annotation;
> import java.lang.reflect.Type;
>
> import javax.ws.rs.WebApplicationException;
> import javax.ws.rs.core.MediaType;
> import javax.ws.rs.core.MultivaluedMap;
>
> import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
>
> import us.XXXXXXXXX.iotool.model.Collection;
>
> public class CollectionJAXBElementProvider extends JAXBElementProvider {
>
> @Override
> public void writeTo(Object obj, Class<?> cls, Type genericType,
>     Annotation[] anns, MediaType m,
>      MultivaluedMap<String, Object> headers, OutputStream os)
>        throws IOException {
> try {
>  Object actualObject = checkAdapter(obj, anns, true);
>  // if it's a java.util.Collection, wrap it in our collection object
>  if (actualObject instanceof java.util.Collection) {
>    us.XXXXXXXXX.iotool.model.Collection collection = new Collection();
>    java.util.List list  =
>      new java.util.ArrayList<Object>((java.util.Collection)actualObject);
>    collection.setAnies(list);
>    actualObject = collection;
>  }
>
>  // now pass to the superclass
>  super.writeTo(actualObject, cls, genericType, anns, m, headers, os);
>  }  catch (WebApplicationException e) {
>   throw e;
>  } catch (Exception e) {
>   throw new WebApplicationException(e);
>  }
> }
>
> }
>
>
> This works fine -- any java.util.Collection will get wrapped in a
> <Collection> tag.

interesting solution...

>
> There are a couple of downsides here:
>
> (1) Doing it in this provider means that it doesn't apply to my JSON
> provider.
> (2) I don't think that I have a great way to consume this on the client side
> as anything other than a wrapped collection (if that even works).
>
> Two sets of questions:
> (1) Can I get to my desired end -- transparently handling
> java.util.Collection objects -- without all this mucking about?  Can I do
> this with a XmlJavaTypeAdapter?

I've been thinking about introducing a @CollectionElement annotation and a Collections message body writer :

@CollectionElement(name="persons", ns=http://persons)
List<Person> getPersons() {}

MessageBodyWriters get the method annotations passed to it, so :

Produces("application/xml, text/xml, application/*+xml")
public class CollectionsProvider implements MessageBodyWriter<Object> {

   public boolean isWriteable(...) {return true if Collection }
   public void writeTo(Object obj, Class<?> cls, Type genericType,  Annotation[] anns, MediaType m,
          MultivaluedMap<String, Object> headers, OutputStream os)  throws IOException {

          CollectionElement root = AnnotationUtils.getAnnotation(CollectionElement.class, anns);
          os.write(getStartTag(root));

          // get class of the first element or use genericType
          Collection<Object> collection = (Collection<Object>)obj;
          Class<?> elementClass = ...
          MessageBodyWriter bodyWriter = Providers.getMessageBodyWriter(elementClass, ....);
          for (Object o : collection) {
               bodyWriter.writeTo(o, ..., os);
          }

          os.write(getEndTag(root));
   }

}

I think this should work seamlessly for all XML-based collections, even those not relying on JAXB. I was prototyping it when working 
on 0.8 support but for some reasons I decided not to go ahead then - may be there's some flaw above but it appears it should work.

We can also make the use of @CollectionElement optional - but then we'd need to use some default wrapper element like <result> or 
<collection> which may make the actual xml instance fail the validation on the other end. Deducing the namespace from the collection 
elements may end up be too brittle/ineffective or unreliable if it's non-JAXB.

What do you think ? Let me know please...

>
> (2) Is there a different spot in the chain where I can put this that would
> change the objects prior to their being consumed by any providers?  The
> documentation on the JAX-RS filters wasn't totally clear to me on this
> point.

Yes, you can do with CXF out interceptors or JAX-RS response filters or even with custom invokers, they all have access to the 
response object. With custom invokers you just wrap the response object as you need, for ex see :
http://svn.apache.org/repos/asf/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/CustomJAXRSInvoker.java

so you do

return new MyWrapper(super.invoke(...));

with filters you can do :

public interface MyResponseHandler {

    Response handleResponse(Message outputMessage,
                           OperationResourceInfo invokedOperation,
                           Response response) {
           // this method is not minimally effective as you can get invokedOperation/response from
           // outputMessage - but you might need to deal directly with the message
           // 1 - using response
           ResponseBuilder builder = Response.status(response.getStatus());
           // next, copy response headers into the builder
           // finally
           return builder.entity(new MyWrapper(response.getEntity())).build();

           // 2. Using message - this can be done in CXF out interceptor too
           MessageContentsList objs = MessageContentsList.getContentsList(message);
if (objs !== null && objs.size() == 1) {
    Object responseObj = objs.remove(0);
    obj.add(new MyWrapper(responseObj));
}
    }

}


cheers, Sergey


>
> Thanks in advance,
> Dan
>
>
> -----
> CONFIDENTIALITY NOTICE: The information contained in this message
> may be privileged and confidential and protected from disclosure.
> If the reader of this message is not the intended recipient, or
> responsible for delivering it to the intended recipient, please
> be advised that any distribution, dissemination, copying or other
> transmission or use of the information contained in this message
> or its enclosed attachments is strictly prohibited.  Please
> notify us immediately if you have received this message in error
> by replying to the sender of the message and deleting it from
> your computer.  Thank you.
>
>
>