Hi all,

So, I played around a bit more, and I now have a semi-working
solution. Semi-working, because I do get a List of enums back, which
is what I was actually after.
Not fully working, because it now blows up in the bowels of cxf (3.1.6).

Here is the mehtod signature - as a reminder, I'm trying to call
/foo;d=2016-10-06;f=a,b,c - and the LocalDate conversion works just
fine...
@GET
@Path("foo")
public Response foo(@MatrixParam("d") LocalDate date,
@MatrixParam("f") Foo foos) {
//...

Here is my ParamConverterProvider - it is registered and gets called
for matrix parameter f - yay!
public class StringListHandler implements ParamConverterProvider{
    @Override
    public <T> ParamConverter<T> getConverter(final Class<T> rawType,
Type genericType, Annotation[] annotations) {
        if(rawType == CommaSeparatedList.class) {
            return (ParamConverter<T>) new
ParamConverter<CommaSeparatedList>() {
                @Override
                public CommaSeparatedList fromString(String value) {
                    CommaSeparatedList list = new CommaSeparatedList(value);
                    return list;
                }
                @Override
                public String toString(CommaSeparatedList value) {
                    return value.toString();
                }
            };
        }
        return null;
    }
}

Here is my target type. It extends ArrayList - and I think that is now
the problem...
public class CommaSeparatedList extends ArrayList<Foo> {
    public CommaSeparatedList(String value) {
        List<String> list = Arrays.asList(value.split("\\s*,\\s*"));
        List<Foo> foos = new ArrayList<>(list.size());
        for (String element : list) {
            foos.add(Foo.valueOf(element.toUpperCase()));
        }
        addAll(foos);
    }
}

Here is the enum I'm using:
public enum Foo {
    A, B, C
}

And here are the Exception and StackTrace cxf now throws at me after I
return my CommaSeparatedList , i.e. ArrayList<Foo> (extending
Collection):
java.lang.IllegalArgumentException: argument type mismatch
argument type mismatch while invoking public javax.ws.rs.core.Response
com.example.rs.MyEndpoint.foo(org.joda.time.LocalDate,com.example.common.CommaSeparatedList)
with params [2016-10-06, [[A, B, C]]].
0 = {StackTraceElement@3424}
"org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:166)"
1 = {StackTraceElement@3425}
"org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:140)"
2 = {StackTraceElement@3426}
"org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189)"
3 = {StackTraceElement@3427}
"org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99)"
4 = {StackTraceElement@3428}
"org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59)"
5 = {StackTraceElement@3429}
"org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96)"
6 = {StackTraceElement@3430}
"org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)"
7 = {StackTraceElement@3431}
"org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)"
8 = {StackTraceElement@3432}
"org.apache.cxf.transport.local.LocalConduit.dispatchDirect(LocalConduit.java:191)"
9 = {StackTraceElement@3433}
"org.apache.cxf.transport.local.LocalConduit.close(LocalConduit.java:156)"
10 = {StackTraceElement@3434}
"org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)"
11 = {StackTraceElement@3435}
"org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)"
12 = {StackTraceElement@3436}
"org.apache.cxf.jaxrs.client.AbstractClient.doRunInterceptorChain(AbstractClient.java:652)"
13 = {StackTraceElement@3437}
"org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1097)"
14 = {StackTraceElement@3438}
"org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:894)"
15 = {StackTraceElement@3439}
"org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:865)"
16 = {StackTraceElement@3440}
"org.apache.cxf.jaxrs.client.WebClient.invoke(WebClient.java:331)"
17 = {StackTraceElement@3441}
"org.apache.cxf.jaxrs.client.WebClient.get(WebClient.java:357)"

I think the problem is in
AbstractInvoker.performInvocation(performInvocation.java:172) - mainly
because my debugger output at that position looks like this:
paramArray: Object[]  = {Object[2]@3320}
  0 = {LocalDate@3270} "2016-10-06"
  1 = {ArrayList@3295}  size = 1
    0 = {CommaSeparatedList@3294}  size = 3

I think what I'd actually need - to conform with the method signature
of my foo() method in my endpoint from above - is something that looks
a bit more like this (i.e. without the extra ArrayList layer):
paramArray: Object[]  = {Object[2]}
0 = {LocalDate}
1 =  {CommaSeparatedLis}  size = 3

Any idea how I can get that sorted, please?

Again, the goal is to convert ;f=a,b,c into List<Foo>[3] with elements
A, B, and C...

Kind regards,
Christian

On Thu, Oct 6, 2016 at 12:20 AM, Christian Balzer
<christian.at....@gmail.com> wrote:
> Hi all,
>
> We are using cxf with Spring at work, and I have a newbie question...
>
> This is my method signature:
>
> @GET
> @Path("foo")
> public Response foo(@MatrixParam("l") List<String> myList) {
>
> From that, I want to get a list back with the initial input String (to
> my matrix parameter l) being split into list elements at any comma,
> i.e. I want e.g. ";l=a,b,c" to turn into a list of three elements: a,
> b and c.
>
> My converter below is registered (a breakpoint in it is triggered for
> myList), but instead of passing rawType as List, I get rawType as
> String (so it doesn’t do anything).
>
> public class StringListHandler implements ParamConverterProvider {
>     @Override
>     public <T> ParamConverter<T> getConverter(final Class<T> rawType,
> Type genericType, Annotation[] annotations) {
>         if(rawType == List.class) {
>             return new ParamConverter<T>() {
>                 @Override
>                 public T fromString(String value) {
>                     return
> rawType.cast(Arrays.asList(value.split("\\s*,\\s*")));
>                 }
>
>                 @Override
>                 public String toString(T value) {
>                     return value.toString();
>                 }
>             };
>         }
>         return null;
>     }
> }
>
>
> Interestingly enough, I do get a list back. But instead of three
> elements a, b and c, it only seems to have one: a,b,c
>
> What piece of JAX-RS/cxf voodoo am I missing to make this work? ;-)
>
> Is it maybe because cxf comes with a default implementation for a
> List<String> converter so it can turn a URL like foo?l=a&l=b&l=c into
> a List<String> ? Does that also get called for foo;l=a;l=b;l=c ? (I
> thought that c would overwrite a in that situation?)
>
> Do I have to use a custom class with a List<String> property, like
> class MyContainer {
>   public List<List> l;
> }
>
> and change the method signature from above to
> public Response foo(@MatrixParam("l") MyContainer myContainer) {
>
> then check for MyContainer.class in ParamConverterProvider and change
> the fromString() method to
> public T fromString(String value) {
>   MyContainer mC = new MyContainer();
>   mc.l = Arrays.asList(value.split("\\s*,\\s*"));
>   return rawType.cast(mc);
> }
>
> Or should I create a custom argument annotation, say @CommaSeparated,
> and have ParamConverterProvider check for that (and
> rawType==String.class)?
> But if I do that, won't I get a List<List<String>> back?
>
> Any help much appreciated!
>
> Kind regards,
>
> Christian

Reply via email to