I was begun learn jersey for development restful web services.
As I noticed in most of the examples uses following annotations:
@Consumes
defines format of input parameters
@Produces
defines format of output parameters
But in real code I see method which looks like this:
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/login")
public Response login(@FormParam("login") final String username, @FormParam("password") final String password){...}
I see that this method uses POST
HTTP method. Parameters userName
and password
will have form according @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
. and I see URL to execute this method.
But I don't understand what this method returns. Which format?
I just want to clarify that "By Default Jersey produces "application/octet-stream" if it's not specified" is not entirely true. There's actually a lot of complexity going on behind the scenes, that determines the final Content-Type
. As stated in the spec:
Note that the above (actually below :-) renders a response with a default media type of
application/octetstream
when a concrete type cannot be determined.
But, like I said, there is a complex algorithm that goes into determining this "concrete type". And not many cases I've tested will return application/octet-stream
. It goes as follows (this is directly from spec. You can try and make head or tails of it, but it's not for the layperson):
3.8 Determining the MediaType of Responses
In many cases it is not possible to statically determine the media type of a response. The following algorithm is used to determine the response media type, Mselected, at run time:
If the method returns an instance of
Response
whose metadata includes the response media type (Mspecified) then set Mselected = Mspecified, finish.Gather the set of producible media types P:
- If the method is annotated with
@Produces
, set P = {V(method)} where V (t
) represents the values of@Produces
on the specified targett
.- Else if the class is annotated with
@Produces
, set P = {V (class)}.- Else set P = {V (writers)} where '
writers
' is the set ofMessageBodyWriter
that support the class of the returned entity object.If P = {}, set P = {
'*/*'
}Obtain the acceptable media types A. If A = {}, set A = {
'*/*'
}Set M = {}. For each member of A;
a
:
- For each member of P;
p
:
- If a is compatible with
p
, add S(a
;p
) to M, where the functionS
returns the most specific media type of the pair with the q-value ofa
and server-side qs-value ofp
.If M = {} then generate a
NotAcceptableException
(406 status) and no entity. The exception MUST be processed as described in Section 3.3.4. Finish.Sort M in descending order, with a primary key of specificity
(n/m > n/* > */*)
, a secondary key of q-value and a tertiary key of qs-value.For each member of M;
m
:
- If
m
is a concrete type, set Mselected =m
, finish.If M contains
'*/*'
or'application/*
', set Mselected ='application/octet-stream'
, finish.Generate a
NotAcceptableException
(406 status) and no entity. The exception MUST be processed as described in Section 3.3.4. Finish.
You can see it's not as easy as saying it will always default to application/octet-stream
. Simple example
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createCustomer(@FormParam("id") int id,
@FormParam("name") String name) {
return Response.ok("OK I GOT IT").build();
}
The above will return Content-Type: text/plain
Say you create a Customer
object and return it
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createCustomer(@FormParam("id") int id,
@FormParam("name") String name) {
Customer customer = new Customer(id, name);
return Response.ok(customer).build();
}
From what I have tested, it will return Content-Type: application/xml
and yes the body content will be xml.
Now if we send the request with an Accept
header of application/json
, we will get a response header of Content-Type: application/json
, as yes the body content will be json. This is where Content Negotiation plays a factor
If we just responded with a 201 Created
, which is very common in POST
/create requests
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createCustomer(@FormParam("id") int id,
@FormParam("name") String name) {
return Response.created(someNewUri).build();
}
there will be no Content-Type
response header, as there's no content.
Now some of the example above aren't great REST princial examples, but it goes to show, that a lot goes in to determining the media type, if we don't explicitly set it with @Produces
. You have to consider, the body of the response, available MessageBodyWriters
, you have Content Negotiation to factor in, and whatever else is in that mumbo-jumbo from the spec. (Note: I've bolded the'Content Negotiation' link because it is a concept you should really get familiar with when working with REST. It actually plays a big part with JAX-RS/Jersey).
So really the answer to your question is it depends. But hopefully you've gained some extra knowledge from this post :-)
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