Tomcat, JAX-RS, Jersey, @PathParam: how to pass dots and slashes?

Maxim Suponya picture Maxim Suponya · Jun 21, 2012 · Viewed 11.2k times · Source

Having a method like this:

@GET @Path("/name/{name}")
@Produces(MediaType.TEXT_PLAIN)
public String getProperty(@PathParam("name") String name) {
        System.out.println(name);
}

How do I pass a value like "test./test"?

/name/test./test     gives HTTP 404
/name/test.%2Ftest   gives HTTP 400
/name/test.%252Ftest prints test%2Ftest

But if I do name = URLDecoder.decode(name); it prints /test and the first part of test. disappears.

There is one or two questions like this already but they are old and there was no good solution found, I thought I'll ask again.

Answer

Donal Fellows picture Donal Fellows · Jun 21, 2012

The pattern in the @Path annotation is internally turned into a regular expression, with the template parts matching only selected characters by default. In particular, they normally don't match / characters; that's almost always the right thing to do (as it lets you put templates part way through a path) but in this case it isn't as you're wanting to consume the whole subsequent path. To get everything, we have to override the regular expression fragment for that particular template; this is actually pretty easy, since we just put in the template fragment a : followed by the RE that we want to use:

@GET @Produces(MediaType.TEXT_PLAIN)
@Path("/name/{name:.+}")
public String getProperty(@PathParam("name") String name) {
    return name;
}

This will match all characters after the /name/ (up to but not including any ? query part) but will only match if there's something there at all. Be aware that if you have any other @Path("/name/...") things about, things can get really confusing! So don't do that.