Spring Framework 6.2.0-M1: all the little things

Engineering | Stéphane Nicoll | April 11, 2024 | ...

The Spring Framework team has been busy reviewing the issue tracker in anger and reducing the number of opened issues. This was long overdue, with a number of issues being invalid or superseded in the meantime. This helped the team focusing on a more manageable amount of issues and we used the opportunity to look at long standing issues that we haven’t had the time to address yet.

In this post, I’d like to walk you through a collection of those relatively small issues, sometimes highly voted, that are finally available in this milestone.

Support for escaping property placeholders

Property placeholders are a way to replace a property from the environment in an arbitrary String. Assuming that customer.name is set to "John Smith" in the Environment, "Customer ${customer.name}" would resolve to "Customer John Smith".

There are corner cases where you’d like to retain the original value rather than having it resolved. An issue was created in 2008 with quite a bit of votes. Spring Framework 6.2.0-M1 allows you to escape a placeholder using a configurable escape character (backslash by default). Taking our previous example, "Customer \${customer.name}" resolves now to "Customer ${customer.name}".

This looks like an innocent change, why did it take us so long to fix it?! It turns out we had to rewrite the parser from scratch, which has other positive side effects: default values are now lazily resolved and the exception message provides the chain of resolutions when resolving nested placeholders.

Support for fallback beans

This highly voted issue has also been resolved and gives you more control when crafting configuration that may require a fallback bean. A fallback bean is used if no bean of that type has been provided. This is essentially a companion of @Primary without the trade-off of having to specify it.

Consider that a component requires MyService to be defined. You can provide a default implementation for the service but you’d like that if a user specifies one, it can be injected by type transparently. So far, the user had to configure their specific bean with @Primary to make sure it is used, since two beans of that type are defined now.

As of Spring Framework 6.2.0-M1 you can craft your configuration with @Fallback:

@Configuration
class MyConfiguration {

	@Bean
	MyComponent myComponent(MyService service) {
    	...
	}

	@Bean
	@Fallback
	MyService defaultMyService() {
    	...
	}

}

As you can guess, if no other MyService bean is defined, defaultMyService is used. Otherwise, the container will pick transparently the one that’s been defined externally.

Bean Background Initialization

One of the most voted issues ever is also resolved in this milestone. Individual beans can be initialized in the background using the newly introduced bootstrap attribute.

@Configuration
class MyConfiguration {

    @Bean(bootstrap = BACKGROUND)
    MyExpensiveComponent myComponent() {
   	 ...
    }

}

Check the reference guide for more details about this new feature.

TaskDecorator support for scheduled tasks

Spring Framework 6.2.0-M1 allows using TaskDecorator for scheduled tasks as well, harmonizing task execution and scheduling in the process. See the related issue for more details.

AssertJ support for MockMvc

We love AssertJ! While Spring Boot has already jumped on that train a while ago and provides several testing facilities using it, the framework team has been more conservative. At the same time, we recognize that our Hamcrest support may not fit everyone’s needs: the use of static imports make the API less discoverable and writing custom assertions is harder.

Spring Framework 6.2.0-M1 provides an exhaustive support for testing your web application with MockMvc and AssertJ.

Building an AssertableMockMvc instance is more straightforward, with dedicated factory methods on the class itself. If you have a WebApplicationContext handy, this is as easy as AssertableMockMvc.from(webApplicationContext). If you want to test only a controller in a unit test, you can do so as follows:

AssertableMockMvc mvc = AssertableMockMvc.of(List.of(new HelloController()), builder ->
    	builder.defaultRequest(get("/hello").accept(MediaType.APPLICATION_JSON)).build());

Once you have an instance you can perform your usual requests and wrap that in AssertJ’s standard assertThat:

assertThat(mvc.perform(get("/vehicle/{id}", "12").accept(MediaType.TEXT_PLAIN))).hasStatusOk()
    	.body().isEqualTo("Honda Civic");

This first milestone covers the same features as the existing Hamcrest matchers, and extend it with advanced JSON support, for instance:

assertThat(perform(get("/message"))).body().json()
    	.isLenientlyEqualTo(new ClassPathResource("samples/message.json"));

This is the first cut of the API and we expect community feedback to improve it.

There is more!

With more than one hundred issues resolved, Spring Framework 6.2.0-M1 is packed with enhancements, expect more information in the coming weeks from us.

Until there is a Spring Boot 3.4 snapshot that is built against it, you’ll have to override the spring-framework.version to the milestone. Please give that a try and let us know how it goes.

Happy coding!

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all