Spring MVC handles a JSON endpoint in two stages. First, request headers and handler mapping decide whether a handler is eligible and which response media types are acceptable. Second, a message converter reads the request body into a Java type or writes a returned Java value to the response body. Jackson’s converter does the JSON work in the second stage. It does not perform HTTP content negotiation. When a request returns 406 Not Acceptable or 415 Unsupported Media Type, the cause is usually in the first stage, or in whether a converter can handle the Java type and media type in the second.
Two headers, two jobs
Most confusion about Spring content negotiation comes from treating Content-Type and Accept as two versions of the same thing. They describe different messages and are checked by different parts of Spring MVC.
As an Amazon Associate I earn from qualifying purchases.
| Header | Sent by | Describes | Checked against in Spring MVC |
|---|---|---|---|
Content-Type |
Whoever sends a body (usually the client on a POST, PUT, or PATCH) | The media type of the body actually being sent | The handler’s consumes condition, then whether a converter can read the body into the target Java type |
Accept |
The client, as a preference | Response media types the client is willing to receive | The handler’s produces condition, the requested-media-type strategy, then whether a converter can write the returned value as the selected media type |
RFC 9110 (HTTP Semantics, 2022) describes Accept as a request preference used in proactive negotiation, where the server chooses a response representation based on the client’s stated preferences. Content-Type labels the representation carried in a message. For an incoming JSON request, it tells Spring which kind of body it is being asked to read.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →How handler mapping constrains a request
Before any body is converted, the handler mapping step filters candidate handlers using the media-type conditions declared on the mapping. These conditions do not convert anything. They decide whether a method is a match at all.
#1 Best Overall
consumes: the request body
consumes is matched against the request’s Content-Type. In the following controller, a request whose body is text/plain does not reach the method:
@PostMapping(value = "/orders", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Order> create(@RequestBody OrderRequest request) {
// ...
}
If no handler on the path accepts the body’s media type, Spring rejects the request with 415. This happens before any converter attempts to read the body.
produces: the response
produces constrains what the handler can return. It is matched against the acceptable media types derived from the request, which normally means the Accept header. A method declared with produces = "application/json" is a poor fit for a client that sends Accept: application/xml, and Spring can answer 406 when no candidate matches.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteA produces value also narrows what a converter must be able to write. Declaring produces does not make a converter exist. It only tells Spring which media type the converter has to produce.
Rank #2
Where the response format comes from
Spring MVC resolves the requested media types through a content negotiation strategy. In the current Spring Framework reference, the Accept header is the default strategy. If URL-based selection is needed, the reference recommends a query parameter strategy over path extensions. Path extensions still exist as an option, but Spring advises against preferring them.
| Strategy | How the format is expressed | Trade-offs |
|---|---|---|
Accept header (default) |
Client sends Accept: application/json |
One URI can serve several representations, so shared caches must vary on Accept (origin servers signal this with a Vary response header). Clients that do not set Accept get whatever default Spring selects, so setting it explicitly matters for API consumers. |
| Query parameter (Spring’s recommended URL-based option) | For example, /orders/42?format=json |
Easy to test in a browser and to bookmark. Each format has its own URI, which suits caching. Its parameter name is part of your public API, so changing it breaks clients. |
| Path extension (an option Spring advises against preferring) | For example, /orders/42.json |
Visible in the URL, but it complicates URI templates and can collide with paths that contain dots. It is less preferred in current Spring guidance, so new APIs should have a specific reason to choose it. |
Whichever strategy you choose, check it with an explicit request. Sending Accept and watching the status and Content-Type of the response is the quickest way to see what Spring selected.
What HttpMessageConverter does
The Spring Framework Reference, in its section on HTTP message conversion, describes the module this way: “The spring-web module contains the HttpMessageConverter interface for reading and writing the body of HTTP requests and responses through InputStream and OutputStream.”
A converter answers two questions. Can it read this Java type from this media type? Can it write this Java type as this media type? Spring asks each registered converter in order and uses the first one that can handle the case. That is why converter order and the list’s contents can change the result. A custom converter placed early can intercept types that Jackson would otherwise handle.
Jackson’s converter is one entry in that list. When Jackson is on the classpath, Spring registers a converter that uses a Jackson ObjectMapper to map between JSON and Java objects. Its default supported media type is application/json. It handles JSON bodies; it does not handle other formats such as XML or form data, which other converters cover.
Configuring MappingJackson2HttpMessageConverter in Spring Framework 6.2
The Spring Framework 6.2 reference documents MappingJackson2HttpMessageConverter as a Jackson 2 converter backed by an ObjectMapper. It requires com.fasterxml.jackson.core:jackson-databind on the classpath. Manage the version through your Spring Boot parent or your Jackson BOM, and confirm that it matches the Jackson line your Framework release expects.
Two extension points exist in Framework 6.2, and they behave differently:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Method on WebMvcConfigurer |
Default converters | Use it when |
|---|---|---|
configureMessageConverters(List<HttpMessageConverter<?>> converters) |
Replaced. Any converter you do not add is gone. | You need full control and are willing to register every converter your application uses. |
extendMessageConverters(List<HttpMessageConverter<?>> converters) |
Retained. The list already contains the defaults, and you add to or modify it. | You want to tune one converter, such as the Jackson converter’s mapper, or add a converter while keeping the defaults. |
For most applications the second method is the one to use. This example enables indented output on the Jackson converter that Spring already registered:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter jackson) {
jackson.getObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true);
}
}
}
}
This change applies to every JSON response, so it suits development diagnostics more than production APIs. For production, prefer configuring the mapper’s features and modules deliberately, and test serialization output against your clients.
Spring Boot
Spring Boot’s documentation for 6.2-based applications says that any detected HttpMessageConverter beans are added in addition to the default converters. Boot therefore does not replace the defaults when you declare a converter bean. It recommends its HttpMessageConverters mechanism for registering converters, or extending the list with extendMessageConverters().
In a Boot application, avoid copying a bare configureMessageConverters() override from an older example. It replaces the converter list that Boot’s auto-configuration has built, so JSON, string, and other defaults can disappear and the failure may show up later as a 406 or 415 in an unrelated endpoint. Check Boot’s Jackson and converter documentation for your release before changing the list. Mapper customization in Boot is typically done through configuration properties or a Jackson customization bean, not by building a new mapper.
Recommended Free Tools
Spring Framework 7 and the Jackson 3 converter
Spring Framework 7.0 changes the Jackson story. In the 7.0.9 API documentation, MappingJackson2HttpMessageConverter is marked deprecated since 7.0, for removal, in favor of JacksonJsonHttpMessageConverter. The replacement uses Jackson 3, whose mapper type is JsonMapper. Those 7.0.9 pages were the current stable reference when this article was prepared, so check the latest 7.0.x patch before you upgrade.
Best Value
| Element | Spring Framework 6.2 (Jackson 2) | Spring Framework 7.0 (Jackson 3) |
|---|---|---|
| Converter class | MappingJackson2HttpMessageConverter |
JacksonJsonHttpMessageConverter |
| Mapper type | ObjectMapper (Jackson 2 databind) |
JsonMapper (Jackson 3) |
| Status | Current in the 6.2 line | Jackson 2 class deprecated since 7.0 for removal; the Jackson 3 class is the replacement |
| Dependency | com.fasterxml.jackson.core:jackson-databind |
Jackson 3 artifacts; take the exact coordinates from the Jackson 3 documentation for your version |
Keep the Jackson generation consistent within one application. Do not mix a Jackson 2 converter example with Jackson 3 imports, and do not register both converters for the same JSON media type unless you have a reason and have checked which one wins. Expect a compiler or IDE deprecation warning wherever source still references the Jackson 2 converter on Framework 7.0; the warning is the signal to plan the move, and it is not itself a runtime failure.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting
406 Not Acceptable
Spring returns 406 when the request’s acceptable media types do not match anything the handler can produce, or when no converter can write the returned value in a selected type. RFC 9110 permits a server to respond 406 when no available representation is acceptable, but it also permits the server to disregard the Accept preference. Spring’s behavior follows its own configuration, so diagnose the mapping and converter rather than assuming the standard requires a particular result.
- Send the exact request and note the
Acceptvalue:curl -i -H "Accept: application/xml" http://localhost:8080/orders/42. Replace the host, port, and path with your own. - Compare that value with the endpoint’s
producesattribute. If the method declares onlyapplication/json, anapplication/xmlrequest cannot match it. - Repeat the request with
Accept: application/json. If this succeeds, the mismatch is in the client’s preference or the endpoint’s declared types, not in the converter. - If the request is correct and the response is still 406, check that a converter can write the returned Java type as the selected media type. A returned type that Jackson cannot serialize, or a type with no matching converter, produces this outcome too.
- If the endpoint is a Boot application, check whether custom converter configuration removed the defaults, as described above.
415 Unsupported Media Type
Spring returns 415 when the request body’s Content-Type does not satisfy any consumes condition on the matching handler, or when no converter can read the body into the target parameter type.
- Check the request’s actual
Content-Type. A common cause is a missing header, so the body is treated as an unsupported type, or a client sendstext/plainwhere JSON was intended. - Check the
consumesvalue on the handler. If it isapplication/json, a request withContent-Type: text/plainshould receive 415 from the mapping stage. That is the expected behavior of the condition, not a Jackson error. - If the
Content-Typeis correct and the handler matches, check whether the converter can read the target type. An unsupported target type, or a JSON structure that does not bind to the Java class, can surface as a different error depending on configuration, so read the full exception chain before concluding.
Unexpected JSON, XML, or converter selection
When a response comes back in a format you did not expect, the converter list is the first thing to inspect. Converters are consulted in order, and the first capable converter wins. A short diagnostic in extendMessageConverters() that logs the class name and supported media types of each entry will show the effective list at startup. Remove the diagnostic once the cause is found.
Spring 7 deprecation warning
- Search the codebase for
MappingJackson2HttpMessageConverterand for Jackson 2 imports such ascom.fasterxml.jackson.databind.ObjectMapperused in converter configuration. - On Framework 7.0, plan the migration to
JacksonJsonHttpMessageConverter. Verify the Spring Boot, Jackson, and Framework version compatibility in each project’s release documentation before changing the dependencies. - Test serialization of dates, null handling, and custom serializers after the move, since mapper defaults and module setup are where Jackson 2 and 3 differ most in practice.
Exact exception text and status outcomes depend on the Framework version, controller signature, selected handler, converter order, Boot auto-configuration, and client headers. Reproduce the case with the same versions before trusting a fix.
Quick Recap
Which setup to use
| Situation | Recommended approach |
|---|---|
| Spring Framework 6.2 with Spring Boot | Rely on Boot’s converter detection and mapper configuration. Add converters as beans, or use extendMessageConverters(). Avoid configureMessageConverters() unless you are replacing the whole list on purpose. |
| Spring Framework 6.2 without Boot | Use extendMessageConverters() to adjust the Jackson 2 converter while keeping the defaults. |
| New code on Spring Framework 7.0 | Use JacksonJsonHttpMessageConverter and Jackson 3 types. Do not start new code on MappingJackson2HttpMessageConverter. |
| Existing 7.0 code that uses the Jackson 2 converter | Keep it working for now, record the deprecation, and migrate the converter and mapper types together as one change. |
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




