1
votes

I have the following json structure:

{
    "foo" : {
        "foo1" : {
            "txt" : "val",
            "txt1" : "val1",
            "txt2" : "val2",
        },
        "foo2" : {
            "txt" : "val",
            "txt1" : "val1",
            "txt2" : "val2",
        }
    },
    "bar" : {
        "bar1": {
            "txt" : "val",
            "txt1" : "val1",
            "txt2" : "val2",
        },
        "bar2": {
            "txt" : "val",
            "txt1" : "val1",
            "txt2" : "val2",
        }
    }
}

While i have the following pojo:

class Pojo {
  String txt;
  String txt1;
  String txt2;
}

And my resteasy method looks like:

@POST
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
@Path("/foo")
public void bar(@QueryParam("jsonObj") Map<String,Map<String,Pojo>> jsonObj);

However while starting the server i get the following error:

java.lang.RuntimeException: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam("jsonObj") on public abstract void com.foo.FooBar.bar(java.util.Map) for basetype: java.util.Map at org.jboss.resteasy.core.StringParameterInjector.initialize(StringParameterInjector.java:217) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.StringParameterInjector.(StringParameterInjector.java:61) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.QueryParamInjector.(QueryParamInjector.java:28) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.InjectorFactoryImpl.createParameterExtractor(InjectorFactoryImpl.java:85) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.MethodInjectorImpl.(MethodInjectorImpl.java:42) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.InjectorFactoryImpl.createMethodInjector(InjectorFactoryImpl.java:76) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.ResourceMethodInvoker.(ResourceMethodInvoker.java:100) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.ResourceMethodRegistry.processMethod(ResourceMethodRegistry.java:280) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.ResourceMethodRegistry.register(ResourceMethodRegistry.java:251) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:221) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:193) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:179) ~[resteasy-jaxrs-3.0.9.Final.jar:na] at org.jboss.resteasy.plugins.spring.SpringBeanProcessor.onApplicationEvent(SpringBeanProcessor.java:486) ~[resteasy-spring-3.0.9.Final.jar:na] at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:96) ~[spring-context-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:334) ~[spring-context-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:948) ~[spring-context-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) ~[spring-context-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410) ~[spring-web-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) ~[spring-web-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) [spring-web-3.2.8.RELEASE.jar:3.2.8.RELEASE] at org.jboss.resteasy.plugins.spring.SpringContextLoaderListener.contextInitialized(SpringContextLoaderListener.java:48) [resteasy-spring-3.0.9.Final.jar:na] at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939) [catalina.jar:7.0.47] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) [catalina.jar:7.0.47] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.47] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) [catalina.jar:7.0.47] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) [catalina.jar:7.0.47] at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0-45] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0-45] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0-45] at java.lang.Thread.run(Thread.java:744) [na:1.7.0-45]

I went through the documentation and for Complex Objects it says to use StringConvertor, but shouldn't it be supported for a simple types like List, Map etc...

1
As the error message (and the documentation) states, you can't automatically inject parameters into a map as it is an interface and therefore has no constructor with only a single parameter and no valueOf() or fromString() methods. You can however try to define a custom javax.ws.rs.ext.ParamConverter implementation which creates a Map for you. - Roman Vottner
Furthermore, do you really provide this JSON structure as query-parameter? - Roman Vottner
So in my custom convertor in the fromString, i would have to parse the json and convert into a Map assign back to the Map? If that's the case then i'm better off just accepting the param as a string and converting it there itself - user320550
"Furthermore, do you really provide this JSON structure as query-parameter?" Good point. Since it's a POST i think i'm better off using the @FormParam - user320550
None of the parameter annotations is appropriate in this case as you obviously send the JSON as body in a POST request. Do you have control over the JSON format? If so, change it to contain lists of foo's (or bar's) which furthermore contain lists of foo1's (or bar1's) which actually contain your pojo and update your pojo to fit the modified design. If not, simply use an InputStream or String method parameter (withoug any annotations) and create the object on your own (or use a MessageBodyReader to convert the input-stream to your pojos). - Roman Vottner

1 Answers

1
votes

Instead of taking the JSON in Map> jsonObj format , you can use InputStream and then you can process the input stream to get the objects out of it.