Claus Ibsen created CAMEL-25769:
-----------------------------------
Summary: camel-core - REST binding: a GET with Content-Type
text/plain is answered 500 when bindingMode is json
Key: CAMEL-25769
URL: https://issues.apache.org/jira/browse/CAMEL-25769
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: Claus Ibsen
Fix For: 4.24.0
With bindingMode json, a request whose Content-Type is not JSON gets no JSON
answer. A GET of a REST DSL operation that answers a Map, sent with
Content-Type text/plain:
{noformat}
curl -H 'Content-Type: text/plain;charset=UTF-8'
http://localhost:8080/orders/ORD-1002
500 Internal Server Error
WARN VertxPlatformHttpConsumer : Failed handling platform-http endpoint
/orders/{id}. Caused by: [org.apache.camel.NoTypeConversionAvailableException -
No type converter available to convert from type: java.util.LinkedHashMap to
the required type: java.io.InputStream]
{noformat}
The same GET without a Content-Type, or with application/json, gets the order
as JSON.
Cause, in RestBindingAdvice.doMarshal: the request's Content-Type header is
still on the message when the answer is made. ensureHeaderContentType keeps an
existing Content-Type, so application/json is not set, and the answer is
marshalled only when its Content-Type contains json. The Map is left as it is,
and the HTTP consumer cannot write it. Vert.x only reports the failure; the
decision is in the binding.
The Content-Type of a request describes its body, and a GET has none. The
format of the answer comes from the Accept header and what the operation
produces: Spring MVC and JAX-RS answer JSON for such a GET whatever its
Content-Type, when the operation declares no consumes. Most clients send no
Content-Type on a GET (browsers, curl, the Java HttpClient), but some do: the
Citrus HTTP client sends text/plain by default, which is how this was found, in
the contracts/rest-code-first example (apache/camel-jbang-examples#118). Camel
answers with a server error for a header that does not concern the answer.
Proposal:
* The request's Content-Type does not decide the answer. The binding remembers
it when the request comes in; when the message still has that value at the end,
the route did not choose a type, so the binding sets the Content-Type of its
mode (application/json) and marshals.
* A Content-Type that the route sets itself still wins, so a route can answer
text/csv and skip the binding, as today.
* A body that is already text stays as it is, so a route that answers a String
to a text/plain request gets the same answer as today. Only the case that fails
today changes: an object body (Map, List, POJO).
* Tests for each of the three cases.
_Claude Code on behalf of davsclaus_
--
This message was sent by Atlassian Jira
(v8.20.10#820010)