I've created a JAX-RS service (MyService) that has a number of sub resources, each of which is a subclass of MySubResource. The sub resource class being chosen is picked based on the parameters given in the MyService path, for example:
@Path("/") @Provides({"text/html", "text/xml"})
public class MyResource {
@Path("people/{id}") public MySubResource getPeople(@PathParam("id") String id) {
return new MyPeopleSubResource(id);
}
@Path("places/{id}") public MySubResource getPlaces(@PathParam("id") String id) {
return new MyPlacesSubResource(id);
}
}
where MyPlacesSubResource and MyPeopleSubResource are both sub-classes of MySubResource.
MySubResource is defined as:
public abstract class MySubResource {
protected abstract Results getResults();
@GET public Results get() { return getResults(); }
@GET @Path("xml")
public Response getXml() {
return Response.ok(getResults(), MediaType.TEXT_XML_TYPE).build();
}
@GET @Path("html")
public Response getHtml() {
return Response.ok(getResults(), MediaType.TEXT_HTML_TYPE).build();
}
}
Results is processed by corresponding MessageBodyWriters depending on the mimetype of the response.
While this works it results in paths like /people/Bob/html or /people/Bob/xml where what I really want is /people/Bob.html or /people/Bob.xml
Does anybody know how to accomplish what I want to do?
Old topic, but this is something I solved recently using Jersey; perhaps it'll help someone else.
Jersey supports specifying the accepted content type as a file extension in the URI through the use of request filters. Jersey supplies a UriConnegFilter
(URI Content Negotiation Filter) object that you extend to translate specific extensions to content types. You then include that filter as an initial parameter to the Jersey application.
Since that all sounds so vague, here's a concrete example from my project:
I wanted to be able to interpret ".json" and ".xml" at the end of the URL as meaning that the client wanted JSON-formatted or XML-formatted content, respectively. To that end, I extended UriConnegFilter
like so:
package my.filter.package;
import com.sun.jersey.api.container.filter.UriConnegFilter;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.MediaType;
public class MediaTypeFilter extends UriConnegFilter {
private static final Map<String, MediaType> mappedMediaTypes = new HashMap<String, MediaType>(2);
static {
mappedMediaTypes.put("json", MediaType.APPLICATION_JSON_TYPE);
mappedMediaTypes.put("xml", MediaType.APPLICATION_XML_TYPE);
}
public MediaTypeFilter() {
super(mappedMediaTypes);
}
}
Then, since I am using Jersey as a Servlet, I added MediaTypeFilter
to my web.xml:
<servlet>
<servlet-name>My Jersey Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>my.resource.package</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter;
my.filter.package.MediaTypeFilter;
com.sun.jersey.api.container.filter.PostReplaceFilter;
com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter;
com.sun.jersey.api.container.filter.LoggingFilter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
With that in place, Jersey translates the extension on the URI into the specified media type, and removes the extension. This works for root resources and sub-resources because it operates on the whole URI. For your particular example, /people/Bob.xml would become /people/Bob and the Accept
header in the request would be changed to "application/xml" (overriding any existing Accept
header).
hth,
-Peter
You could possibly write some servlet routing to work it out. Realistically though, you should be using Content Types to do this.
@GET @Path("/") @Produces(MediaType.APPLICATION_XML)
public Response getXml() { ... }
@GET @Path("/") @Produces(MediaType.APPLICATION_HTML)
public Response getHtml() { ... }
The JAX-RS provider will then work out what to call based on the client's request. Even better, you could us JAXB and RestEASY to do it all for you!
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("/{id}")
public MyObject getXml(@PathParam("typeDocument") String id) {
myObjectService.get(id);
}
@XmlRootElement(name="myObject")
public class MyObject {
// Some properties
}
See http://java.dzone.com/articles/resteasy-spring for a good example with Spring.
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