Reputation: 2505
I'm building something of a relay server, using JAX-RS. I need to be able to extract any query parameters from a GET request and then re-wrap them into another request, to pass along to another server. I'm unfamiliar with MultivaluedMap
, but I just figured out what is happening. The UriInfo
class's getQueryParameters
method returns a MultivaluedMap<String, String>
. What bit me, unexpectedly, is that the values of each parameter are List
values, even though they purport to be String
values (by the way I read the JavaDoc).
In other words, if I have a key-value pair of foo=bar
, in the URL query string, when I extract the parameter, it comes out as foo=[bar]
. This totally throws me for a loop (a 500 Server Error, actually) when I try to re-wrap the parameter and send it along to the other server.
Is there another way to handle unpacking the query string from a Request, and then re-packing it for another Request? I'm including some code to illustrate my issue:
@GET
@Path("parameters")
public Response showParameters(@Context UriInfo uriInfo) {
MultivaluedMap<String, String> parameters = uriInfo.getQueryParameters();
StringBuffer sb = new StringBuffer();
sb.append("<h4>Parameters:</h4>");
if (parameters != null) {
sb.append("<ul>");
Iterator it = parameters.keySet().iterator();
while (it.hasNext()) {
String key = (String)it.next();
sb.append("<li>")
.append(key)
.append(": ")
.append(parameters.get(key))
.append("</li>");
}
sb.append("</ul>");
}
else {
sb.append("<p>None</p>");
}
return Response.ok(sb.toString()).build();
}
So, in summary, what gets printed out from the code above, if the request has query parameters, is something like this:
Parameters:
Is there another way to unpack/re-pack, and maybe avoid this whole issue altogether? Thanks.
@Jack deserves credit for pointing me in the right direction, and I am marking his answer as correct, but here is what I got working.
Client client = ClientBuilder.newClient();
// Assume instance variable providing URI (without query string).
WebTarget target = client.target(theRequestUri);
// Instance variable uriInfo.
MultivaluedMap<String, String> parameters = uriInfo.getQueryParameters();
if (parameters != null && parameters.size() > 0) {
Iterator it = parameters.keySet().iterator();
String key = null;
StringTokenizer st = null;
while (it.hasNext()) {
key = (String)it.next();
// RESTEasy API is quirky, here. It wraps the values in square
// brackets; moreover, each value is separated by a comma and
// padded by a space as well. ([one, two, three, etc])
st = new StringTokenizer(parameters.get(key).toString(), "[,]");
while (st.hasMoreTokens()) {
target = target.queryParam(key, st.nextToken().trim());
}
}
}
// Instance method: getContentType.
Response response = target.request().accept(getContentType()).get();
Upvotes: 3
Views: 6381
Reputation: 6960
Its because of MultivaluedMap interface.
public interface MultivaluedMap<K, V> extends Map<K, List<V>> {
It returns the values as List
.
Instead of parameters.get(key)
try parameters.getFirst(key)
Note that this will drop the other values for the same parameter. It is possible to send multiple values for same parameter while making a rest call such as blahblah:8080?foo=bar1&foo=bar2
. With getFirst()
call you will get bar1
value only. If you are sure you will not get multiple calls, you can go with getFirst(key)
approach
--- UPDATED --- Based on your comments, it seems you need to iterate over the multivalued map and call queryParam on the WebTarget instance. I understand you are looking for a library/straight forward way to do this. I did not try RESTEasy. But code I believe should be simple enough.
multiValuesMap?.each { key, values->
webTargetInstance = webTargetInstance.queryParam(key, values as Object[])
}
Upvotes: 3