Open jerseyrobot opened 7 years ago
@pavelbucek Commented It might seem inconsistent, but it should be compliant with the JAX-RS Spec, chapter "3.8 Determining the MediaType of Responses"
we can't change the implementation without changing the spec.
@NicoNes Commented Hi @pavelbucek,
Actually I red this chapter of the spec before writting the issue and I still keep on saying that this inconsistency is not because of the spec. Lets apply the spec step by step for each of the two cases I used:
1st case: method annotated with @Produces({ "*/xml" })
and Accept header set to "application/*"
Not applicable in our case
P = {"*/xml"}
P is not empty so P = {"*/xml"}
A is not empty so A = {"application/*"}
MediaType.valueOf("application/*").isComptatible(MediaType.valueOf("*/xml"))
returns true so M = {"application/*"} (the most specific).
M is not empty so lets jump to step 7
M.length = 1 so sort operation returns M = {"application/*"}
As M does not contain any concrete type the selected media type can not be determinated here. Go to step 9
M contains {"application/*"} so selected media type is Mselected = "application/octet-stream"
2nd case: method annotated with @Produces({ "*/xml", "application/octet-stream" })
and Accept header set to "application/*"
Not applicable in our case
P = {"*/xml", "application/octet-stream"}
P is not empty so P = {"*/xml", "application/octet-stream"}
A is not empty so A = {"application/*"}
Both MediaType.valueOf("application/*").isComptatible(MediaType.valueOf("*/xml"))
and MediaType.valueOf("application/*").isComptatible(MediaType.valueOf("application/octet-stream"))
returns true so M = {"application/*", "application/octet-stream"} (the most specific).
M is not empty so lets jump to step 7
Sort operation returns M = {"application/octet-stream", "application/*"}
As M contains a concrete type the selected media type is Mselected = "application/octet-stream". Finish so no need to process other steps
So according to the spec in both cases the selected media type should be "application/octet-stream" and as I do not provide any MessageBodyWritter for this media type an exception should be thrown.
Am I wrong ?
@NicoNes Commented Hi,
Again I was doing few more tests about MediaType negotiation and I spotted another weird behavior inconsistent with the spec according to me.
Here is the case:
Application set up:
MessageBodyWritter
) and with a custom MessageBodyWritter
in charge of handling application/json
as follow:@Produces(MediaType.APPLICATION_JSON)
public class CustomJacksonJaxbJsonProvider extends com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider{
}
ExceptionMapper
in charge of handling NotFoundException
and return a Message Entity annotated with all correct Jaxb
annotations.Test case:
Lets call a non existing method using any HTTP client with Accept
header set to application/xml
.
Current behavior:
The custom ExceptionMapper
will do its jobs and catch the NotFoundException
and return the Message entity .
Althought the incoming request Accept
header is set to application/xml
, the server will choose to use the CustomJacksonJaxbJsonProvider
decicated to application/json
to write the Message entity.
So on the client side the message is JSON formatted however no Content-Type
header is present.
Expected behavior:
The custom ExceptionMapper
will do its jobs and catch the NotFoundException
and return the Message entity .
According to the spec I was expecting the server to use one of the Jersey XML providers (MessageBodyWritter
) to write the Message entity.
So on the client side the message will be XML formatted and Content-Type
header set to application/xml
.
Step by step the media type negotiation should be:
Not applicable in our case
Since we are dealing with a 404 there is no method and no class selected. So we have to select all MessageBodyWriter
able to handle the Message entity class.
Jersey XML providers XmlRootObjectJaxbProvider
and my custom CustomJacksonJaxbJsonProvider
should be selected among others since their are typed as MessageBodyWritter<Object>
.
So P will contains {...,"application/xml", "application/json", ....}
P is not empty so P = {...,"application/xml", "application/json", ....}
A is not empty so A = {"application/xml"}
MediaType.valueOf("application/xml").isComptatible(MediaType.valueOf("application/xml")) returns true MediaType.valueOf("application/xml").isComptatible(MediaType.valueOf("application/json")) returns false so M = {"application/xml"} (the most specific).
M.length = 1 so sort operation returns M = {"application/xml"}
As M contains a concrete type the selected media type is Mselected = "application/xml". Finish so no need to process other steps
Hi,
Let's consider following resource running into a Jersey container:
echo1
method using any HTTP client withAccept
header set toapplication/*
, it will fail with:echo2
method in the same context it will success and the response media type will be application/xml.I was expecting the first call to work as the second one, but it does not because of the fact that
echo1
method id annotated with@Produces({ "*/xml" })
which contains only 1 media type.The code to check seems to be
MethodSelectingRouter.usePreSelectedMediaType(...)
called byMethodSelectingRouter.determineResponseMediaType(...)
.Maybe this method should become:
What do you think ?