Companion code for "Global Exception Handling with ProblemDetail (RFC 9457) in Spring Boot 4". Thirteen failures under five handling setups (Boot defaults, the Boot flag, a ResponseEntityExceptionHandler advice, advice plus an ErrorController, a catch-all ordered first), validation errors, i18n, content negotiation, Security's 401/403, silent 500s and decoding on the client. 16 tests pin the behaviour. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01C3TETMrqVUWeFkNtz3Jbo3
1.6 KiB
5. Content negotiation: why Accept: application/xml gets JSON
← 4. Types and message codes · Index · Next: 6. Outside Spring MVC →
With jackson-dataformat-xml on the classpath a successful response honours Accept: application/xml. An error response to the same request does not
(content-negotiation.txt):
Accept |
GET /orders/1 (200) |
GET /orders/999 (404) |
|---|---|---|
application/json |
application/json |
application/problem+json |
application/xml |
application/xml |
application/problem+json |
application/problem+xml |
- | application/problem+xml |
text/html |
- | application/problem+json |
image/png |
- | application/problem+json (still 404, not 406) |
For a ProblemDetail body the producible types are application/problem+json and
application/problem+xml. application/xml is compatible with neither - problem+xml is a
different subtype, not a specialisation - so negotiation finds no match and Spring falls back to
JSON rather than failing the error response with a 406. The fallback is the right call; the
surprise is that an XML client must ask for application/problem+xml by name to get XML errors.
The XML body uses the RFC's namespace, which RFC 9457 kept from 7807:
<problem xmlns="urn:ietf:rfc:7807"><detail>Order 999 does not exist</detail><instance>/orders/999</instance><status>404</status><title>Order not found</title><type>https://ankurm.com/problems/order-not-found</type><orderId>999</orderId></problem>