We started using Jersey/JAX-RS for internal REST endpoints that get used by our front-end code. Endpoints that have to return a result, always send JSON objects.
For deb
You should always declare the @Produces
and @Consumes
annotations (either at the class level or method level) for the purpose of Content Negotiation and HTTP protocol correctness. Without these annotations, the result will be dependent on the client request and the default behavior of the server (which may be different across implementations), which leads to unpredictable and ambiguous results.
With these annotations, we advertise what media types we can produce and consume. On Retrieve (GET) requests, the client should send an Accept
header with the media type of the resource they expect back. And on Create requests (PUT, POST), the client should send a Content-Type
header telling the server what media type the data is that they are sending. If these headers don't match what the server is advertised to handle, then the client will get error responses back telling them what the problem is; with a Retrieve request and a non-matching Accept
header, the response will be a 406 Not Acceptable. With a Create request and a non-matching Content-Type
header, the response will be a 415 Unsupported Media Type.
This is how content negotiation works. And to make sure our server behaves as the clients expect, we should declare what we can handle on the server. The annotations do just this.
As you mentioned, when you left off the @Produces
, the client told you you needed to change the response type. This is because the result was that the Content-Type
response header was set to application/octet-stream
, which is what the answers here conclude. Clients use the Content-Type
header to determine how to handle the response.
That last example was for a Retrieve request. If we left off the @Consumes
on a Create endpoint, a lot of different things can go wrong. Take for example we have an endpoint that we want to accept JSON, so we create a POJO to map the JSON to.
@POST
public Response create(Customer customer) {}
For this to work, it is dependent on the client setting the Content-Type
header on the request to application/json
. But without the @Consumes
annotation, we are basically advertising this endpoint to be able to accept any media type, which is just ridiculous. The @Consumes
annotation acts like a guard saying "If you don't send the right type of data, you cannot pass". But since we don't have the guard, all data is allowed through, and the result is unpredictable, because depending on what the client sets the Content-Type
to, we don't know what MessageBodyReader
1 will handle the conversion from the entity body to Customer
. If the correct MessageBodyReader
is not chosen (the one that converts JSON to POPJOs), then most likely it will lead to an exception, and the client will get back a 500 Internal Server Error, which is not as specific as getting a 415 Unsupported Media Type.
1. See chapter 8 and 9 of the Jersey docs. It will explain how entity bodies are converted to Java objects (and vice versa) using MessageBodyReader
and MessageBodyWriter
, respectively.