Using Java Records for real: Spring Boot
Can Java records already be used with Spring Boot? Thanks to Jackson’s support of records, yes they can!
If you are not yet familiar with Java records you might want to start by looking at the official proposal in JEP 359 or at the official documentation.
Jackson is a serialization/deserialization library supporting JSON (and many other formats). Spring Boot uses it to accept and return JSON content from the controllers for instance.
In version 2.12, the support of Java records has been added to Jackson. It should be noted that the latest version of Spring Boot (2.4.1 as of this writing) is still using Jackson 2.11.x so you would have to override the version in your build tool to use records.
Here is an example of a build.gradle file to use records with Spring Boot:
Now let’s see how we can leverage records to simplify our day to day usage of Spring Boot.
Using records for configuration
Spring Boot supports mapping configuration to beans using @ConfigurationProperties
.
You just need to provide a simple bean with getters and setters for it to be automatically mapped.
Jackson is the underlying library used to perform this mapping so we can leverage it to use records instead.
With the following configuration in the application.yaml
file:
and the following record:
We would be able to retrieve and inject an instance of RecordConfiguration
with just this content: RecordConfiguration[aProperty=123, anotherProperty=value].
@ConfigurationProperties
lets us map the properties starting with the custom prefix.
As we used a record that does not come with setters we added the @ConstructorBinding
annotation to rely on the constructor instead.
Configuration properties are just a perfect match for Java records, immutable objects with read-only properties.
The default toString()
implementation is useful for debugging purposes (although you might want to be careful
about logging sensitive configuration data).
Using records in controllers
Another place in Spring Boot’s applications where immutable objects would make sense is for controllers. Most of the tutorials you will find out there will show you how you can take an object and pass it as a controller parameter down to be persisted in the database. This is convenient to demonstrate the simplicity of Spring Boot but we all know that once our application starts to become a little more complex we will benefit from decoupling the different layers.
At the controller layer we usually need simple POJOs, just a representation of the data that is received and sent back over the wire. Yet another good use case for records!
Let’s take a look at the RESTful Web Service guide from Spring, here we define a simple controller that returns a Greeting
object:
With Greeting
defined as:
🧐 This structure looks familiar…
That’s it, just as the guide says: This application uses the Jackson JSON library to automatically marshal instances of type Greeting into JSON. Jackson is included by default by the web starter.
So we are indeed good to go just writing records to serialize data to JSON in our Spring web services. It also works the same way to deserialize data so records can be used as input parameters for request bodies too.
Using records with templates
Now maybe you are not only returning JSON content but also using templates. Another area where records can help!
Here is a simple template that displays data about books:
And a controller using this template:
Here we even created an inline record, just passing around the required data to the template.
However if you want to benefit from Intellij support for Thymeleaf
you might want to make it a proper class to annotate its usage with @thymesVar
.
(Not) Using records to persist data
Could we use records to persist objects to a database?
The short answer is no, records are not well suited for persistence, mainly because Hibernates does not just save or read data from the database but manages the entire state, potentially generating update statements. Something that would be hard to achieve with immutable objects such as records.
This blog post by Vlad Mihalcea explains it very well and offers one use case for records: DTO projections.
Here we looked only at relational databases using Hibernate, with other databases, such as MongoDB the story might be different though.
Conclusion
In this blog post we showed how Java records can be used within a Spring Boot application:
- to map configuration properties to objects
- to serialize and deserialize JSON data in controllers
- to pass data in templates
These are just a few places that came to mind where records can be a good fit, there are probably more so feel free to continue the discussion on Twitter!