We're using Dropwizard / Jersey to build a web service. The resource has a path and the method has a sub-path. When returning response created (201) the path of the method we're getting is prepended to the location we provide. When returning status OK with a location (contrived I know), all is well, and the location is returned just as we provided it.
How can we return a location that is not a sub-path of the location of our method?
In the example below: a get to "http://localhost/foo/bar" (created status) responds with location of "http://localhost/foo/bar/wibble" (note the /foo/bar)
while a get to "http://localhost/foo/baz" (ok status) responds with location of "http://localhost/wibble" which is what we want.
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.net.URI;
@Path("/foo")
public class FooResource {
@POST
@Path("/bar")
public Response bar() {
URI uriOfCreatedResource = URI.create("/wibble");
return Response.created(uriOfCreatedResource).build();
}
@POST
@Path("/baz")
public Response baz() {
URI uriOfCreatedResource = URI.create("/wibble");
return Response.ok().location(uriOfCreatedResource).build();
}
}
In case someone stumbles here wondering about this; I dug into Jersey's code to see why this happens. This should explain your problem & Carlo's workaround.
com.sun.jersey.spi.container.ContainerResponse contains this gem:
private void setHeaders(MultivaluedMap<String, Object> headers) {
this.headers = headers;
Object location = headers.getFirst(HttpHeaders.LOCATION);
if (location != null) {
if (location instanceof URI) {
final URI locationUri = (URI)location;
if (!locationUri.isAbsolute()) {
final URI base = (statusType.getStatusCode() == Status.CREATED.getStatusCode())
? request.getAbsolutePath() // WHY!?
: request.getBaseUri();
location = UriBuilder.fromUri(base).
path(locationUri.getRawPath()).
replaceQuery(locationUri.getRawQuery()).
fragment(locationUri.getRawFragment()).
build();
}
headers.putSingle(HttpHeaders.LOCATION, location);
}
}
}
In other words: for some reason, someone decided it was a good idea to treat the location header differently if the response status code is 201. Like Carlo noticed, using absolute paths avoids this issue.
Happened to me on GlassFish (JavaEE6). I think it's a bug, but I never managed to dig the code to the actual URI conversion....
I've found a workaround though:
public Response bar(@Context UriInfo info) {
URI absoluteURI=info.getBaseUriBuilder().path("/wibble").build();
return Response.created(absoluteURI).build();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With