Store @PathParam values from REST call in a list or array
My function looks like this:
@PUT
@Path("property/{uuid}/{key}/{value}")
@Produces("application/xml")
public Map<String,ValueEntity> updateProperty(@Context HttpServletRequest request,
@PathParam("key") String key,
@PathParam("value") String value,
@PathParam("uuid") String uuid) throws Exception {
...
}
I need to change it so it accepts an undefined (or many) list of key-value pairs from a REST call, something like
@Path("property/{uuid}/{key1}/{value1}/{key2}/{value2}/{key3}/{value3}/...")
Is it possible to store them in an array or a list, so I don't list dozens of @PathParams and parameters to avoid this:
@PathParam("key1") String key1,
@PathParam("key2") String key2,
@PathParam("key3") String key3,
source to share
It might be a good opportunity to rethink this design. By using /
s, we denote, with each one /
, that we are trying to find another resource. Key / value pair (in the context of a URL) mainly refers to query parameters or matrix parameters.
If /property/{uuid}
is the path to the main resource and we just want to offer some parameters to the client to access that resource, then we can allow matrix parameters or query parameters
The matrix parameters (in the request url) will look something like this:
/12345;key1=value1;key2=value2;key3=value3
A resource method for getting values might look something like this:
@GET
@Path("/property/{uuid}")
public Response getMatrix(@PathParam("uuid") PathSegment pathSegment) {
StringBuilder builder = new StringBuilder();
// Get the {uuid} value
System.out.println("Path: " + pathSegment.getPath());
MultivaluedMap matrix = pathSegment.getMatrixParameters();
for (Object key : matrix.keySet()) {
builder.append(key).append(":")
.append(matrix.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
- Cm.
PathSegment
The request parameters (in the request url) might look something like this:
/12345?key1=value1&key2=value2&key3=value3
A resource method for getting values might look something like this:
@GET
@Path("/property/{uuid}")
public Response getQuery(@PathParam("uuid") String uuid,
@Context UriInfo uriInfo) {
MultivaluedMap params = uriInfo.getQueryParameters();
StringBuilder builder = new StringBuilder();
for (Object key : params.keySet()) {
builder.append(key).append(":")
.append(params.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
- Cm.
UriInfo
The difference is that Matrix parameters can be embedded in route segments, and query parameters must be placed at the end of the URL. You may also notice a slight difference in syntax.
Some resources
- Query string (Wikipedia)
- When to use query parameters versus matrix parameters?
- URL matrix parameters versus query parameters
UPDATE
Also looking at PUT
in your method signature it seems you are trying to update the resource using that path as the values you are trying to update, since I don't see any parameters in your method for the subject. When PUTting, you should send the view to the entity body, not as segments or path parameters.
source to share
Workaround:
@Path("/foo/bar/{other: .*}
public Response foo(@PathParam("other") VariableStrings vstrings) {
String[] splitPath = vstrings.getSplitPath();
}
VariableStrings class:
public class VariableStrings {
private String[] splitPath;
public VariableStrings(String unparsedPath) {
splitPath = unparsedPath.split("/");
}
}
Sequence segment path to vararg array in JAX-RS / Jersey?
Another example where you map an optional parameter to Map:
@GET
@ Produces({"application/xml", "application/json", "plain/text"})
@ Path("/location/{locationId}{path:.*}")
public Response getLocation(@PathParam("locationId") int locationId, @PathParam("path") String path) {
Map < String, String > params = parsePath(path);
String format = params.get("format");
if ("xml".equals(format)) {
String xml = "<location<</location<<id<</id<" + locationId + "";
return Response.status(200).type("application/xml").entity(xml).build();
} else if ("json".equals(format)) {
String json = "{ 'location' : { 'id' : '" + locationId + "' } }";
return Response.status(200).type("application/json").entity(json).build();
} else {
String text = "Location: id=" + locationId;
return Response.status(200).type("text/plain").entity(text).build();
}
}
private Map < String, String > parsePath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
String[] pathParts = path.split("/");
Map < String, String > pathMap = new HashMap < String, String > ();
for (int i = 0; i < pathParts.length / 2; i++) {
String key = pathParts[2 * i];
String value = pathParts[2 * i + 1];
pathMap.put(key, value);
}
return pathMap;
}
source to share