rest icon indicating copy to clipboard operation
rest copied to clipboard

jax-rs get with "return String" generates response header content-type: application/octet-stream

Open gorlok opened this issue 5 years ago • 7 comments

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 avatar Feb 06 '20 20:02 gorlok

@gorlok What is your proposal how the JAX-RS Spec, API, JavaDocs, and / or TCK shall be changed?

mkarg avatar Feb 08 '20 14:02 mkarg

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?

chkal avatar Feb 15 '20 10:02 chkal

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?

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.

mkarg avatar Feb 15 '20 12:02 mkarg

@spericas Any thoughts?

chkal avatar Feb 15 '20 17:02 chkal

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 avatar Feb 18 '20 15:02 spericas

@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?

chkal avatar Feb 22 '20 08:02 chkal

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.

In conjunction with 4.2.1, yes.

mkarg avatar Feb 22 '20 14:02 mkarg