Skip to content

Spring Framework 7.1 Release Notes

Sam Brannen edited this page Oct 22, 2026 · 26 revisions

This is a preview page for Spring Framework 7.1.0, scheduled for November 2026.

Upgrading From Spring Framework 7.0

Baseline Upgrades

This new generation raises its minimum requirements for the following:

  • Jackson 3.1 for LTS support
  • Hibernate ORM 7.3 support; runtime compatibility with Hibernate ORM 7.1 and 7.2 is retained for the time being.
  • HtmlUnit 5.4 for the spring-test integration with MockMvc

Removed APIs

HandlerMappingIntrospector removed

HandlerMappingIntrospector has been removed (#36481). This class was formerly for internal use by Spring Security to perform path checks aligned with Spring MVC. It also implemented CorsConfigurationSource to allow CORS checks based on @CrossOrigin annotations on controllers. As a result of the removal, applications may now experience the absence of a CorsConfigurationSource bean.

HandlerMappingIntrospector was never intended for general use either directly or indirectly as CorsConfigurationSource. Generally as CORS checks are built into the DispatcherServlet there is no need to apply them anywhere else. Consequently there is no direct replacement. However, the Spring MVC config continues to expose a PreFlightRequestHandler bean (now DefaultPreFlightRequestHandler) to handle preflight requests early as those are not authenticated and possible to handle fully early within the filter chain.

Breaking Changes

PropertySource.toString() no longer depends on the log level

PropertySource.toString() now consistently produces concise output consisting of the simple class name and the name of the property source, for example MapPropertySource {name='myProperties'} (#37540). Previously, if DEBUG logging was enabled for the concrete PropertySource implementation, the output additionally included the identity hash code and the toString() representation of the underlying source object. If you relied on that verbose output, for example for troubleshooting, use getSource() or, for an EnumerablePropertySource, getPropertyNames() explicitly instead.

JAXB message converter auto-detection

We noticed that the JAXB message converter can consume a lot of CPU resources at runtime, even if XML isn't being used by the application. The "jakarta.xml.bind:jakarta.xml.bind-api" dependency is very common in Servlet applications and is often auto-detected by HttpMessageConverters as a valid choice.

As of Framework 7.1, HttpMessageConverters will not auto-detect JAXB converters for server applications. RestTemplate and RestClient will still detect it, because the CPU overhead there is less important.

You can bring back this converter in your server application with the following configuration:

@Configuration(proxyBeanMethods = false)
class JaxbConverterConfiguration implements WebMvcConfigurer {

	@Override
	public void configureMessageConverters(HttpMessageConverters.ServerBuilder builder) {
		builder.withXmlConverter(new Jaxb2RootElementHttpMessageConverter());
	}
}

Default limits set for WebFlux multipart parsing

DefaultPartHttpMessageReader now sets default limits for maxDiskUsagePerPart to 1MB and maxParts to 50 (#36928). Both had no default limits previously. The new default values align with default values set in Boot for Servlet applications and with Tomcat for the number of parts. Use ServerCodecConfigurer in the WebFlux config to register a MultipartHttpMessageReader that delegates to a customized DefaultPartHttpMessageReader.

ProblemDetail "instance" field is no longer set automatically

The instance field of ProblemDetail is no longer set automatically (#35969). Previously it was set to the request path, but RFC 9457 defines this as a URI identifier for a specific occurrence of the problem, potentially also returning information about the problem. A plain request path doesn't meet that definition. Applications can set the field directly on ProblemDetail or ErrorResponse locally, or configure an ErrorResponse.Interceptor through the MVC or WebFlux Java config.

Server errors are recorded on the HTTP server observation

Exceptions that are translated to a 5xx response by ResponseEntityExceptionHandler (MVC and WebFlux), ResponseStatusExceptionResolver and DefaultHandlerExceptionResolver are now recorded as the error of the current HTTP server observation (#37384). Previously, these exceptions were handled without the observation seeing them.

As a result, for such requests:

  • The error key of the http.server.requests metrics is now the exception name instead of none.
  • Traces mark the server span as failed and carry the exception.

Client errors (4xx) are never recorded, so dashboards and alerts on those are unchanged.

Applications that rely on the previous behavior, for example alerts that count a non-none error value as an unexpected failure, may see more server errors than before. These requests were already counted with outcome=SERVER_ERROR, but without the exception. The change can be reverted for specific exceptions with a custom ObservationConvention that ignores the error.

Default message converters in RestClient.Builder

Prior to Framework 7.1, calling RestClient.Builder#configureMessageConverters (or the RestTestClient.Builder variant) turned off the auto-detection of default message converters: only converters configured explicitly were registered, unless registerDefaults() was called (#36747). As of Spring Framework 7.1, the HttpMessageConverters.ClientBuilder always starts from the default converters, which aligns with the Spring MVC and WebClient configuration. Overriding a single converter with withJsonConverter or adding one with addCustomConverter now keeps all other default converters.

Applications that relied on the previous behavior to configure a minimal set of converters should now disableDefaults() explicitly. Converters set with the deprecated RestClient.Builder#messageConverters methods are not affected. Spring Boot applications using the auto-configured RestClient.Builder are not affected either, since Boot already registers default converters.

Consistent handling of 0 timeouts in HTTP clients

A timeout of 0 is now consistently treated as "no timeout" for connect, read, and block timeouts in our HTTP client support (#37425). Previously, ReactorClientHttpRequestFactory rejected a read timeout of 0, JettyClientHttpRequestFactory failed every request for a read timeout of Duration.ZERO, and a block timeout of Duration.ZERO for HTTP Service clients (AbstractReactorHttpExchangeAdapter#setBlockTimeout) failed every blocking request. The same applies to the block timeout in RSocketServiceProxyFactory (#37451) and the response timeout in WebTestClient (#37454).

In addition, negative timeouts are now rejected, and sub-millisecond Duration values are rejected wherever they would otherwise be truncated to 0. Applications that relied on negative values being ignored by SimpleClientHttpRequestFactory (falling back to the system default) should no longer set the timeout, and applications that relied on sub-millisecond values being treated as infinite should use 0 instead.

WebClient applies proxy system properties with Reactor Netty

The default HttpClient created by ReactorClientHttpConnector now applies Reactor Netty's proxyWithSystemProperties(), so WebClient honors JVM proxy system properties such as https.proxyHost and https.proxyPort (#36654). This aligns with ReactorClientHttpRequestFactory, which has done so since Spring Framework 7.0 (#34850). To opt out, pass a custom HttpClient to the ReactorClientHttpConnector constructor, or call noProxy() in the HttpClient mapper function.

Default context configuration in test class hierarchies

The Spring TestContext Framework now reliably detects default context configuration (such as static nested @Configuration classes or default XML configuration files) for all superclasses and enclosing classes of a test class (#31456). Previously, such default configuration was ignored if the type hierarchy or enclosing class hierarchy (for @Nested test classes) did not declare @ContextConfiguration; for example, for a subclass or @Nested class of a test class annotated only with @SpringBootTest. As a result, tests may now encounter unexpected beans in their ApplicationContext or outright failures.

Since Spring Framework 7.0.6, a warning is logged whenever such default context configuration is detected but ignored, which helps to identify affected tests before upgrading. If you do not want such configuration to be processed, you can apply @ContextConfiguration only where you actually want such classes to be processed, remove the @Configuration declaration, or move static nested @Configuration classes to standalone top-level classes. See the Default Context Configuration section of the reference manual for details.

Deprecations

  • As announced in the state of HTTP clients in Spring blog post, RestTemplate and related types are formally deprecated as of 7.1. Their actual removal is scheduled for Spring Framework 8.0 (not yet scheduled).
  • The default constructors of ForwardedHeaderFilter (Spring MVC) and ForwardedHeaderTransformer (WebFlux) have been deprecated for removal in favor of a new one with a boolean argument whether to use the standard "Forwarded" header or the "X-Forwarded" alternative headers (see #37072). A separate property enables use of "X-Forwarded-Prefix" if needed. This makes forwarded header processing more deterministic and aligned with what is expected from the proxy. Please, see the updated Security Considerations section, as well as related changes in Spring Boot (see spring-boot/51030).
  • The AllEncompassingFormHttpMessageConverter is deprecated in favor of the new MultipartHttpMessageConverter. It is not configured by default anymore in HTTP clients and server applications.
  • The disallowedFields property of DataBinder is deprecated as it is fragile and easy to get out of sync with the actual properties over time. Please use constructor binding, a model object designed for the expected inputs, or allowedFields instead.
  • the Apache Derby project is retired since 2023 and this release deprecates its support.
  • org.springframework.beans.PropertyAccessorUtils has been deprecated in favor of the new PropertyPath type and its dedicated parser. This introduces a tighter grammar and parsing for bean property paths in general.

New and Noteworthy

JPA 4.0 and Hibernate 8.0 support

Spring Framework 7.1 extends its optional support for the upcoming JPA 4.0 and Hibernate ORM 8.0, building on the EntityAgent support from #36025:

  • @PersistenceAgent injection is supported by PersistenceAnnotationBeanPostProcessor (#36264).
  • PersistenceUnitInfo implementations expose the new JPA 4.0 package and module descriptor discovery callbacks. Annotated module-info classes are discovered next to package-info classes (#37316).
  • SpringBeanContainer is aligned with the revised Hibernate 8.0 BeanContainer SPI, including lazy access to "bootstrap-safe" beans. This also fixes MultiTenantConnectionProvider, which Hibernate now retrieves as a managed bean (#37381).

Existing applications can already run against Hibernate 8.0 on Spring Framework 7.0.10, which provides the same behavior as with JPA 3.2 and Hibernate 7.x (#37315). The new JPA 4.0 features need 7.1.

HTTP QUERY support

RFC 10008 introduces the new QUERY HTTP method. This spans the gap between GET and POST: QUERY is an idempotent method with a request body. This is a brand new standard and the industry is starting to adopt it. This release ships minimal support to unlock your typical use case.

For example:

@RestController
public class TestController {

  @RequestMapping(method = RequestMethod.QUERY, path = "/form", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
  public ResponseEntity<String> form(@RequestParam String name) {
    return ResponseEntity.ok("hello: " + name);
  }

  @RequestMapping(method = RequestMethod.QUERY, path = "/body", consumes = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<String> body(@RequestBody Project project) {
    return ResponseEntity.ok("project: " + project.id);
  }

  public record Project (String name, String id) {

  }

}

You can test these endpoints with the following curl commands:

$ curl -X QUERY -d "name=spring" http://localhost:8080/form
$ curl -X QUERY -H "Content-Type: application/json" -d '{"name":"Spring Framework", "id":"spring-framework"}' http://localhost:8080/body

We are not shipping a @QueryMapping annotation or DSL extensions for now; we will gradually add more features as industry adoption increases.

Improved Multipart support

Before Spring Framework 7.1, Multipart payloads could be read/written in Spring MVC applications with the Servlet Multipart Resolver support. RestTemplate and RestClient could send Multipart requests thanks to the FormHttpMessageConverter. This means HTTP clients could not read multipart responses and you couldn't thoroughly test your Multipart endpoints with RestTestClient.

As of 7.1, Spring Framework now dedicates FormHttpMessageConverter to URL encoded forms and ships a new MultipartHttpMessageConverter that can write and read Multipart payloads.

Check out in the reference documentation how RestClient can parse Multipart responses as MultiValueMap and how you can use RestTestClient to test your Multipart server endpoints.

When using RestTestClient with MockMvc, integration tests will now support handling multipart requests sent by RestTestClient.

Problem Details for error handling in Spring MVC

Spring MVC can now render any unhandled exception as an RFC 9457 problem detail, without requiring a @ControllerAdvice that extends ResponseEntityExceptionHandler (#37380).

This is opt-in through WebMvcConfigurer:

@Configuration
public class WebConfig implements WebMvcConfigurer {

      @Override
      public void configureProblemDetails(ProblemDetailsConfigurer configurer) {
              configurer.renderUnhandledExceptions(true);
      }
}

With this enabled, exceptions that no @ExceptionHandler method handles are rendered as application/problem+json responses (#37398):

  • ErrorResponse exceptions, ResponseStatusException and @ResponseStatus exceptions keep their status and detail.
  • Framework exceptions get the same status and detail as ResponseEntityExceptionHandler.
  • Any other exception results in a generic 500 response. The exception message is never exposed.
  • Type, title and detail can be customized through the MessageSource.

Browsers can get an HTML error page instead of JSON. An ErrorResponseViewResolver is called when the client prefers HTML, so applications can render problem details with their own error templates (#37400):

configurer.viewResolver((request, problemDetail, errorResponse) ->
              new ModelAndView("error/" + problemDetail.getStatus(),
                              Map.of("problem", problemDetail)));

JSON comparison with JsonUnit in spring-test

The JSONassert library is no longer maintained. To keep the JSON comparison features of spring-test working, they now support JsonUnit as well. This covers the json(...) methods of WebTestClient, RestTestClient, MockMvc and MockRestServiceServer, as well as the JSON assertions in MockMvcTester.

Spring detects the library at runtime, so adding net.javacrumbs.json-unit:json-unit-core to the test classpath is enough. If both JsonUnit and JSONassert are present, JsonUnit is used, and assertion failure messages will look different. JsonComparator.of(JsonCompareMode) exposes this detection for custom use.

For richer assertions, developers can keep using JsonUnit's own json-unit-spring integration.

Clone this wiki locally