spring-projects / spring-projects/spring-framework
RestClient.Builder.configureMessageConverters disables the implicit registration of default converters.
@bclozel is already working on this.
Since May 6, 2026.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
In Spring Framework 7, I noticed that calling RestClient.Builder.configureMessageConverters(...) changes how default message converters are registered.
In DefaultRestClientBuilder.initMessageConverters(), defaults are registered only when both messageConverters and convertersConfigurer are null:
private List<HttpMessageConverter<?>> initMessageConverters() {
HttpMessageConverters.ClientBuilder builder = HttpMessageConverters.forClient();
if (this.messageConverters == null && this.convertersConfigurer == null) {
builder.registerDefaults();
}
else {
if (this.messageConverters != null) {
this.messageConverters.forEach(builder::addCustomConverter);
}
if (this.convertersConfigurer != null) {
this.convertersConfigurer.accept(builder);
}
}
List<HttpMessageConverter<?>> result = new ArrayList<>();
builder.build().forEach(result::add);
return result;
}
This means that as soon as configureMessageConverters(...) is called, the implicit registerDefaults() path is skipped. For example:
RestClient client = RestClient.builder()
.configureMessageConverters(builder -> {
builder.withJsonConverter(new JacksonJsonHttpMessageConverter(jsonMapper));
})
.build();
My initial expectation was that this would keep the default converters and replace/configure the JSON converter. However, since registerDefaults() is not called, the configured JSON converter may not be included in the final converter list unless the user explicitly calls registerDefaults():
RestClient client = RestClient.builder()
.configureMessageConverters(builder -> {
builder.registerDefaults();
builder.withJsonConverter(new JacksonJsonHttpMessageConverter(jsonMapper));
})
.build();
Is this the intended behavior?
The part that feels surprising is that the method name configureMessageConverters(...) can be interpreted as “configure the message converters used by the RestClient”, possibly starting from the default converter set. In practice, it appears to mean “fully configure the HttpMessageConverters.ClientBuilder, including deciding whether defaults should be registered”.
I understand that there are valid use cases where users may want to call disableDefaults() or provide a fully custom converter configuration. However, I am wondering why the implicit default registration is disabled merely by the presence of convertersConfigurer, rather than allowing the configurer to operate on the default converter setup by default.
More specifically, I would like to understand the design rationale behind this condition:
if (this.messageConverters == null && this.convertersConfigurer == null) {
builder.registerDefaults();
}
Would it be possible or desirable for configureMessageConverters(...) to start with defaults unless the user explicitly calls disableDefaults()? Or is the intended contract that any use of configureMessageConverters(...) requires users to explicitly call registerDefaults() when they want to retain the default converters?
This is especially relevant when migrating from the previous list-based messageConverters(...) customization style, where users could modify an already initialized converter list. With the new HttpMessageConverters.ClientBuilder based API, it is easy to accidentally configure a JSON converter while ending up with no default converters at all.
If this is intended, it may be helpful to clarify in the Javadoc that configureMessageConverters(...) disables implicit default registration and that callers should invoke registerDefaults() explicitly when they want to customize the default converter set.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.