3

I'm looking for a way to pass a map that contains param names and values to a GET Web Target. I am expecting RESTEasy to convert my map to a list of URL query params; however, RESTEasy throws an exception saying Caused by: javax.ws.rs.ProcessingException: RESTEASY004565: A GET request cannot have a body. . How can I tell RESTEasy to convert this map to a URL query parameters?

This is the proxy interface:

@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
public interface ExampleClient {

    @GET
    @Path("/example/{name}")
    @Produces(MediaType.APPLICATION_JSON)
    Object getObject(@PathParam("name") String name, MultivaluedMap<String, String> multiValueMap);

}

This is the usage:

@Controller
public class ExampleController {

  @Inject
  ExampleClient exampleClient; // injected correctly by spring DI

  // this runs inside a spring controller
  public String action(String objectName) {
      MultivaluedMap<String, String> params = new MultivaluedHashMap<>();

      // in the real code I get the params and values from a DB
      params.add("foo", "bar")
      params.add("jar", "car")
      //.. keep adding

      exampleClient.getObject(objectName, params); // throws exception
  }

}
0

2 Answers 2

4

After hours digging down in RESTEasy source code, I found out that there is no way to do that though interface annotation. In short, RESTEasy creates something called a 'processor' from org.jboss.resteasy.client.jaxrs.internal.proxy.processors.ProcessorFactory to map the annotation to the target URI.

However, it is really simple to solve this issue by creating a ClientRequestFilter that takes the Map from the request body (before executing the request of course), and place them inside the URI query param. Check the code below:

The filter:

@Provider
@Component // because I'm using spring boot
public class GetMessageBodyFilter implements ClientRequestFilter {
    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        if (requestContext.getEntity() instanceof Map && requestContext.getMethod().equals(HttpMethod.GET)) {
            UriBuilder uriBuilder = UriBuilder.fromUri(requestContext.getUri());
            Map allParam = (Map)requestContext.getEntity();
            for (Object key : allParam.keySet()) {
                uriBuilder.queryParam(key.toString(), allParam.get(key));
            }
            requestContext.setUri(uriBuilder.build());
            requestContext.setEntity(null);
        }
    }
}

PS: I have used Map instead of MultivaluedMap for simplicity

Sign up to request clarification or add additional context in comments.

Comments

0

Nowadays it can be achieved using @RestQuery annotation

 @GET
 Set<Extension> getByFilter(@RestQuery Map<String, String> filter);

Each Map entry represents exactly one query parameter

This is example from official documentation to Quarkus 3.24.4
https://quarkus.io/guides/rest-client#query-parameters

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.