3

I'm using Jersey 1.17.1 and on every URL I've created I want to allow people to put ".json" at the end or not. Here's an example of what I've done:

@GET
@Path("basepath{extension: (\\.json)?}")
public String foobar() {
    ...
}

Eventually I'm going to let them choose between nothing, ".json" or ".xml" and I'm concerned about my DRY violation here. I'll have to change every @Path to this instead:

@GET
@Path("basepath{extension: (\\.json|\\.xml)?}")
public String foobar() {
    ...
}

Is there a better way to do this that lets my path value be more reusable? Although I can't use Jersey 2.0, I'd be interested to know if it can solve this problem.

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356

2 Answers2

5

One way to do this is to subclass PackagesResourceConfig and inform Jersey which extensions should map to which media types. For instance:

public class ExampleResourceConfig extends PackagesResourceConfig {
  @Override
  public Map<String, MediaType> getMediaTypeMappings() {
    Map<String, MediaType> map = new HashMap<>();
    map.put("xml", MediaType.APPLICATION_XML_TYPE);
    map.put("json", MediaType.APPLICATION_JSON_TYPE);
    return map;
  }
}

and then your actual REST service might look like:

@GET
@Path("basepath")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response foobar() {
  ...   
}

Jersey will select the appropriate media type based on the url extension. Note that Response is returned instead of String. I'm not sure how you're building your response and what your requirements are but Jersey can handle converting your Java beans into either XML or JSON (or even JSONP) without a problem.

condit
  • 10,852
  • 2
  • 41
  • 60
  • That's pretty cool. What if I threw another requirement in there: I want one special path to be for PDF. Can that be accomplished by avoiding it in the `getMediaTypeMappings` and explicitly setting it as a `@Produces` on the resource code? – Daniel Kaplan Sep 18 '13 at 00:24
  • 1
    Sure - you've got some options there. I would still add PDF to your media type mappings. You could write a separate method with the same `@Path` that just `@Produces` PDF. You could add PDF to the `@Produces` of your existing method, detect if PDF was requested by the client and modify the response accordingly. Or, if your response beans are conducive to it, you could implement a [MessageBodyWriter](https://jsr311.java.net/nonav/javadoc/javax/ws/rs/ext/MessageBodyWriter.html) that `@Produces` PDF. Then you would just add `@Produces` PDF to your existing foobar method and you're done. – condit Sep 18 '13 at 14:28
  • This option also handles requests with no URL extension: Jersey will serve the first `MediaType` annotation unless the client adds an `Accept` header, in which case Jersey will serve that media type. This way you can comply with accept headers and have the convenience of changing the return type by changing the URL extension in your browser. – condit Sep 18 '13 at 16:44
  • 1
    Note that in Jersey 2.x, you can just set `init-param` _jersey.config.server.mediaTypeMappings_ in web.xml, with a value containing a list of name:value extension pairs: ` jersey.config.server.mediaTypeMappings txt : text/plain, xml : application/xml, json : application/json ` – Buzz Killington Oct 03 '14 at 16:01
  • @condit I am doing a similar thing in my application and am facing an issue. When i make a GET call with .xml as extension, I am getting the expected response where as, when i am trying with .json, it is returning an empty response with 200. What could be the issue? – doctore Sep 06 '16 at 15:09
0

In the REST API implementation , the resource representation can be either xml or json or etc. This is not a good way of restful implementation if you specify the types as the extensions of the URL. The correct way is to use HTTP ACCEPT header

like Accept: application/json or

Accept: application/xml

Refer : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Vineet Singla
  • 1,609
  • 2
  • 20
  • 34
  • 2
    I think if you're going to be pedantic, you're right. But the benefit of being able to test this in the browser is totally worth it in my opinion. – Daniel Kaplan Sep 18 '13 at 07:25
  • Actually, please take this opportunity to enlighten me: What bad things will happen if I violate this? – Daniel Kaplan Sep 18 '13 at 16:22
  • A resource has its representation and a unique URL. but in this scenario the same resource will be represented by different URLs. So from the client perspective it has 2-3 different URls represtenting the same resource and could create confusion. Consider u have 3 formats xml,json,html , so u would have to provide 3 urls. And as far as the representation format is considered we can provide this in HTTP header, and URL remains the same. – Vineet Singla Sep 19 '13 at 04:59