rest
rest copied to clipboard
jax-rs get with "return String" generates response header content-type: application/octet-stream
I found something weird and/or inconsistent. When a method returns String, without any @Produces nor MediaType response indication, default Content-Type's response is application/octet-stream instead of text/plain in some runtimes.
This happens with OpenLiberty and ThorntailV2. Meanwhile, on Payara Content-Type is text/plain.
I first raised this issue on OpenLiberty's issue tracking here: https://github.com/OpenLiberty/open-liberty/issues/10759
Talking with Andy McCright, he saw that JAX-RS defines the default as application/octet-stream since JAX-RS 1.0, but for other primitives (like long) use text/plain (defined in section 4.2.2):
java.lang.Boolean, java.lang.Character, java.lang.Number Only for text/plain. Corresponding primitive types supported via boxing/unboxing conversion.
I would expect a content-type text/plain for String and primitives by default, and application/octectstream for all the rest of types (like byte[], Object, etc). That's the way it works on PayaraMicro and DotNet Core 3.1 (just for reference).
I posted steps to reproduce it on https://github.com/OpenLiberty/open-liberty/issues/10759 using https://start.microprofile.io/ samples.
It's so weird, that when you test such a service with OpenAPI UI (Swagger), you can't see the response's body, and you get a "Download file" instead. Because the response was content-typed as application/octectstream instead of text/plain, but it's a string response.
Maybe this can be reviewed on a future release.
@gorlok What is your proposal how the JAX-RS Spec, API, JavaDocs, and / or TCK shall be changed?
IMO the default media type of application/octet-stream
is a great choice and makes sense to me. I don't fully understanding the restriction to text/plain
for boolean, character and number as described in 4.2.2. Anyone knows why it was defined this way?
IMO the default media type of
application/octet-stream
is a great choice and makes sense to me. I don't fully understanding the restriction totext/plain
for boolean, character and number as described in 4.2.2. Anyone knows why it was defined this way?
Cannot remember that, but I think it has to do with the fact that for text/plain
the rendered information may be used as-is, while an application/octet-stream
(mind the prefix application
!) MIGHT imply additional knowledge about the text's syntax (according to wikipedia). This means, true
, false
, X
, 123
are unambiguous, while a longer String
COULD contain things like XML or JSON which need further parsing. But really, this is just a wild guess.
@spericas Any thoughts?
Not sure if all the section numbers here are accurate. Section 4.2.4 is the one that lists the standard entity providers (and allows */*
for String). Section 4.2.2 has a reference to Section 3.8 which, if I understand the issue here, is the more relevant one.
Section 3.8 defines the algorithm to determine the media type of a response, and this algorithm depends on the set of writers defined (and their @Produces) and the "Accept" header in the request. I would normally expected text/plain
for a String
, but that depends on those factors.
@spericas Thanks for your reply.
Section 3.8 also states:
Note that the above renders a response with a default media type of ‘application/octet-stream’ when a concrete type cannot be determined. It is RECOMMENDED that MessageBodyWriter implementations specify at least one concrete type via @Produces.
But as far as I understand, the spec doesn't require the standard entity types defined in section 4.2.4 to specify a concrete type. I guess that's why JAX-RS implementations behave differently in this case, depending on whether the writer defines a concrete type or not.
My interpretation of 4.2.4 is that the standard message body writer for String
effectively behaves like it defines @Produces("*/*")
, which would lead to application/octet-stream
for the response.
Or am I missing something?
My interpretation of 4.2.4 is that the standard message body writer for
String
effectively behaves like it defines@Produces("*/*")
, which would lead toapplication/octet-stream
for the response.
In conjunction with 4.2.1, yes.