You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Vassilis Virvilis <v....@biovista.com> on 2014/08/12 17:12:06 UTC

registering ParamConverterProviders with cxf

Hi,

Some time before I have started a thread with jackson and form 
parameters in cxf
http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E

Sergey suggested that I should use ParamConverterProvider.

I tried it today and it worked. Great.

Now I am trying the next step which is to pass List<Entity> instead of 
Entity in the input. The problem is that my ParamConverterProvider is 
not called with the actual input class as specified in the interface 
(List<Entity>) but with plain Entity as you can see from the logs. It 
then fails because due to
		*** Can not deserialize instance of com.biovista.lib.datatype.Entity 
out of START_ARRAY token ****

INFO 
com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41): 
**** called: arg0: class com.biovista.lib.datatype.Entity arg1: class 
com.biovista.lib.datatype.Entity arg2: 
[Ljava.lang.annotation.Annotation;@7f65ae66 providers: 
org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
INFO 
com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44): 
Annotation: @javax.ws.rs.FormParam(value=entities)

Here is my ParamConverterProvider


package com.biovista.ws.impl.jaxrs;

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

import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.Providers;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.codehaus.jackson.map.ObjectMapper;

@Provider
public class JacksonJsonParamConverterProvider implements 
ParamConverterProvider {
     private final Log log = LogFactory.getLog(getClass());

     @Override
     public <T> ParamConverter<T> getConverter(final Class<T> rawType,
             final Type genericType, final Annotation[] annotations) {

         log.info("**** called: arg0: " + rawType + " arg1: " + genericType
                 + " arg2: " + annotations + " providers: " + providers);
         for (final Annotation annotation : annotations) {
             log.info("Annotation: " + annotation);
         }

         return new ParamConverter<T>() {
             @Override
             public T fromString(final String value) {
                 try {
                     log.info("Called for " + value);
                     return mapper.reader(rawType).readValue(value);
                 } catch(IOException e) {
                     throw new ProcessingException(e);
                 }
             }

             @Override
             public String toString(final T value) {
                 try {
                     return mapper.writer().writeValueAsString(value);
                 } catch(Exception e) {
                     throw new ProcessingException(e);
                 }
             }
         };
     }
}


How can I register different ParamConverterProvider for different input 
types? Or is that List is handled specially? By jackson or CXF? In 
jackson I just need to do
         final List<Entity> entities = mapper.readValue(entities_json,
             new TypeReference<List<Entity>>() {
             });

but I don't know how to do this from inside CXF. I am using CXF 3.0

     Thanks
-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
I've got a confirmation CXF does it the same way as Jersey so I think 
CXF is compliant.

Thanks, Sergey
On 14/08/14 09:49, Sergey Beryozkin wrote:
> Hi
> On 14/08/14 08:42, Vassilis Virvilis wrote:
>> On 08/14/2014 09:34 AM, Vassilis Virvilis wrote:
>>> Hi,
>>>
>>>
>>> Hope this clears it up. I will take now a read on the spec and I will
>>> follow up if I spot anything.
>>>
>>
>>
>> I opened up an issue with Resty-GWT at
>> https://github.com/resty-gwt/resty-gwt/issues/195
>> I am not an expert but looks like that CXF is per JAX-RS spec and
>> Resty-GWT isn't.
> It's Ok for a given client framework to use a single parameter to convey
> a JSON array if it chooses so, nothing non-RESTful about it, it's not
> expected to fit cleanly into a JAX-RS API to do with converting
> individual parameters.
>
> Does Resty-Gwt requires to have a List<Entity> signature ? Would it work
> if you replace List<Entity> with
> class EntityWrapper {
>      List<Entity> entities;
> }
>
> If yes, then just introduce it and never look back to this issue again
> :-), have EntityWrapper in the method signature and have a
> ParamConverter<EntityWrapper>.
>
> That said, we'd need to make sure CXF is compliant (even though I'd
> prefer a wrapper any time), I'm honestly hoping 'yes' but my
> interpretation of how it should work may differ from the formal line.
>
> Can you please subscribe to jaxrs users list and reply to the message I
> posted yesterday titled "ParamConverter and Collections" with more
> feedback ?
>
> Cheers, Sergey
>
>>
>> Thanks
>>
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
Hi,

On 08/14/2014 11:49 AM, Sergey Beryozkin wrote:
> Hi
> On 14/08/14 08:42, Vassilis Virvilis wrote:
>> On 08/14/2014 09:34 AM, Vassilis Virvilis wrote:
>>> Hi,
>>>
>>>
>>> Hope this clears it up. I will take now a read on the spec and I will
>>> follow up if I spot anything.
>>>
>>
>>
>> I opened up an issue with Resty-GWT at
>> https://github.com/resty-gwt/resty-gwt/issues/195
>> I am not an expert but looks like that CXF is per JAX-RS spec and
>> Resty-GWT isn't.
> It's Ok for a given client framework to use a single parameter to convey
> a JSON array if it chooses so, nothing non-RESTful about it, it's not
> expected to fit cleanly into a JAX-RS API to do with converting
> individual parameters.
>
> Does Resty-Gwt requires to have a List<Entity> signature ? Would it work
> if you replace List<Entity> with
> class EntityWrapper {
>      List<Entity> entities;
> }
>
> If yes, then just introduce it and never look back to this issue again
> :-), have EntityWrapper in the method signature and have a
> ParamConverter<EntityWrapper>.
>

I believe it would work. However I am reluctant to do it because I am 
porting (would like to port) a rather biggish API and frankly I think 
this EntityListWrapper is just pollution of my code base.

That said I will do it if I have to but I 'd just prefer not too.

> That said, we'd need to make sure CXF is compliant (even though I'd
> prefer a wrapper any time), I'm honestly hoping 'yes' but my
> interpretation of how it should work may differ from the formal line.
>
> Can you please subscribe to jaxrs users list and reply to the message I
> posted yesterday titled "ParamConverter and Collections" with more
> feedback ?
>

I will give it a try...

-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi
On 14/08/14 08:42, Vassilis Virvilis wrote:
> On 08/14/2014 09:34 AM, Vassilis Virvilis wrote:
>> Hi,
>>
>>
>> Hope this clears it up. I will take now a read on the spec and I will
>> follow up if I spot anything.
>>
>
>
> I opened up an issue with Resty-GWT at
> https://github.com/resty-gwt/resty-gwt/issues/195
> I am not an expert but looks like that CXF is per JAX-RS spec and
> Resty-GWT isn't.
It's Ok for a given client framework to use a single parameter to convey 
a JSON array if it chooses so, nothing non-RESTful about it, it's not 
expected to fit cleanly into a JAX-RS API to do with converting 
individual parameters.

Does Resty-Gwt requires to have a List<Entity> signature ? Would it work 
if you replace List<Entity> with
class EntityWrapper {
     List<Entity> entities;
}

If yes, then just introduce it and never look back to this issue again 
:-), have EntityWrapper in the method signature and have a 
ParamConverter<EntityWrapper>.

That said, we'd need to make sure CXF is compliant (even though I'd 
prefer a wrapper any time), I'm honestly hoping 'yes' but my 
interpretation of how it should work may differ from the formal line.

Can you please subscribe to jaxrs users list and reply to the message I 
posted yesterday titled "ParamConverter and Collections" with more 
feedback ?

Cheers, Sergey

>
> Thanks
>


Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
On 08/14/2014 09:34 AM, Vassilis Virvilis wrote:
> Hi,
>
>
> Hope this clears it up. I will take now a read on the spec and I will
> follow up if I spot anything.
>


I opened up an issue with Resty-GWT at 
https://github.com/resty-gwt/resty-gwt/issues/195
I am not an expert but looks like that CXF is per JAX-RS spec and 
Resty-GWT isn't.

Thanks

-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
Hi,

I just found on RestyGWT sources and verified with tests that handles 
correctly the @QueryParam case but not the @FormParam case. So I believe 
this concludes it unless the standard handles differently @QueryParam 
from @FormParam.

I will try to raise the issue with RestyGWT 
(https://github.com/resty-gwt/resty-gwt/issues/195) and eventually 
submit a fix.

    Thanks

On 08/14/2014 03:35 PM, Vassilis Virvilis wrote:
> On 08/14/2014 11:37 AM, Sergey Beryozkin wrote:
>
>> No problems at all, thanks for the clarifications. It's a bit of a grey
>> area, and I actually sent a message to the JAX-RS group to clarify. You
>> may well be right in the end :-). It's just a bit of a sensitive area, a
>> non-compliance will be addressed immediately if confirmed, but we need a
>> clear statement in the API docs or a message from a spec lead, etc.
>>
>
> My take on this from the admittedly superficial reading of the spec is
> that CXF is right and Resty-GWT is wrong. For the cases of List, Set,
> SortedSet (and their descendants?) the list argument must be broken in
> multiple params with the same name. All others Map, HashMap,
> (even Collections? CXF treats Collection as a List which makes sense of
> course) are fair game and the client can put the payload as he wants it.
>
> Of course I may be wrong. Won't be the first time...
>
>     Vassilis
>
>

-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
On 08/14/2014 11:37 AM, Sergey Beryozkin wrote:

> No problems at all, thanks for the clarifications. It's a bit of a grey
> area, and I actually sent a message to the JAX-RS group to clarify. You
> may well be right in the end :-). It's just a bit of a sensitive area, a
> non-compliance will be addressed immediately if confirmed, but we need a
> clear statement in the API docs or a message from a spec lead, etc.
>

My take on this from the admittedly superficial reading of the spec is 
that CXF is right and Resty-GWT is wrong. For the cases of List, Set, 
SortedSet (and their descendants?) the list argument must be broken in 
multiple params with the same name. All others Map, HashMap,
(even Collections? CXF treats Collection as a List which makes sense of 
course) are fair game and the client can put the payload as he wants it.

Of course I may be wrong. Won't be the first time...

    Vassilis


-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Vassilis
On 14/08/14 07:34, Vassilis Virvilis wrote:
> Hi,
>
> On 08/13/2014 06:43 PM, Sergey Beryozkin wrote:
>> On 13/08/14 15:43, Vassilis Virvilis wrote:
>>> This however transmits the entities as one jsonified array with [{x:"a",
>>> y:"b"}, {x:"c", y:"d"}] if you know what I mean. CXF in the other
>>> doesn't parse it as per  JAX-RS spec probably but I am not sure. So what
>>> are the options?
>>>
>> What exactly doe it this mean :-) ? I.e, why are you making the
>> statement that CXF does not follow the spec ? I've no problems with
>> users pointing out to such issues, the more of them discovered the
>> better, but I haven't seen anything so far in this case that proves CXF
>> does not follow the spec
>>
>
>
> I have to apologize about that. This is not what I meant to say at all.
>
> What I mean was: RestyGWT and CXF differ on how they put/expect the
> @FormParam argument when there is a List involved. I tried to say (but
> failed) that CXF probably __follows__ JAX-RS hence the difference but I
> am not 100% certain. Why I am not 100% certain? Because I don't know the
> spec but I know from all these years lurking on this list that CXF takes
> the W3 standards and interoperability very seriously and strives to
> fulfill them.
>
> Hope this clears it up. I will take now a read on the spec and I will
> follow up if I spot anything.
>
No problems at all, thanks for the clarifications. It's a bit of a grey 
area, and I actually sent a message to the JAX-RS group to clarify. You 
may well be right in the end :-). It's just a bit of a sensitive area, a 
non-compliance will be addressed immediately if confirmed, but we need a 
clear statement in the API docs or a message from a spec lead, etc.

Thanks, Sergey

>       Vassilis
>
> __________________________________
>
> Vassilis Virvilis Ph.D.
> Head of IT
> Biovista Inc.
>
> US Offices
> 2421 Ivy Road
> Charlottesville, VA 22903
> USA
> T: +1.434.971.1141
> F: +1.434.971.1144
>
> European Offices
> 34 Rodopoleos Street
> Ellinikon, Athens 16777
> GREECE
> T: +30.210.9629848
> F: +30.210.9647606
>
> www.biovista.com
>
> Biovista is a privately held biotechnology company that finds novel uses
> for existing drugs, and profiles their side effects using their
> mechanism of action. Biovista develops its own pipeline of drugs in CNS,
> oncology, auto-immune and rare diseases. Biovista is collaborating with
> biopharmaceutical companies on indication expansion and de-risking of
> their portfolios and with the FDA on adverse event prediction.
>
>


Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
Hi,

On 08/13/2014 06:43 PM, Sergey Beryozkin wrote:
> On 13/08/14 15:43, Vassilis Virvilis wrote:
>> This however transmits the entities as one jsonified array with [{x:"a",
>> y:"b"}, {x:"c", y:"d"}] if you know what I mean. CXF in the other
>> doesn't parse it as per  JAX-RS spec probably but I am not sure. So what
>> are the options?
>>
> What exactly doe it this mean :-) ? I.e, why are you making the
> statement that CXF does not follow the spec ? I've no problems with
> users pointing out to such issues, the more of them discovered the
> better, but I haven't seen anything so far in this case that proves CXF
> does not follow the spec
>


I have to apologize about that. This is not what I meant to say at all.

What I mean was: RestyGWT and CXF differ on how they put/expect the 
@FormParam argument when there is a List involved. I tried to say (but 
failed) that CXF probably __follows__ JAX-RS hence the difference but I 
am not 100% certain. Why I am not 100% certain? Because I don't know the 
spec but I know from all these years lurking on this list that CXF takes 
the W3 standards and interoperability very seriously and strives to 
fulfill them.

Hope this clears it up. I will take now a read on the spec and I will 
follow up if I spot anything.

      Vassilis

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
On 13/08/14 15:43, Vassilis Virvilis wrote:
> Ok
>
> I made some progress and in the mean time I understood some of the
> things you have been saying... I think the following descriptions
> summarizes my status. I have also asked for help from resty-gwt forum. I
> will let you know what comes up...
>
> Thanks for the help so far. Much apprecieated...
>
> https://groups.google.com/forum/#!topic/restygwt/T98XXEHiCl0
>
>
> Hi everybody,
>
> Here are some must do reading that I found...
> http://stackoverflow.com/questions/3182033/pass-list-to-restful-webservice
> https://github.com/resty-gwt/resty-gwt/issues/92
>
> So what I am trying to do? Basically this.
>
>      @POST
>      @Path("existing-entities")
>      @Consumes("application/x-www-form-urlencoded")
>      public void getExistingEntities(
>              @FormParam("entities") List<Entity> entities,
>              MethodCallback<List<Entity>> callback);
>
> This however transmits the entities as one jsonified array with [{x:"a",
> y:"b"}, {x:"c", y:"d"}] if you know what I mean. CXF in the other
> doesn't parse it as per  JAX-RS spec probably but I am not sure. So what
> are the options?
>
What exactly doe it this mean :-) ? I.e, why are you making the 
statement that CXF does not follow the spec ? I've no problems with 
users pointing out to such issues, the more of them discovered the 
better, but I haven't seen anything so far in this case that proves CXF 
does not follow the spec

Thanks, Sergey


> 1) Use a list wrapper. Ugly and as I said I am porting existing services
> and I don't feel like filling my sources with useless wrapper classes.
> Never mind the changes to the clients of the services. This is my last
> option. I will do that when all else fail.
>
> 2) Don't use @FormParam. This actually works
>
>      @POST
>      @Path("existing-entities")
>      public void getExistingEntities(
>              List<Entity> entities,
>              MethodCallback<List<Entity>> callback);
>
> This puts the payload to MessageBody.
> The disadvantage is that you can send only one list this way. As I said
> previously I am porting... and there are cases that I need to transmit 2
> or more lists as input parameters.
>
> 3) Third option and here I may need some help. If you actually post a
> form with the same option name CXF (and probably Jersey) puts it in a
> list. I have verified with curl
>
>        curl --data 'entities=`urlencode {x:"a",
> y:"b"}`&entities=`urlencode {x:"c", y:"d"}`'
> http://localhost/ws/rest/v1/ported/existing-entities -H 'Accept:
> application/json'
>
> and it works. So what I need is a way to teach Resty-GWT to do that kind
> of form posting and not the entities: [{x:"a", y:"b"}, {x:"c", y:"d"}]
> thingy when encounters
>
>      @POST
>      @Path("existing-entities")
>      @Consumes("application/x-www-form-urlencoded")
>      public void getExistingEntities(
>              @FormParam("entities") List<Entity> entities,
>              MethodCallback<List<Entity>> callback);
>
> I suppose I have to use a custom MessageBodyWriter in the client side.
> Is this possible in resty-gwt? I don't mind mucking with resty-gwt
> source but I don't know from where to start. Any ideas?
>
>     Thanks in advance.
>
>
>
> On 08/12/2014 10:23 PM, Sergey Beryozkin wrote:
>> Hi,
>> On 12/08/14 19:44, v.virvilis@biovista.com wrote:
>>> Hi Sergey,
>>>
>>> First of all thanks for your prompt reply as always. Your help is
>>> appreciated.
>>>
>>> Secondly, I am sorry I didn't explain the situation more clearly. I am a
>>> bit frustrated with this... as always when things don't work as we
>>> expect them too. It is quite probable that I lack the necessary
>>> understanding to make things work.
>>>
>>> Now to the problem.
>>>
>>> I have GWT and Resty-GWT into the client. RestyGWT requires jackson and
>>> so I have to use jackson and not jettinson in the server part where I
>>> have CXF.
>>>
>>> In the client I jave something like this
>>>
>>>      @POST
>>>      @Path("existing-entities")
>>>      @Consumes("application/x-www-form-urlencoded")
>>>      public void getExistingEntities(
>>>              @FormParam("entities") List<Entity> entities,
>>>              MethodCallback<List<Entity>> callback);
>>>
>>> In the server I have
>>>
>>>      @POST
>>>      @Path("existing-entities")
>>>      @Consumes("application/x-www-form-urlencoded")
>>>      public List<Entity> getExistingEntities(
>>>              @FormParam("entities") List<Entity> entities) throws
>>> SQLException;
>>>
>>>
>>> When I issue the call from the client with two entities: I get in the
>>> form contents. This is done by resty-gwt:
>>> entities: [{"name":"cca1", "type":"GENE"},{"name":"cca2",
>>> "type":"GENE"}]
>>>
>>> which is a JSONArray payload.
>>>
>>> What cxf does is to take the full json string and trying to shovel it
>>> down the throat of my poor ParamConverter as entity and not as
>>> List<Entity>.
>>>
>> as I explained earlier with the example of a query containing multipal
>> parameters of the same name, ParamConverterProvider deals with the
>> individual parameters such as Entity in your case
>>
>>> I am not getting it. I think CXF either should break the array and call
>>> the converter for each object or it should leave the converter to
>>> convert the array. Now it is not breaking it but it doesn't give me the
>>> option to handle the array,
>>
>> How exactly would CXF or indeed any other generic framework break this
>> JSON Array ? It won't. It has no idea about the semantics associated
>> with a given parameter.
>>
>> You were right earlier on, just introduce a wrapper and forget about
>> mapping it to the explicit collection :-). Explicit collections just
>> make things more complicated unless there's an obvious/straightforward
>> mapping as in the example I provided earlier on.
>>
>> Thanks, Sergey
>>
>>>
>>> INFO
>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>
>>>
>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>>> com.biovista.lib.datatype.Entity arg2:
>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>> INFO
>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>
>>>
>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>> INFO
>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider$1.fromString(JacksonJsonParamConverterProvider.java:71):
>>>
>>>
>>> Called for [{"name":"cca1", "type":"
>>> GENE"},{"name":"cca2", "type":"GENE"}]
>>> WARN 2014-08-12 17:47:46,722 http-bio-8081-exec-197:
>>> org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:452):
>>> Interceptor for {http://impl.ws.biovista.com/}VizitService has thrown
>>> exception, unwinding now javax.ws.rs.ProcessingException:
>>> org.codehaus.jackson.map.JsonMappingException: Can not deserialize
>>> instance of com.biovista.lib.datatype.Entity out of START_ARRAY token
>>>
>>> Now what do you think I should do in order to send complex types and
>>> collections to the server from the client?
>>>
>>> About Jersey - I don't know I have never used it. I am not sure how I
>>> should research it. In theory everything works. In practice you get to
>>> see the weird corner cases.
>>>
>>> I am not 100% sure but I believe the opposite way (cxf to send
>>> List<Entity>) works as expected. I will test and report tomorrow.
>>>
>>> Again thanks for the patience.
>>>
>>>
>>> On 2014-08-12 12:17, Sergey Beryozkin wrote:
>>>> On 12/08/14 17:13, Sergey Beryozkin wrote:
>>>>> Sorry, do not understand what you are trying to do.
>>>>>
>>>>> Why do you use a single parameter (query, header, or may be form) to
>>>>> send a JSON array ? This is typically sent as a message body, in which
>>>>> case JAX-RS MessageBodyReader takes care of it.
>>>>>
>>>>> Imagine this case:
>>>>>
>>>>> ?a=1-2-3&a=4-5-6
>>>>>
>>>>> here we have 2 'a' query parameters, one with value "1-2-3" and
>>>>> another
>>>>> - with "4-5-6"
>>>>>
>>>>> and we have this signature:
>>>>>
>>>>> Response get(@QueryParam("a") List<Integer> list);
>>>>>
>>>>> In this case we convert each parameter to Integer (the converter would
>>>>> remove '-'), the runtime takes case of creating a List.
>>>>> If we expected the converter to convert a String to List<Integer> then
>>>>> what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and
>>>>> expect it to parse it manually ? Not sure it makes sense.
>>>>
>>>> And given that ParamConverterProvider is expected to be reusable, what
>>>> would we do with
>>>>
>>>> and a sequence like
>>>>
>>>> /path;a=1-2-3;a=4-5-6
>>>> Response get(@MatrixParam("a") List<Integer> list);
>>>>
>>>> the converter would have to parse both
>>>> "a=1-2-3&a=4-5-6" and "a=1-2-3;a=4-5-6"
>>>>
>>>> IMHO it is not how it should work, but please do not hesitate to
>>>> investigate it further with Jersey
>>>>
>>>> Cheers, Sergey
>>>>
>>>>>
>>>>> Can you investigate what Jersey does ? I'm pretty sure it was
>>>>> discussed,
>>>>> specifically that the runtime should take care of dealing with the
>>>>> list
>>>>> itself, but they might deal with it differently
>>>>>
>>>>> Cheers, Sergey
>>>>>
>>>>>
>>>>>
>>>>> On 12/08/14 16:45, Vassilis Virvilis wrote:
>>>>>> Aah,
>>>>>>
>>>>>> So in order to make this work through CXF is to define an
>>>>>> EntitiesListWrapper class. Right? Then the ParamConverter will be
>>>>>> called
>>>>>> with EntitiesListWrapper as argument and jackson will deserialize.
>>>>>> Right?
>>>>>>
>>>>>> Is there any other way to break the input of
>>>>>>              final String entities_json = "[{\"name\":\"cca1\",
>>>>>> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
>>>>>> so the paramconverter will be called with the correct substring each
>>>>>> time?
>>>>>>
>>>>>> This looks weird.
>>>>>>
>>>>>>      Vassilis
>>>>>>
>>>>>>
>>>>>> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>>>>>>> Hi
>>>>>>>
>>>>>>> AFAIK ParamConverterProvider is expected to be called once per every
>>>>>>> entity in the list.
>>>>>>>
>>>>>>> Thanks, Sergey
>>>>>>>
>>>>>>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Some time before I have started a thread with jackson and form
>>>>>>>> parameters in cxf
>>>>>>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Sergey suggested that I should use ParamConverterProvider.
>>>>>>>>
>>>>>>>> I tried it today and it worked. Great.
>>>>>>>>
>>>>>>>> Now I am trying the next step which is to pass List<Entity>
>>>>>>>> instead of
>>>>>>>> Entity in the input. The problem is that my
>>>>>>>> ParamConverterProvider is
>>>>>>>> not called with the actual input class as specified in the
>>>>>>>> interface
>>>>>>>> (List<Entity>) but with plain Entity as you can see from the
>>>>>>>> logs. It
>>>>>>>> then fails because due to
>>>>>>>>          *** Can not deserialize instance of
>>>>>>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>>>>>>
>>>>>>>> INFO
>>>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1:
>>>>>>>> class
>>>>>>>> com.biovista.lib.datatype.Entity arg2:
>>>>>>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>>>>>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>>>>>>> INFO
>>>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>>>>>>
>>>>>>>> Here is my ParamConverterProvider
>>>>>>>>
>>>>>>>>
>>>>>>>> package com.biovista.ws.impl.jaxrs;
>>>>>>>>
>>>>>>>> import java.io.IOException;
>>>>>>>> import java.lang.annotation.Annotation;
>>>>>>>> import java.lang.reflect.Type;
>>>>>>>>
>>>>>>>> import javax.ws.rs.ProcessingException;
>>>>>>>> import javax.ws.rs.core.Context;
>>>>>>>> import javax.ws.rs.core.MediaType;
>>>>>>>> import javax.ws.rs.ext.ContextResolver;
>>>>>>>> import javax.ws.rs.ext.MessageBodyReader;
>>>>>>>> import javax.ws.rs.ext.ParamConverter;
>>>>>>>> import javax.ws.rs.ext.ParamConverterProvider;
>>>>>>>> import javax.ws.rs.ext.Provider;
>>>>>>>> import javax.ws.rs.ext.Providers;
>>>>>>>>
>>>>>>>> import org.apache.commons.logging.Log;
>>>>>>>> import org.apache.commons.logging.LogFactory;
>>>>>>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>>>>>>> import org.codehaus.jackson.map.ObjectMapper;
>>>>>>>>
>>>>>>>> @Provider
>>>>>>>> public class JacksonJsonParamConverterProvider implements
>>>>>>>> ParamConverterProvider {
>>>>>>>>      private final Log log = LogFactory.getLog(getClass());
>>>>>>>>
>>>>>>>>      @Override
>>>>>>>>      public <T> ParamConverter<T> getConverter(final Class<T>
>>>>>>>> rawType,
>>>>>>>>              final Type genericType, final Annotation[]
>>>>>>>> annotations) {
>>>>>>>>
>>>>>>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>>>>>>> genericType
>>>>>>>>                  + " arg2: " + annotations + " providers: " +
>>>>>>>> providers);
>>>>>>>>          for (final Annotation annotation : annotations) {
>>>>>>>>              log.info("Annotation: " + annotation);
>>>>>>>>          }
>>>>>>>>
>>>>>>>>          return new ParamConverter<T>() {
>>>>>>>>              @Override
>>>>>>>>              public T fromString(final String value) {
>>>>>>>>                  try {
>>>>>>>>                      log.info("Called for " + value);
>>>>>>>>                      return
>>>>>>>> mapper.reader(rawType).readValue(value);
>>>>>>>>                  } catch(IOException e) {
>>>>>>>>                      throw new ProcessingException(e);
>>>>>>>>                  }
>>>>>>>>              }
>>>>>>>>
>>>>>>>>              @Override
>>>>>>>>              public String toString(final T value) {
>>>>>>>>                  try {
>>>>>>>>                      return
>>>>>>>> mapper.writer().writeValueAsString(value);
>>>>>>>>                  } catch(Exception e) {
>>>>>>>>                      throw new ProcessingException(e);
>>>>>>>>                  }
>>>>>>>>              }
>>>>>>>>          };
>>>>>>>>      }
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> How can I register different ParamConverterProvider for different
>>>>>>>> input
>>>>>>>> types? Or is that List is handled specially? By jackson or CXF? In
>>>>>>>> jackson I just need to do
>>>>>>>>          final List<Entity> entities =
>>>>>>>> mapper.readValue(entities_json,
>>>>>>>>              new TypeReference<List<Entity>>() {
>>>>>>>>              });
>>>>>>>>
>>>>>>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>>>>>>
>>>>>>>>      Thanks
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>
>>
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
Ok

I made some progress and in the mean time I understood some of the 
things you have been saying... I think the following descriptions 
summarizes my status. I have also asked for help from resty-gwt forum. I 
will let you know what comes up...

Thanks for the help so far. Much apprecieated...

https://groups.google.com/forum/#!topic/restygwt/T98XXEHiCl0


Hi everybody,

Here are some must do reading that I found...
http://stackoverflow.com/questions/3182033/pass-list-to-restful-webservice
https://github.com/resty-gwt/resty-gwt/issues/92

So what I am trying to do? Basically this.

     @POST
     @Path("existing-entities")
     @Consumes("application/x-www-form-urlencoded")
     public void getExistingEntities(
             @FormParam("entities") List<Entity> entities,
             MethodCallback<List<Entity>> callback);

This however transmits the entities as one jsonified array with [{x:"a", 
y:"b"}, {x:"c", y:"d"}] if you know what I mean. CXF in the other 
doesn't parse it as per  JAX-RS spec probably but I am not sure. So what 
are the options?

1) Use a list wrapper. Ugly and as I said I am porting existing services 
and I don't feel like filling my sources with useless wrapper classes. 
Never mind the changes to the clients of the services. This is my last 
option. I will do that when all else fail.

2) Don't use @FormParam. This actually works

     @POST
     @Path("existing-entities")
     public void getExistingEntities(
             List<Entity> entities,
             MethodCallback<List<Entity>> callback);

This puts the payload to MessageBody.
The disadvantage is that you can send only one list this way. As I said 
previously I am porting... and there are cases that I need to transmit 2 
or more lists as input parameters.

3) Third option and here I may need some help. If you actually post a 
form with the same option name CXF (and probably Jersey) puts it in a 
list. I have verified with curl

       curl --data 'entities=`urlencode {x:"a", 
y:"b"}`&entities=`urlencode {x:"c", y:"d"}`' 
http://localhost/ws/rest/v1/ported/existing-entities -H 'Accept: 
application/json'

and it works. So what I need is a way to teach Resty-GWT to do that kind 
of form posting and not the entities: [{x:"a", y:"b"}, {x:"c", y:"d"}] 
thingy when encounters

     @POST
     @Path("existing-entities")
     @Consumes("application/x-www-form-urlencoded")
     public void getExistingEntities(
             @FormParam("entities") List<Entity> entities,
             MethodCallback<List<Entity>> callback);

I suppose I have to use a custom MessageBodyWriter in the client side. 
Is this possible in resty-gwt? I don't mind mucking with resty-gwt 
source but I don't know from where to start. Any ideas?

    Thanks in advance.



On 08/12/2014 10:23 PM, Sergey Beryozkin wrote:
> Hi,
> On 12/08/14 19:44, v.virvilis@biovista.com wrote:
>> Hi Sergey,
>>
>> First of all thanks for your prompt reply as always. Your help is
>> appreciated.
>>
>> Secondly, I am sorry I didn't explain the situation more clearly. I am a
>> bit frustrated with this... as always when things don't work as we
>> expect them too. It is quite probable that I lack the necessary
>> understanding to make things work.
>>
>> Now to the problem.
>>
>> I have GWT and Resty-GWT into the client. RestyGWT requires jackson and
>> so I have to use jackson and not jettinson in the server part where I
>> have CXF.
>>
>> In the client I jave something like this
>>
>>      @POST
>>      @Path("existing-entities")
>>      @Consumes("application/x-www-form-urlencoded")
>>      public void getExistingEntities(
>>              @FormParam("entities") List<Entity> entities,
>>              MethodCallback<List<Entity>> callback);
>>
>> In the server I have
>>
>>      @POST
>>      @Path("existing-entities")
>>      @Consumes("application/x-www-form-urlencoded")
>>      public List<Entity> getExistingEntities(
>>              @FormParam("entities") List<Entity> entities) throws
>> SQLException;
>>
>>
>> When I issue the call from the client with two entities: I get in the
>> form contents. This is done by resty-gwt:
>> entities: [{"name":"cca1", "type":"GENE"},{"name":"cca2", "type":"GENE"}]
>>
>> which is a JSONArray payload.
>>
>> What cxf does is to take the full json string and trying to shovel it
>> down the throat of my poor ParamConverter as entity and not as
>> List<Entity>.
>>
> as I explained earlier with the example of a query containing multipal
> parameters of the same name, ParamConverterProvider deals with the
> individual parameters such as Entity in your case
>
>> I am not getting it. I think CXF either should break the array and call
>> the converter for each object or it should leave the converter to
>> convert the array. Now it is not breaking it but it doesn't give me the
>> option to handle the array,
>
> How exactly would CXF or indeed any other generic framework break this
> JSON Array ? It won't. It has no idea about the semantics associated
> with a given parameter.
>
> You were right earlier on, just introduce a wrapper and forget about
> mapping it to the explicit collection :-). Explicit collections just
> make things more complicated unless there's an obvious/straightforward
> mapping as in the example I provided earlier on.
>
> Thanks, Sergey
>
>>
>> INFO
>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>
>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>> com.biovista.lib.datatype.Entity arg2:
>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>> INFO
>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>
>> Annotation: @javax.ws.rs.FormParam(value=entities)
>> INFO
>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider$1.fromString(JacksonJsonParamConverterProvider.java:71):
>>
>> Called for [{"name":"cca1", "type":"
>> GENE"},{"name":"cca2", "type":"GENE"}]
>> WARN 2014-08-12 17:47:46,722 http-bio-8081-exec-197:
>> org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:452):
>> Interceptor for {http://impl.ws.biovista.com/}VizitService has thrown
>> exception, unwinding now javax.ws.rs.ProcessingException:
>> org.codehaus.jackson.map.JsonMappingException: Can not deserialize
>> instance of com.biovista.lib.datatype.Entity out of START_ARRAY token
>>
>> Now what do you think I should do in order to send complex types and
>> collections to the server from the client?
>>
>> About Jersey - I don't know I have never used it. I am not sure how I
>> should research it. In theory everything works. In practice you get to
>> see the weird corner cases.
>>
>> I am not 100% sure but I believe the opposite way (cxf to send
>> List<Entity>) works as expected. I will test and report tomorrow.
>>
>> Again thanks for the patience.
>>
>>
>> On 2014-08-12 12:17, Sergey Beryozkin wrote:
>>> On 12/08/14 17:13, Sergey Beryozkin wrote:
>>>> Sorry, do not understand what you are trying to do.
>>>>
>>>> Why do you use a single parameter (query, header, or may be form) to
>>>> send a JSON array ? This is typically sent as a message body, in which
>>>> case JAX-RS MessageBodyReader takes care of it.
>>>>
>>>> Imagine this case:
>>>>
>>>> ?a=1-2-3&a=4-5-6
>>>>
>>>> here we have 2 'a' query parameters, one with value "1-2-3" and another
>>>> - with "4-5-6"
>>>>
>>>> and we have this signature:
>>>>
>>>> Response get(@QueryParam("a") List<Integer> list);
>>>>
>>>> In this case we convert each parameter to Integer (the converter would
>>>> remove '-'), the runtime takes case of creating a List.
>>>> If we expected the converter to convert a String to List<Integer> then
>>>> what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and
>>>> expect it to parse it manually ? Not sure it makes sense.
>>>
>>> And given that ParamConverterProvider is expected to be reusable, what
>>> would we do with
>>>
>>> and a sequence like
>>>
>>> /path;a=1-2-3;a=4-5-6
>>> Response get(@MatrixParam("a") List<Integer> list);
>>>
>>> the converter would have to parse both
>>> "a=1-2-3&a=4-5-6" and "a=1-2-3;a=4-5-6"
>>>
>>> IMHO it is not how it should work, but please do not hesitate to
>>> investigate it further with Jersey
>>>
>>> Cheers, Sergey
>>>
>>>>
>>>> Can you investigate what Jersey does ? I'm pretty sure it was
>>>> discussed,
>>>> specifically that the runtime should take care of dealing with the list
>>>> itself, but they might deal with it differently
>>>>
>>>> Cheers, Sergey
>>>>
>>>>
>>>>
>>>> On 12/08/14 16:45, Vassilis Virvilis wrote:
>>>>> Aah,
>>>>>
>>>>> So in order to make this work through CXF is to define an
>>>>> EntitiesListWrapper class. Right? Then the ParamConverter will be
>>>>> called
>>>>> with EntitiesListWrapper as argument and jackson will deserialize.
>>>>> Right?
>>>>>
>>>>> Is there any other way to break the input of
>>>>>              final String entities_json = "[{\"name\":\"cca1\",
>>>>> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
>>>>> so the paramconverter will be called with the correct substring each
>>>>> time?
>>>>>
>>>>> This looks weird.
>>>>>
>>>>>      Vassilis
>>>>>
>>>>>
>>>>> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>>>>>> Hi
>>>>>>
>>>>>> AFAIK ParamConverterProvider is expected to be called once per every
>>>>>> entity in the list.
>>>>>>
>>>>>> Thanks, Sergey
>>>>>>
>>>>>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> Some time before I have started a thread with jackson and form
>>>>>>> parameters in cxf
>>>>>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Sergey suggested that I should use ParamConverterProvider.
>>>>>>>
>>>>>>> I tried it today and it worked. Great.
>>>>>>>
>>>>>>> Now I am trying the next step which is to pass List<Entity>
>>>>>>> instead of
>>>>>>> Entity in the input. The problem is that my
>>>>>>> ParamConverterProvider is
>>>>>>> not called with the actual input class as specified in the interface
>>>>>>> (List<Entity>) but with plain Entity as you can see from the
>>>>>>> logs. It
>>>>>>> then fails because due to
>>>>>>>          *** Can not deserialize instance of
>>>>>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>>>>>
>>>>>>> INFO
>>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1:
>>>>>>> class
>>>>>>> com.biovista.lib.datatype.Entity arg2:
>>>>>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>>>>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>>>>>> INFO
>>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>>>>>
>>>>>>> Here is my ParamConverterProvider
>>>>>>>
>>>>>>>
>>>>>>> package com.biovista.ws.impl.jaxrs;
>>>>>>>
>>>>>>> import java.io.IOException;
>>>>>>> import java.lang.annotation.Annotation;
>>>>>>> import java.lang.reflect.Type;
>>>>>>>
>>>>>>> import javax.ws.rs.ProcessingException;
>>>>>>> import javax.ws.rs.core.Context;
>>>>>>> import javax.ws.rs.core.MediaType;
>>>>>>> import javax.ws.rs.ext.ContextResolver;
>>>>>>> import javax.ws.rs.ext.MessageBodyReader;
>>>>>>> import javax.ws.rs.ext.ParamConverter;
>>>>>>> import javax.ws.rs.ext.ParamConverterProvider;
>>>>>>> import javax.ws.rs.ext.Provider;
>>>>>>> import javax.ws.rs.ext.Providers;
>>>>>>>
>>>>>>> import org.apache.commons.logging.Log;
>>>>>>> import org.apache.commons.logging.LogFactory;
>>>>>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>>>>>> import org.codehaus.jackson.map.ObjectMapper;
>>>>>>>
>>>>>>> @Provider
>>>>>>> public class JacksonJsonParamConverterProvider implements
>>>>>>> ParamConverterProvider {
>>>>>>>      private final Log log = LogFactory.getLog(getClass());
>>>>>>>
>>>>>>>      @Override
>>>>>>>      public <T> ParamConverter<T> getConverter(final Class<T>
>>>>>>> rawType,
>>>>>>>              final Type genericType, final Annotation[]
>>>>>>> annotations) {
>>>>>>>
>>>>>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>>>>>> genericType
>>>>>>>                  + " arg2: " + annotations + " providers: " +
>>>>>>> providers);
>>>>>>>          for (final Annotation annotation : annotations) {
>>>>>>>              log.info("Annotation: " + annotation);
>>>>>>>          }
>>>>>>>
>>>>>>>          return new ParamConverter<T>() {
>>>>>>>              @Override
>>>>>>>              public T fromString(final String value) {
>>>>>>>                  try {
>>>>>>>                      log.info("Called for " + value);
>>>>>>>                      return mapper.reader(rawType).readValue(value);
>>>>>>>                  } catch(IOException e) {
>>>>>>>                      throw new ProcessingException(e);
>>>>>>>                  }
>>>>>>>              }
>>>>>>>
>>>>>>>              @Override
>>>>>>>              public String toString(final T value) {
>>>>>>>                  try {
>>>>>>>                      return
>>>>>>> mapper.writer().writeValueAsString(value);
>>>>>>>                  } catch(Exception e) {
>>>>>>>                      throw new ProcessingException(e);
>>>>>>>                  }
>>>>>>>              }
>>>>>>>          };
>>>>>>>      }
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> How can I register different ParamConverterProvider for different
>>>>>>> input
>>>>>>> types? Or is that List is handled specially? By jackson or CXF? In
>>>>>>> jackson I just need to do
>>>>>>>          final List<Entity> entities =
>>>>>>> mapper.readValue(entities_json,
>>>>>>>              new TypeReference<List<Entity>>() {
>>>>>>>              });
>>>>>>>
>>>>>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>>>>>
>>>>>>>      Thanks
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>
>

-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi,
On 12/08/14 19:44, v.virvilis@biovista.com wrote:
> Hi Sergey,
>
> First of all thanks for your prompt reply as always. Your help is
> appreciated.
>
> Secondly, I am sorry I didn't explain the situation more clearly. I am a
> bit frustrated with this... as always when things don't work as we
> expect them too. It is quite probable that I lack the necessary
> understanding to make things work.
>
> Now to the problem.
>
> I have GWT and Resty-GWT into the client. RestyGWT requires jackson and
> so I have to use jackson and not jettinson in the server part where I
> have CXF.
>
> In the client I jave something like this
>
>      @POST
>      @Path("existing-entities")
>      @Consumes("application/x-www-form-urlencoded")
>      public void getExistingEntities(
>              @FormParam("entities") List<Entity> entities,
>              MethodCallback<List<Entity>> callback);
>
> In the server I have
>
>      @POST
>      @Path("existing-entities")
>      @Consumes("application/x-www-form-urlencoded")
>      public List<Entity> getExistingEntities(
>              @FormParam("entities") List<Entity> entities) throws
> SQLException;
>
>
> When I issue the call from the client with two entities: I get in the
> form contents. This is done by resty-gwt:
> entities: [{"name":"cca1", "type":"GENE"},{"name":"cca2", "type":"GENE"}]
>
> which is a JSONArray payload.
>
> What cxf does is to take the full json string and trying to shovel it
> down the throat of my poor ParamConverter as entity and not as
> List<Entity>.
>
as I explained earlier with the example of a query containing multipal 
parameters of the same name, ParamConverterProvider deals with the 
individual parameters such as Entity in your case

> I am not getting it. I think CXF either should break the array and call
> the converter for each object or it should leave the converter to
> convert the array. Now it is not breaking it but it doesn't give me the
> option to handle the array,

How exactly would CXF or indeed any other generic framework break this 
JSON Array ? It won't. It has no idea about the semantics associated 
with a given parameter.

You were right earlier on, just introduce a wrapper and forget about 
mapping it to the explicit collection :-). Explicit collections just 
make things more complicated unless there's an obvious/straightforward 
mapping as in the example I provided earlier on.

Thanks, Sergey

>
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
> com.biovista.lib.datatype.Entity arg2:
> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
> Annotation: @javax.ws.rs.FormParam(value=entities)
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider$1.fromString(JacksonJsonParamConverterProvider.java:71):
> Called for [{"name":"cca1", "type":"
> GENE"},{"name":"cca2", "type":"GENE"}]
> WARN 2014-08-12 17:47:46,722 http-bio-8081-exec-197:
> org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:452):
> Interceptor for {http://impl.ws.biovista.com/}VizitService has thrown
> exception, unwinding now javax.ws.rs.ProcessingException:
> org.codehaus.jackson.map.JsonMappingException: Can not deserialize
> instance of com.biovista.lib.datatype.Entity out of START_ARRAY token
>
> Now what do you think I should do in order to send complex types and
> collections to the server from the client?
>
> About Jersey - I don't know I have never used it. I am not sure how I
> should research it. In theory everything works. In practice you get to
> see the weird corner cases.
>
> I am not 100% sure but I believe the opposite way (cxf to send
> List<Entity>) works as expected. I will test and report tomorrow.
>
> Again thanks for the patience.
>
>
> On 2014-08-12 12:17, Sergey Beryozkin wrote:
>> On 12/08/14 17:13, Sergey Beryozkin wrote:
>>> Sorry, do not understand what you are trying to do.
>>>
>>> Why do you use a single parameter (query, header, or may be form) to
>>> send a JSON array ? This is typically sent as a message body, in which
>>> case JAX-RS MessageBodyReader takes care of it.
>>>
>>> Imagine this case:
>>>
>>> ?a=1-2-3&a=4-5-6
>>>
>>> here we have 2 'a' query parameters, one with value "1-2-3" and another
>>> - with "4-5-6"
>>>
>>> and we have this signature:
>>>
>>> Response get(@QueryParam("a") List<Integer> list);
>>>
>>> In this case we convert each parameter to Integer (the converter would
>>> remove '-'), the runtime takes case of creating a List.
>>> If we expected the converter to convert a String to List<Integer> then
>>> what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and
>>> expect it to parse it manually ? Not sure it makes sense.
>>
>> And given that ParamConverterProvider is expected to be reusable, what
>> would we do with
>>
>> and a sequence like
>>
>> /path;a=1-2-3;a=4-5-6
>> Response get(@MatrixParam("a") List<Integer> list);
>>
>> the converter would have to parse both
>> "a=1-2-3&a=4-5-6" and "a=1-2-3;a=4-5-6"
>>
>> IMHO it is not how it should work, but please do not hesitate to
>> investigate it further with Jersey
>>
>> Cheers, Sergey
>>
>>>
>>> Can you investigate what Jersey does ? I'm pretty sure it was discussed,
>>> specifically that the runtime should take care of dealing with the list
>>> itself, but they might deal with it differently
>>>
>>> Cheers, Sergey
>>>
>>>
>>>
>>> On 12/08/14 16:45, Vassilis Virvilis wrote:
>>>> Aah,
>>>>
>>>> So in order to make this work through CXF is to define an
>>>> EntitiesListWrapper class. Right? Then the ParamConverter will be
>>>> called
>>>> with EntitiesListWrapper as argument and jackson will deserialize.
>>>> Right?
>>>>
>>>> Is there any other way to break the input of
>>>>              final String entities_json = "[{\"name\":\"cca1\",
>>>> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
>>>> so the paramconverter will be called with the correct substring each
>>>> time?
>>>>
>>>> This looks weird.
>>>>
>>>>      Vassilis
>>>>
>>>>
>>>> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>>>>> Hi
>>>>>
>>>>> AFAIK ParamConverterProvider is expected to be called once per every
>>>>> entity in the list.
>>>>>
>>>>> Thanks, Sergey
>>>>>
>>>>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>>>>> Hi,
>>>>>>
>>>>>> Some time before I have started a thread with jackson and form
>>>>>> parameters in cxf
>>>>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Sergey suggested that I should use ParamConverterProvider.
>>>>>>
>>>>>> I tried it today and it worked. Great.
>>>>>>
>>>>>> Now I am trying the next step which is to pass List<Entity>
>>>>>> instead of
>>>>>> Entity in the input. The problem is that my ParamConverterProvider is
>>>>>> not called with the actual input class as specified in the interface
>>>>>> (List<Entity>) but with plain Entity as you can see from the logs. It
>>>>>> then fails because due to
>>>>>>          *** Can not deserialize instance of
>>>>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>>>>
>>>>>> INFO
>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>>>>>> com.biovista.lib.datatype.Entity arg2:
>>>>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>>>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>>>>> INFO
>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>>>>
>>>>>> Here is my ParamConverterProvider
>>>>>>
>>>>>>
>>>>>> package com.biovista.ws.impl.jaxrs;
>>>>>>
>>>>>> import java.io.IOException;
>>>>>> import java.lang.annotation.Annotation;
>>>>>> import java.lang.reflect.Type;
>>>>>>
>>>>>> import javax.ws.rs.ProcessingException;
>>>>>> import javax.ws.rs.core.Context;
>>>>>> import javax.ws.rs.core.MediaType;
>>>>>> import javax.ws.rs.ext.ContextResolver;
>>>>>> import javax.ws.rs.ext.MessageBodyReader;
>>>>>> import javax.ws.rs.ext.ParamConverter;
>>>>>> import javax.ws.rs.ext.ParamConverterProvider;
>>>>>> import javax.ws.rs.ext.Provider;
>>>>>> import javax.ws.rs.ext.Providers;
>>>>>>
>>>>>> import org.apache.commons.logging.Log;
>>>>>> import org.apache.commons.logging.LogFactory;
>>>>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>>>>> import org.codehaus.jackson.map.ObjectMapper;
>>>>>>
>>>>>> @Provider
>>>>>> public class JacksonJsonParamConverterProvider implements
>>>>>> ParamConverterProvider {
>>>>>>      private final Log log = LogFactory.getLog(getClass());
>>>>>>
>>>>>>      @Override
>>>>>>      public <T> ParamConverter<T> getConverter(final Class<T>
>>>>>> rawType,
>>>>>>              final Type genericType, final Annotation[]
>>>>>> annotations) {
>>>>>>
>>>>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>>>>> genericType
>>>>>>                  + " arg2: " + annotations + " providers: " +
>>>>>> providers);
>>>>>>          for (final Annotation annotation : annotations) {
>>>>>>              log.info("Annotation: " + annotation);
>>>>>>          }
>>>>>>
>>>>>>          return new ParamConverter<T>() {
>>>>>>              @Override
>>>>>>              public T fromString(final String value) {
>>>>>>                  try {
>>>>>>                      log.info("Called for " + value);
>>>>>>                      return mapper.reader(rawType).readValue(value);
>>>>>>                  } catch(IOException e) {
>>>>>>                      throw new ProcessingException(e);
>>>>>>                  }
>>>>>>              }
>>>>>>
>>>>>>              @Override
>>>>>>              public String toString(final T value) {
>>>>>>                  try {
>>>>>>                      return
>>>>>> mapper.writer().writeValueAsString(value);
>>>>>>                  } catch(Exception e) {
>>>>>>                      throw new ProcessingException(e);
>>>>>>                  }
>>>>>>              }
>>>>>>          };
>>>>>>      }
>>>>>> }
>>>>>>
>>>>>>
>>>>>> How can I register different ParamConverterProvider for different
>>>>>> input
>>>>>> types? Or is that List is handled specially? By jackson or CXF? In
>>>>>> jackson I just need to do
>>>>>>          final List<Entity> entities =
>>>>>> mapper.readValue(entities_json,
>>>>>>              new TypeReference<List<Entity>>() {
>>>>>>              });
>>>>>>
>>>>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>>>>
>>>>>>      Thanks
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>


Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi,
On 12/08/14 19:44, v.virvilis@biovista.com wrote:
> Hi Sergey,
>
> First of all thanks for your prompt reply as always. Your help is
> appreciated.
>
> Secondly, I am sorry I didn't explain the situation more clearly. I am a
> bit frustrated with this... as always when things don't work as we
> expect them too. It is quite probable that I lack the necessary
> understanding to make things work.
>
> Now to the problem.
>
> I have GWT and Resty-GWT into the client. RestyGWT requires jackson and
> so I have to use jackson and not jettinson in the server part where I
> have CXF.
>
> In the client I jave something like this
>
>      @POST
>      @Path("existing-entities")
>      @Consumes("application/x-www-form-urlencoded")
>      public void getExistingEntities(
>              @FormParam("entities") List<Entity> entities,
>              MethodCallback<List<Entity>> callback);
>
> In the server I have
>
>      @POST
>      @Path("existing-entities")
>      @Consumes("application/x-www-form-urlencoded")
>      public List<Entity> getExistingEntities(
>              @FormParam("entities") List<Entity> entities) throws
> SQLException;
>
>
> When I issue the call from the client with two entities: I get in the
> form contents. This is done by resty-gwt:
> entities: [{"name":"cca1", "type":"GENE"},{"name":"cca2", "type":"GENE"}]
>
> which is a JSONArray payload.
>
> What cxf does is to take the full json string and trying to shovel it
> down the throat of my poor ParamConverter as entity and not as
> List<Entity>.
>
as I explained earlier with the example of a query containing multipal 
parameters of the same name, ParamConverterProvider deals with the 
individual parameters such as Entity in your case

> I am not getting it. I think CXF either should break the array and call
> the converter for each object or it should leave the converter to
> convert the array. Now it is not breaking it but it doesn't give me the
> option to handle the array,

How exactly would CXF or indeed any other generic framework break this 
JSON Array ? It won't. It has no idea about the semantics associated 
with a given parameter.

You were right earlier on, just introduce a wrapper and forget about 
mapping it to the explicit collection :-). Explicit collections just 
make things more complicated unless there's an obvious/straightforward 
mapping as in the example I provided earlier on.

Thanks, Sergey

>
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
> com.biovista.lib.datatype.Entity arg2:
> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
> Annotation: @javax.ws.rs.FormParam(value=entities)
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider$1.fromString(JacksonJsonParamConverterProvider.java:71):
> Called for [{"name":"cca1", "type":"
> GENE"},{"name":"cca2", "type":"GENE"}]
> WARN 2014-08-12 17:47:46,722 http-bio-8081-exec-197:
> org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:452):
> Interceptor for {http://impl.ws.biovista.com/}VizitService has thrown
> exception, unwinding now javax.ws.rs.ProcessingException:
> org.codehaus.jackson.map.JsonMappingException: Can not deserialize
> instance of com.biovista.lib.datatype.Entity out of START_ARRAY token
>
> Now what do you think I should do in order to send complex types and
> collections to the server from the client?
>
> About Jersey - I don't know I have never used it. I am not sure how I
> should research it. In theory everything works. In practice you get to
> see the weird corner cases.
>
> I am not 100% sure but I believe the opposite way (cxf to send
> List<Entity>) works as expected. I will test and report tomorrow.
>
> Again thanks for the patience.
>
>
> On 2014-08-12 12:17, Sergey Beryozkin wrote:
>> On 12/08/14 17:13, Sergey Beryozkin wrote:
>>> Sorry, do not understand what you are trying to do.
>>>
>>> Why do you use a single parameter (query, header, or may be form) to
>>> send a JSON array ? This is typically sent as a message body, in which
>>> case JAX-RS MessageBodyReader takes care of it.
>>>
>>> Imagine this case:
>>>
>>> ?a=1-2-3&a=4-5-6
>>>
>>> here we have 2 'a' query parameters, one with value "1-2-3" and another
>>> - with "4-5-6"
>>>
>>> and we have this signature:
>>>
>>> Response get(@QueryParam("a") List<Integer> list);
>>>
>>> In this case we convert each parameter to Integer (the converter would
>>> remove '-'), the runtime takes case of creating a List.
>>> If we expected the converter to convert a String to List<Integer> then
>>> what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and
>>> expect it to parse it manually ? Not sure it makes sense.
>>
>> And given that ParamConverterProvider is expected to be reusable, what
>> would we do with
>>
>> and a sequence like
>>
>> /path;a=1-2-3;a=4-5-6
>> Response get(@MatrixParam("a") List<Integer> list);
>>
>> the converter would have to parse both
>> "a=1-2-3&a=4-5-6" and "a=1-2-3;a=4-5-6"
>>
>> IMHO it is not how it should work, but please do not hesitate to
>> investigate it further with Jersey
>>
>> Cheers, Sergey
>>
>>>
>>> Can you investigate what Jersey does ? I'm pretty sure it was discussed,
>>> specifically that the runtime should take care of dealing with the list
>>> itself, but they might deal with it differently
>>>
>>> Cheers, Sergey
>>>
>>>
>>>
>>> On 12/08/14 16:45, Vassilis Virvilis wrote:
>>>> Aah,
>>>>
>>>> So in order to make this work through CXF is to define an
>>>> EntitiesListWrapper class. Right? Then the ParamConverter will be
>>>> called
>>>> with EntitiesListWrapper as argument and jackson will deserialize.
>>>> Right?
>>>>
>>>> Is there any other way to break the input of
>>>>              final String entities_json = "[{\"name\":\"cca1\",
>>>> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
>>>> so the paramconverter will be called with the correct substring each
>>>> time?
>>>>
>>>> This looks weird.
>>>>
>>>>      Vassilis
>>>>
>>>>
>>>> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>>>>> Hi
>>>>>
>>>>> AFAIK ParamConverterProvider is expected to be called once per every
>>>>> entity in the list.
>>>>>
>>>>> Thanks, Sergey
>>>>>
>>>>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>>>>> Hi,
>>>>>>
>>>>>> Some time before I have started a thread with jackson and form
>>>>>> parameters in cxf
>>>>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Sergey suggested that I should use ParamConverterProvider.
>>>>>>
>>>>>> I tried it today and it worked. Great.
>>>>>>
>>>>>> Now I am trying the next step which is to pass List<Entity>
>>>>>> instead of
>>>>>> Entity in the input. The problem is that my ParamConverterProvider is
>>>>>> not called with the actual input class as specified in the interface
>>>>>> (List<Entity>) but with plain Entity as you can see from the logs. It
>>>>>> then fails because due to
>>>>>>          *** Can not deserialize instance of
>>>>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>>>>
>>>>>> INFO
>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>>>>>> com.biovista.lib.datatype.Entity arg2:
>>>>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>>>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>>>>> INFO
>>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>>>>
>>>>>> Here is my ParamConverterProvider
>>>>>>
>>>>>>
>>>>>> package com.biovista.ws.impl.jaxrs;
>>>>>>
>>>>>> import java.io.IOException;
>>>>>> import java.lang.annotation.Annotation;
>>>>>> import java.lang.reflect.Type;
>>>>>>
>>>>>> import javax.ws.rs.ProcessingException;
>>>>>> import javax.ws.rs.core.Context;
>>>>>> import javax.ws.rs.core.MediaType;
>>>>>> import javax.ws.rs.ext.ContextResolver;
>>>>>> import javax.ws.rs.ext.MessageBodyReader;
>>>>>> import javax.ws.rs.ext.ParamConverter;
>>>>>> import javax.ws.rs.ext.ParamConverterProvider;
>>>>>> import javax.ws.rs.ext.Provider;
>>>>>> import javax.ws.rs.ext.Providers;
>>>>>>
>>>>>> import org.apache.commons.logging.Log;
>>>>>> import org.apache.commons.logging.LogFactory;
>>>>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>>>>> import org.codehaus.jackson.map.ObjectMapper;
>>>>>>
>>>>>> @Provider
>>>>>> public class JacksonJsonParamConverterProvider implements
>>>>>> ParamConverterProvider {
>>>>>>      private final Log log = LogFactory.getLog(getClass());
>>>>>>
>>>>>>      @Override
>>>>>>      public <T> ParamConverter<T> getConverter(final Class<T>
>>>>>> rawType,
>>>>>>              final Type genericType, final Annotation[]
>>>>>> annotations) {
>>>>>>
>>>>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>>>>> genericType
>>>>>>                  + " arg2: " + annotations + " providers: " +
>>>>>> providers);
>>>>>>          for (final Annotation annotation : annotations) {
>>>>>>              log.info("Annotation: " + annotation);
>>>>>>          }
>>>>>>
>>>>>>          return new ParamConverter<T>() {
>>>>>>              @Override
>>>>>>              public T fromString(final String value) {
>>>>>>                  try {
>>>>>>                      log.info("Called for " + value);
>>>>>>                      return mapper.reader(rawType).readValue(value);
>>>>>>                  } catch(IOException e) {
>>>>>>                      throw new ProcessingException(e);
>>>>>>                  }
>>>>>>              }
>>>>>>
>>>>>>              @Override
>>>>>>              public String toString(final T value) {
>>>>>>                  try {
>>>>>>                      return
>>>>>> mapper.writer().writeValueAsString(value);
>>>>>>                  } catch(Exception e) {
>>>>>>                      throw new ProcessingException(e);
>>>>>>                  }
>>>>>>              }
>>>>>>          };
>>>>>>      }
>>>>>> }
>>>>>>
>>>>>>
>>>>>> How can I register different ParamConverterProvider for different
>>>>>> input
>>>>>> types? Or is that List is handled specially? By jackson or CXF? In
>>>>>> jackson I just need to do
>>>>>>          final List<Entity> entities =
>>>>>> mapper.readValue(entities_json,
>>>>>>              new TypeReference<List<Entity>>() {
>>>>>>              });
>>>>>>
>>>>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>>>>
>>>>>>      Thanks
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>


Re: registering ParamConverterProviders with cxf

Posted by v....@biovista.com.
Hi Sergey,

First of all thanks for your prompt reply as always. Your help is 
appreciated.

Secondly, I am sorry I didn't explain the situation more clearly. I am a 
bit frustrated with this... as always when things don't work as we 
expect them too. It is quite probable that I lack the necessary 
understanding to make things work.

Now to the problem.

I have GWT and Resty-GWT into the client. RestyGWT requires jackson and 
so I have to use jackson and not jettinson in the server part where I 
have CXF.

In the client I jave something like this

     @POST
     @Path("existing-entities")
     @Consumes("application/x-www-form-urlencoded")
     public void getExistingEntities(
             @FormParam("entities") List<Entity> entities,
             MethodCallback<List<Entity>> callback);

In the server I have

     @POST
     @Path("existing-entities")
     @Consumes("application/x-www-form-urlencoded")
     public List<Entity> getExistingEntities(
             @FormParam("entities") List<Entity> entities) throws 
SQLException;


When I issue the call from the client with two entities: I get in the 
form contents. This is done by resty-gwt:
entities: [{"name":"cca1", "type":"GENE"},{"name":"cca2", 
"type":"GENE"}]

which is a JSONArray payload.

What cxf does is to take the full json string and trying to shovel it 
down the throat of my poor ParamConverter as entity and not as 
List<Entity>.

I am not getting it. I think CXF either should break the array and call 
the converter for each object or it should leave the converter to 
convert the array. Now it is not breaking it but it doesn't give me the 
option to handle the array,

INFO 
com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41): 
**** called: arg0: class com.biovista.lib.datatype.Entity arg1: class 
com.biovista.lib.datatype.Entity arg2: 
[Ljava.lang.annotation.Annotation;@7f65ae66 providers: 
org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
INFO 
com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44): 
Annotation: @javax.ws.rs.FormParam(value=entities)
INFO 
com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider$1.fromString(JacksonJsonParamConverterProvider.java:71): 
Called for [{"name":"cca1", "type":"
GENE"},{"name":"cca2", "type":"GENE"}]
WARN 2014-08-12 17:47:46,722 http-bio-8081-exec-197: 
org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:452): 
Interceptor for {http://impl.ws.biovista.com/}VizitService has thrown 
exception, unwinding now javax.ws.rs.ProcessingException: 
org.codehaus.jackson.map.JsonMappingException: Can not deserialize 
instance of com.biovista.lib.datatype.Entity out of START_ARRAY token

Now what do you think I should do in order to send complex types and 
collections to the server from the client?

About Jersey - I don't know I have never used it. I am not sure how I 
should research it. In theory everything works. In practice you get to 
see the weird corner cases.

I am not 100% sure but I believe the opposite way (cxf to send 
List<Entity>) works as expected. I will test and report tomorrow.

Again thanks for the patience.


On 2014-08-12 12:17, Sergey Beryozkin wrote:
> On 12/08/14 17:13, Sergey Beryozkin wrote:
>> Sorry, do not understand what you are trying to do.
>> 
>> Why do you use a single parameter (query, header, or may be form) to
>> send a JSON array ? This is typically sent as a message body, in which
>> case JAX-RS MessageBodyReader takes care of it.
>> 
>> Imagine this case:
>> 
>> ?a=1-2-3&a=4-5-6
>> 
>> here we have 2 'a' query parameters, one with value "1-2-3" and 
>> another
>> - with "4-5-6"
>> 
>> and we have this signature:
>> 
>> Response get(@QueryParam("a") List<Integer> list);
>> 
>> In this case we convert each parameter to Integer (the converter would
>> remove '-'), the runtime takes case of creating a List.
>> If we expected the converter to convert a String to List<Integer> then
>> what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and
>> expect it to parse it manually ? Not sure it makes sense.
> 
> And given that ParamConverterProvider is expected to be reusable, what
> would we do with
> 
> and a sequence like
> 
> /path;a=1-2-3;a=4-5-6
> Response get(@MatrixParam("a") List<Integer> list);
> 
> the converter would have to parse both
> "a=1-2-3&a=4-5-6" and "a=1-2-3;a=4-5-6"
> 
> IMHO it is not how it should work, but please do not hesitate to
> investigate it further with Jersey
> 
> Cheers, Sergey
> 
>> 
>> Can you investigate what Jersey does ? I'm pretty sure it was 
>> discussed,
>> specifically that the runtime should take care of dealing with the 
>> list
>> itself, but they might deal with it differently
>> 
>> Cheers, Sergey
>> 
>> 
>> 
>> On 12/08/14 16:45, Vassilis Virvilis wrote:
>>> Aah,
>>> 
>>> So in order to make this work through CXF is to define an
>>> EntitiesListWrapper class. Right? Then the ParamConverter will be 
>>> called
>>> with EntitiesListWrapper as argument and jackson will deserialize. 
>>> Right?
>>> 
>>> Is there any other way to break the input of
>>>              final String entities_json = "[{\"name\":\"cca1\",
>>> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
>>> so the paramconverter will be called with the correct substring each
>>> time?
>>> 
>>> This looks weird.
>>> 
>>>      Vassilis
>>> 
>>> 
>>> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>>>> Hi
>>>> 
>>>> AFAIK ParamConverterProvider is expected to be called once per every
>>>> entity in the list.
>>>> 
>>>> Thanks, Sergey
>>>> 
>>>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>>>> Hi,
>>>>> 
>>>>> Some time before I have started a thread with jackson and form
>>>>> parameters in cxf
>>>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> Sergey suggested that I should use ParamConverterProvider.
>>>>> 
>>>>> I tried it today and it worked. Great.
>>>>> 
>>>>> Now I am trying the next step which is to pass List<Entity> instead 
>>>>> of
>>>>> Entity in the input. The problem is that my ParamConverterProvider 
>>>>> is
>>>>> not called with the actual input class as specified in the 
>>>>> interface
>>>>> (List<Entity>) but with plain Entity as you can see from the logs. 
>>>>> It
>>>>> then fails because due to
>>>>>          *** Can not deserialize instance of
>>>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>>> 
>>>>> INFO
>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>>> 
>>>>> 
>>>>> 
>>>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: 
>>>>> class
>>>>> com.biovista.lib.datatype.Entity arg2:
>>>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>>>> INFO
>>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>>> 
>>>>> 
>>>>> 
>>>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>>> 
>>>>> Here is my ParamConverterProvider
>>>>> 
>>>>> 
>>>>> package com.biovista.ws.impl.jaxrs;
>>>>> 
>>>>> import java.io.IOException;
>>>>> import java.lang.annotation.Annotation;
>>>>> import java.lang.reflect.Type;
>>>>> 
>>>>> import javax.ws.rs.ProcessingException;
>>>>> import javax.ws.rs.core.Context;
>>>>> import javax.ws.rs.core.MediaType;
>>>>> import javax.ws.rs.ext.ContextResolver;
>>>>> import javax.ws.rs.ext.MessageBodyReader;
>>>>> import javax.ws.rs.ext.ParamConverter;
>>>>> import javax.ws.rs.ext.ParamConverterProvider;
>>>>> import javax.ws.rs.ext.Provider;
>>>>> import javax.ws.rs.ext.Providers;
>>>>> 
>>>>> import org.apache.commons.logging.Log;
>>>>> import org.apache.commons.logging.LogFactory;
>>>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>>>> import org.codehaus.jackson.map.ObjectMapper;
>>>>> 
>>>>> @Provider
>>>>> public class JacksonJsonParamConverterProvider implements
>>>>> ParamConverterProvider {
>>>>>      private final Log log = LogFactory.getLog(getClass());
>>>>> 
>>>>>      @Override
>>>>>      public <T> ParamConverter<T> getConverter(final Class<T> 
>>>>> rawType,
>>>>>              final Type genericType, final Annotation[] 
>>>>> annotations) {
>>>>> 
>>>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>>>> genericType
>>>>>                  + " arg2: " + annotations + " providers: " +
>>>>> providers);
>>>>>          for (final Annotation annotation : annotations) {
>>>>>              log.info("Annotation: " + annotation);
>>>>>          }
>>>>> 
>>>>>          return new ParamConverter<T>() {
>>>>>              @Override
>>>>>              public T fromString(final String value) {
>>>>>                  try {
>>>>>                      log.info("Called for " + value);
>>>>>                      return 
>>>>> mapper.reader(rawType).readValue(value);
>>>>>                  } catch(IOException e) {
>>>>>                      throw new ProcessingException(e);
>>>>>                  }
>>>>>              }
>>>>> 
>>>>>              @Override
>>>>>              public String toString(final T value) {
>>>>>                  try {
>>>>>                      return 
>>>>> mapper.writer().writeValueAsString(value);
>>>>>                  } catch(Exception e) {
>>>>>                      throw new ProcessingException(e);
>>>>>                  }
>>>>>              }
>>>>>          };
>>>>>      }
>>>>> }
>>>>> 
>>>>> 
>>>>> How can I register different ParamConverterProvider for different 
>>>>> input
>>>>> types? Or is that List is handled specially? By jackson or CXF? In
>>>>> jackson I just need to do
>>>>>          final List<Entity> entities = 
>>>>> mapper.readValue(entities_json,
>>>>>              new TypeReference<List<Entity>>() {
>>>>>              });
>>>>> 
>>>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>>> 
>>>>>      Thanks
>>>> 
>>>> 
>>>> 
>>> 
>> 
>> 

Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
On 12/08/14 17:13, Sergey Beryozkin wrote:
> Sorry, do not understand what you are trying to do.
>
> Why do you use a single parameter (query, header, or may be form) to
> send a JSON array ? This is typically sent as a message body, in which
> case JAX-RS MessageBodyReader takes care of it.
>
> Imagine this case:
>
> ?a=1-2-3&a=4-5-6
>
> here we have 2 'a' query parameters, one with value "1-2-3" and another
> - with "4-5-6"
>
> and we have this signature:
>
> Response get(@QueryParam("a") List<Integer> list);
>
> In this case we convert each parameter to Integer (the converter would
> remove '-'), the runtime takes case of creating a List.
> If we expected the converter to convert a String to List<Integer> then
> what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and
> expect it to parse it manually ? Not sure it makes sense.

And given that ParamConverterProvider is expected to be reusable, what 
would we do with

and a sequence like

/path;a=1-2-3;a=4-5-6
Response get(@MatrixParam("a") List<Integer> list);

the converter would have to parse both
"a=1-2-3&a=4-5-6" and "a=1-2-3;a=4-5-6"

IMHO it is not how it should work, but please do not hesitate to 
investigate it further with Jersey

Cheers, Sergey

>
> Can you investigate what Jersey does ? I'm pretty sure it was discussed,
> specifically that the runtime should take care of dealing with the list
> itself, but they might deal with it differently
>
> Cheers, Sergey
>
>
>
> On 12/08/14 16:45, Vassilis Virvilis wrote:
>> Aah,
>>
>> So in order to make this work through CXF is to define an
>> EntitiesListWrapper class. Right? Then the ParamConverter will be called
>> with EntitiesListWrapper as argument and jackson will deserialize. Right?
>>
>> Is there any other way to break the input of
>>              final String entities_json = "[{\"name\":\"cca1\",
>> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
>> so the paramconverter will be called with the correct substring each
>> time?
>>
>> This looks weird.
>>
>>      Vassilis
>>
>>
>> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>>> Hi
>>>
>>> AFAIK ParamConverterProvider is expected to be called once per every
>>> entity in the list.
>>>
>>> Thanks, Sergey
>>>
>>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>>> Hi,
>>>>
>>>> Some time before I have started a thread with jackson and form
>>>> parameters in cxf
>>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Sergey suggested that I should use ParamConverterProvider.
>>>>
>>>> I tried it today and it worked. Great.
>>>>
>>>> Now I am trying the next step which is to pass List<Entity> instead of
>>>> Entity in the input. The problem is that my ParamConverterProvider is
>>>> not called with the actual input class as specified in the interface
>>>> (List<Entity>) but with plain Entity as you can see from the logs. It
>>>> then fails because due to
>>>>          *** Can not deserialize instance of
>>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>>
>>>> INFO
>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>>
>>>>
>>>>
>>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>>>> com.biovista.lib.datatype.Entity arg2:
>>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>>> INFO
>>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>>
>>>>
>>>>
>>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>>
>>>> Here is my ParamConverterProvider
>>>>
>>>>
>>>> package com.biovista.ws.impl.jaxrs;
>>>>
>>>> import java.io.IOException;
>>>> import java.lang.annotation.Annotation;
>>>> import java.lang.reflect.Type;
>>>>
>>>> import javax.ws.rs.ProcessingException;
>>>> import javax.ws.rs.core.Context;
>>>> import javax.ws.rs.core.MediaType;
>>>> import javax.ws.rs.ext.ContextResolver;
>>>> import javax.ws.rs.ext.MessageBodyReader;
>>>> import javax.ws.rs.ext.ParamConverter;
>>>> import javax.ws.rs.ext.ParamConverterProvider;
>>>> import javax.ws.rs.ext.Provider;
>>>> import javax.ws.rs.ext.Providers;
>>>>
>>>> import org.apache.commons.logging.Log;
>>>> import org.apache.commons.logging.LogFactory;
>>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>>> import org.codehaus.jackson.map.ObjectMapper;
>>>>
>>>> @Provider
>>>> public class JacksonJsonParamConverterProvider implements
>>>> ParamConverterProvider {
>>>>      private final Log log = LogFactory.getLog(getClass());
>>>>
>>>>      @Override
>>>>      public <T> ParamConverter<T> getConverter(final Class<T> rawType,
>>>>              final Type genericType, final Annotation[] annotations) {
>>>>
>>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>>> genericType
>>>>                  + " arg2: " + annotations + " providers: " +
>>>> providers);
>>>>          for (final Annotation annotation : annotations) {
>>>>              log.info("Annotation: " + annotation);
>>>>          }
>>>>
>>>>          return new ParamConverter<T>() {
>>>>              @Override
>>>>              public T fromString(final String value) {
>>>>                  try {
>>>>                      log.info("Called for " + value);
>>>>                      return mapper.reader(rawType).readValue(value);
>>>>                  } catch(IOException e) {
>>>>                      throw new ProcessingException(e);
>>>>                  }
>>>>              }
>>>>
>>>>              @Override
>>>>              public String toString(final T value) {
>>>>                  try {
>>>>                      return mapper.writer().writeValueAsString(value);
>>>>                  } catch(Exception e) {
>>>>                      throw new ProcessingException(e);
>>>>                  }
>>>>              }
>>>>          };
>>>>      }
>>>> }
>>>>
>>>>
>>>> How can I register different ParamConverterProvider for different input
>>>> types? Or is that List is handled specially? By jackson or CXF? In
>>>> jackson I just need to do
>>>>          final List<Entity> entities = mapper.readValue(entities_json,
>>>>              new TypeReference<List<Entity>>() {
>>>>              });
>>>>
>>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>>
>>>>      Thanks
>>>
>>>
>>>
>>
>
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
Sorry, do not understand what you are trying to do.

Why do you use a single parameter (query, header, or may be form) to 
send a JSON array ? This is typically sent as a message body, in which 
case JAX-RS MessageBodyReader takes care of it.

Imagine this case:

?a=1-2-3&a=4-5-6

here we have 2 'a' query parameters, one with value "1-2-3" and another 
- with "4-5-6"

and we have this signature:

Response get(@QueryParam("a") List<Integer> list);

In this case we convert each parameter to Integer (the converter would 
remove '-'), the runtime takes case of creating a List.
If we expected the converter to convert a String to List<Integer> then 
what would the runtime pass to the converter, "a=1-2-3&a=4-5-6" and 
expect it to parse it manually ? Not sure it makes sense.

Can you investigate what Jersey does ? I'm pretty sure it was discussed, 
specifically that the runtime should take care of dealing with the list 
itself, but they might deal with it differently

Cheers, Sergey



On 12/08/14 16:45, Vassilis Virvilis wrote:
> Aah,
>
> So in order to make this work through CXF is to define an
> EntitiesListWrapper class. Right? Then the ParamConverter will be called
> with EntitiesListWrapper as argument and jackson will deserialize. Right?
>
> Is there any other way to break the input of
>              final String entities_json = "[{\"name\":\"cca1\",
> \"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
> so the paramconverter will be called with the correct substring each time?
>
> This looks weird.
>
>      Vassilis
>
>
> On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
>> Hi
>>
>> AFAIK ParamConverterProvider is expected to be called once per every
>> entity in the list.
>>
>> Thanks, Sergey
>>
>> On 12/08/14 16:12, Vassilis Virvilis wrote:
>>> Hi,
>>>
>>> Some time before I have started a thread with jackson and form
>>> parameters in cxf
>>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>>
>>>
>>>
>>>
>>> Sergey suggested that I should use ParamConverterProvider.
>>>
>>> I tried it today and it worked. Great.
>>>
>>> Now I am trying the next step which is to pass List<Entity> instead of
>>> Entity in the input. The problem is that my ParamConverterProvider is
>>> not called with the actual input class as specified in the interface
>>> (List<Entity>) but with plain Entity as you can see from the logs. It
>>> then fails because due to
>>>          *** Can not deserialize instance of
>>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>>
>>> INFO
>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>>
>>>
>>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>>> com.biovista.lib.datatype.Entity arg2:
>>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>>> INFO
>>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>>
>>>
>>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>>
>>> Here is my ParamConverterProvider
>>>
>>>
>>> package com.biovista.ws.impl.jaxrs;
>>>
>>> import java.io.IOException;
>>> import java.lang.annotation.Annotation;
>>> import java.lang.reflect.Type;
>>>
>>> import javax.ws.rs.ProcessingException;
>>> import javax.ws.rs.core.Context;
>>> import javax.ws.rs.core.MediaType;
>>> import javax.ws.rs.ext.ContextResolver;
>>> import javax.ws.rs.ext.MessageBodyReader;
>>> import javax.ws.rs.ext.ParamConverter;
>>> import javax.ws.rs.ext.ParamConverterProvider;
>>> import javax.ws.rs.ext.Provider;
>>> import javax.ws.rs.ext.Providers;
>>>
>>> import org.apache.commons.logging.Log;
>>> import org.apache.commons.logging.LogFactory;
>>> import org.apache.cxf.jaxrs.ext.MessageContext;
>>> import org.codehaus.jackson.map.ObjectMapper;
>>>
>>> @Provider
>>> public class JacksonJsonParamConverterProvider implements
>>> ParamConverterProvider {
>>>      private final Log log = LogFactory.getLog(getClass());
>>>
>>>      @Override
>>>      public <T> ParamConverter<T> getConverter(final Class<T> rawType,
>>>              final Type genericType, final Annotation[] annotations) {
>>>
>>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>>> genericType
>>>                  + " arg2: " + annotations + " providers: " +
>>> providers);
>>>          for (final Annotation annotation : annotations) {
>>>              log.info("Annotation: " + annotation);
>>>          }
>>>
>>>          return new ParamConverter<T>() {
>>>              @Override
>>>              public T fromString(final String value) {
>>>                  try {
>>>                      log.info("Called for " + value);
>>>                      return mapper.reader(rawType).readValue(value);
>>>                  } catch(IOException e) {
>>>                      throw new ProcessingException(e);
>>>                  }
>>>              }
>>>
>>>              @Override
>>>              public String toString(final T value) {
>>>                  try {
>>>                      return mapper.writer().writeValueAsString(value);
>>>                  } catch(Exception e) {
>>>                      throw new ProcessingException(e);
>>>                  }
>>>              }
>>>          };
>>>      }
>>> }
>>>
>>>
>>> How can I register different ParamConverterProvider for different input
>>> types? Or is that List is handled specially? By jackson or CXF? In
>>> jackson I just need to do
>>>          final List<Entity> entities = mapper.readValue(entities_json,
>>>              new TypeReference<List<Entity>>() {
>>>              });
>>>
>>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>>
>>>      Thanks
>>
>>
>>
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: registering ParamConverterProviders with cxf

Posted by Vassilis Virvilis <v....@biovista.com>.
Aah,

So in order to make this work through CXF is to define an 
EntitiesListWrapper class. Right? Then the ParamConverter will be called 
with EntitiesListWrapper as argument and jackson will deserialize. Right?

Is there any other way to break the input of
             final String entities_json = "[{\"name\":\"cca1\", 
\"type\":\"GENE\"},{\"name\":\"cca2\", \"type\":\"GENE\"}]";
so the paramconverter will be called with the correct substring each time?

This looks weird.

     Vassilis


On 08/12/2014 06:22 PM, Sergey Beryozkin wrote:
> Hi
>
> AFAIK ParamConverterProvider is expected to be called once per every
> entity in the list.
>
> Thanks, Sergey
>
> On 12/08/14 16:12, Vassilis Virvilis wrote:
>> Hi,
>>
>> Some time before I have started a thread with jackson and form
>> parameters in cxf
>> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>>
>>
>>
>> Sergey suggested that I should use ParamConverterProvider.
>>
>> I tried it today and it worked. Great.
>>
>> Now I am trying the next step which is to pass List<Entity> instead of
>> Entity in the input. The problem is that my ParamConverterProvider is
>> not called with the actual input class as specified in the interface
>> (List<Entity>) but with plain Entity as you can see from the logs. It
>> then fails because due to
>>          *** Can not deserialize instance of
>> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>>
>> INFO
>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
>>
>> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
>> com.biovista.lib.datatype.Entity arg2:
>> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
>> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
>> INFO
>> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
>>
>> Annotation: @javax.ws.rs.FormParam(value=entities)
>>
>> Here is my ParamConverterProvider
>>
>>
>> package com.biovista.ws.impl.jaxrs;
>>
>> import java.io.IOException;
>> import java.lang.annotation.Annotation;
>> import java.lang.reflect.Type;
>>
>> import javax.ws.rs.ProcessingException;
>> import javax.ws.rs.core.Context;
>> import javax.ws.rs.core.MediaType;
>> import javax.ws.rs.ext.ContextResolver;
>> import javax.ws.rs.ext.MessageBodyReader;
>> import javax.ws.rs.ext.ParamConverter;
>> import javax.ws.rs.ext.ParamConverterProvider;
>> import javax.ws.rs.ext.Provider;
>> import javax.ws.rs.ext.Providers;
>>
>> import org.apache.commons.logging.Log;
>> import org.apache.commons.logging.LogFactory;
>> import org.apache.cxf.jaxrs.ext.MessageContext;
>> import org.codehaus.jackson.map.ObjectMapper;
>>
>> @Provider
>> public class JacksonJsonParamConverterProvider implements
>> ParamConverterProvider {
>>      private final Log log = LogFactory.getLog(getClass());
>>
>>      @Override
>>      public <T> ParamConverter<T> getConverter(final Class<T> rawType,
>>              final Type genericType, final Annotation[] annotations) {
>>
>>          log.info("**** called: arg0: " + rawType + " arg1: " +
>> genericType
>>                  + " arg2: " + annotations + " providers: " + providers);
>>          for (final Annotation annotation : annotations) {
>>              log.info("Annotation: " + annotation);
>>          }
>>
>>          return new ParamConverter<T>() {
>>              @Override
>>              public T fromString(final String value) {
>>                  try {
>>                      log.info("Called for " + value);
>>                      return mapper.reader(rawType).readValue(value);
>>                  } catch(IOException e) {
>>                      throw new ProcessingException(e);
>>                  }
>>              }
>>
>>              @Override
>>              public String toString(final T value) {
>>                  try {
>>                      return mapper.writer().writeValueAsString(value);
>>                  } catch(Exception e) {
>>                      throw new ProcessingException(e);
>>                  }
>>              }
>>          };
>>      }
>> }
>>
>>
>> How can I register different ParamConverterProvider for different input
>> types? Or is that List is handled specially? By jackson or CXF? In
>> jackson I just need to do
>>          final List<Entity> entities = mapper.readValue(entities_json,
>>              new TypeReference<List<Entity>>() {
>>              });
>>
>> but I don't know how to do this from inside CXF. I am using CXF 3.0
>>
>>      Thanks
>
>
>

-- 

__________________________________

Vassilis Virvilis Ph.D.
Head of IT
Biovista Inc.

US Offices
2421 Ivy Road
Charlottesville, VA 22903
USA
T: +1.434.971.1141
F: +1.434.971.1144

European Offices
34 Rodopoleos Street
Ellinikon, Athens 16777
GREECE
T: +30.210.9629848
F: +30.210.9647606

www.biovista.com

Biovista is a privately held biotechnology company that finds novel uses 
for existing drugs, and profiles their side effects using their 
mechanism of action. Biovista develops its own pipeline of drugs in CNS, 
oncology, auto-immune and rare diseases. Biovista is collaborating with 
biopharmaceutical companies on indication expansion and de-risking of 
their portfolios and with the FDA on adverse event prediction.



Re: registering ParamConverterProviders with cxf

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi

AFAIK ParamConverterProvider is expected to be called once per every 
entity in the list.

Thanks, Sergey

On 12/08/14 16:12, Vassilis Virvilis wrote:
> Hi,
>
> Some time before I have started a thread with jackson and form
> parameters in cxf
> http://mail-archives.apache.org/mod_mbox/cxf-users/201406.mbox/%3C53AAC4CC.8010206@biovista.com%3E
>
>
> Sergey suggested that I should use ParamConverterProvider.
>
> I tried it today and it worked. Great.
>
> Now I am trying the next step which is to pass List<Entity> instead of
> Entity in the input. The problem is that my ParamConverterProvider is
> not called with the actual input class as specified in the interface
> (List<Entity>) but with plain Entity as you can see from the logs. It
> then fails because due to
>          *** Can not deserialize instance of
> com.biovista.lib.datatype.Entity out of START_ARRAY token ****
>
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:41):
> **** called: arg0: class com.biovista.lib.datatype.Entity arg1: class
> com.biovista.lib.datatype.Entity arg2:
> [Ljava.lang.annotation.Annotation;@7f65ae66 providers:
> org.apache.cxf.jaxrs.impl.tl.ThreadLocalProviders@63aea6a8
> INFO
> com.biovista.ws.impl.jaxrs.JacksonJsonParamConverterProvider.getConverter(JacksonJsonParamConverterProvider.java:44):
> Annotation: @javax.ws.rs.FormParam(value=entities)
>
> Here is my ParamConverterProvider
>
>
> package com.biovista.ws.impl.jaxrs;
>
> import java.io.IOException;
> import java.lang.annotation.Annotation;
> import java.lang.reflect.Type;
>
> import javax.ws.rs.ProcessingException;
> import javax.ws.rs.core.Context;
> import javax.ws.rs.core.MediaType;
> import javax.ws.rs.ext.ContextResolver;
> import javax.ws.rs.ext.MessageBodyReader;
> import javax.ws.rs.ext.ParamConverter;
> import javax.ws.rs.ext.ParamConverterProvider;
> import javax.ws.rs.ext.Provider;
> import javax.ws.rs.ext.Providers;
>
> import org.apache.commons.logging.Log;
> import org.apache.commons.logging.LogFactory;
> import org.apache.cxf.jaxrs.ext.MessageContext;
> import org.codehaus.jackson.map.ObjectMapper;
>
> @Provider
> public class JacksonJsonParamConverterProvider implements
> ParamConverterProvider {
>      private final Log log = LogFactory.getLog(getClass());
>
>      @Override
>      public <T> ParamConverter<T> getConverter(final Class<T> rawType,
>              final Type genericType, final Annotation[] annotations) {
>
>          log.info("**** called: arg0: " + rawType + " arg1: " + genericType
>                  + " arg2: " + annotations + " providers: " + providers);
>          for (final Annotation annotation : annotations) {
>              log.info("Annotation: " + annotation);
>          }
>
>          return new ParamConverter<T>() {
>              @Override
>              public T fromString(final String value) {
>                  try {
>                      log.info("Called for " + value);
>                      return mapper.reader(rawType).readValue(value);
>                  } catch(IOException e) {
>                      throw new ProcessingException(e);
>                  }
>              }
>
>              @Override
>              public String toString(final T value) {
>                  try {
>                      return mapper.writer().writeValueAsString(value);
>                  } catch(Exception e) {
>                      throw new ProcessingException(e);
>                  }
>              }
>          };
>      }
> }
>
>
> How can I register different ParamConverterProvider for different input
> types? Or is that List is handled specially? By jackson or CXF? In
> jackson I just need to do
>          final List<Entity> entities = mapper.readValue(entities_json,
>              new TypeReference<List<Entity>>() {
>              });
>
> but I don't know how to do this from inside CXF. I am using CXF 3.0
>
>      Thanks