3 Replies Latest reply on Dec 10, 2010 7:22 AM by wortmanb.bdw.techma.com

    RESTEasy with optional QueryParams

    wortmanb.bdw.techma.com

      I'd like to build a query service which accepts one or more query parameters and allows one of them to repeat.  I've tried this using the following interface definition:




           
      @GET
      @Produces("application/xml")
      @Path("/SSR")
      public List<Message> querySSR(
                @QueryParam("sessionId") String sessionId,
                @QueryParam("designator") String designator,
                @QueryParam("cflo") Double cflo,
                @QueryParam("cfhi") Double cfhi,
                @QueryParam("startTime") Date startTime,
                @QueryParam("endTime") Date endTime,
                @QueryParam("node") List<String> participants);



      When I try to invoke this service with, for example, just sessionId, I get back a 400 error.  The invocation looks like this:


      IMessageResource client = ProxyFactory.create(IMessageResource.class, url);
      ml = client.querySSR("xx", null, null, null, null, null, null);
      



      I'd like to provide the consumers of this service a nice java interface like this but am not sure how to do that if I change the interface to parse out the query parameters in the code itself.  Any suggestions?

        • 1. Re: RESTEasy with optional QueryParams
          wortmanb.bdw.techma.com

          I have created a version of this web service which parses out the provided query params, and can invoke it via ClientRequest.  The problem now is turning the results back into a List<Message>:


          ClientRequest request = new ClientRequest(myurl);
          request.queryParameter("sessionId", "xx");
          List<Message> ml = request.getTarget(List.class);
          


          This fails:


          org.jboss.resteasy.client.ClientResponseFailure: Unable to find a MessageBodyReader of content-type application/xml and type interface java.util.List
               at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:414)
               at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:405)
               at org.jboss.resteasy.client.core.BaseClientResponse$3.createReaderNotFound(BaseClientResponse.java:349)
               at org.jboss.resteasy.core.messagebody.ReaderUtility.doRead(ReaderUtility.java:106)
               at org.jboss.resteasy.client.core.BaseClientResponse.readFrom(BaseClientResponse.java:354)
               at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:318)
               at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:279)
               at org.jboss.resteasy.client.ClientRequest.getTarget(ClientRequest.java:499)
               at com.techma.shepherd.client.TestClient.testMessageSSR(TestClient.java:1342)
               at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
               at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
               at java.lang.reflect.Method.invoke(Unknown Source)
               at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
               at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
               at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
               at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
               at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
               at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
               at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
               at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
               at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
               at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
               at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
               at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
               at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
               at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
               at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
               at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
               at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
               at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
          



          I know this can be done, because my services are returning lists of Message in other cases, but in each of those, I can use a ProxyFactory-generated client to access the method and don't see a way to do the same for this method.  Its definition follows for completeness.


          @GET
          @Produces("application/xml")
          @Path("/SSR")
          public List<Message> querySSR(@Context UriInfo info);
          



          What is the correct or best way to handle implementing the client side of a method like this, or is there another way to define the service which would allow use of the generated client?

          • 2. Re: RESTEasy with optional QueryParams
            lvdberg

            Hi,


            You should have a holder List which can be marshalled to XML. I made a simple class which serves as a XMLRoot element and includes the list with the elements. That solves your problem.


            Leo

            • 3. Re: RESTEasy with optional QueryParams
              wortmanb.bdw.techma.com

              I ended up going a step further and creating a request class with a builder:


              @XmlRootElement(name = "ssr-request")
              public class SSRRequest {
              
                   public static class Builder {
              
                        private String sessionId = null;
                        private String designator = null;
                        private BigDecimal cflo = null;
                        private BigDecimal cfhi = null;
                        private BigDecimal startTime = null;
                        private BigDecimal endTime = null;
                        private List<String> participants = null;
              
                        public SSRRequest build() {
                             return new SSRRequest(this);
                        }
              
                        public Builder setSessionId(String sessionId) {
                             this.sessionId = sessionId;
                             return this;
                        }



              and so on.  This is working like a champ.