I wanted to avoid having to do matrixParams.getList().get(0) when all I wanted was matrixParams.get(0)... :) That's the only reason, really...
I thought if I have to convert partially in my class, I can just do all of the conversion in my class, and not use cxf's facility at all. And I thought it would work. I'm pretty sure I saw REST URLs in the past that used ;range=10,90 for example - so I was sure cxf would support it somehow... :) Cheers, Christian On Thu, Oct 6, 2016 at 2:58 PM, Sergey Beryozkin <[email protected]> wrote: > Hi, why would you not have > > class MatrixParams { > List<String> list; > } > > @MatrixParam("a") MatrixParams > > Sergey > > > On 06/10/16 14:23, Christian Balzer wrote: >> >> Hello, >> >> Well, you just pointed out that the converters are only supposed to >> work on an individual element of a collection, and cxf' code is >> looking at the param type to see if it is dealing with a collection >> target type (which it will create at runtime, as you pointed out), to >> which it needs to add these elements. So it basically gets confused >> because I've defined my own collection type. It assumes it needs to >> create a collection to add elements to, but the elements I create are >> my own collection. That's how I end up with >> Collection<Collection<Enum>>. Short of cxf checking the actual type of >> the target parameter instead of whether it implements the Collection >> interface, I don't think there is any way around it? >> >> In other words, what I wanted to do won't work in cxf. :/ >> >> Regards, >> >> Christian >> >> On Thu, Oct 6, 2016 at 1:41 PM, Sergey Beryozkin <[email protected]> >> wrote: >>> >>> Hi >>> >>> Looks like a linking issue, >>> >>> Sergey >>> >>> On 06/10/16 13:24, Christian Balzer wrote: >>>> >>>> >>>> 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 >>>> <[email protected]> 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 >>> >>> >>> >>> >>> -- >>> Sergey Beryozkin >>> >>> Talend Community Coders >>> http://coders.talend.com/ > >
