Tackling Records in Spring Boot

Java records fit perfectly in Spring Boot applications. Let’s have several scenarios where Java records can help us increase readability and expressiveness by squeezing the homologous code.

Using Records in Controllers

Typically, a Spring Boot controller operates with simple POJO classes that carry our data back over the wire to the client. For instance, check out this simple controller endpoint returning a list of authors, including their books:

Java
 
@GetMapping("/authors")
public List<Author> fetchAuthors() {
  return bookstoreService.fetchAuthors();
}


Here, the Author (and Book) can be simple carriers of data written as POJOs. But, they can be replaced by records as well. Here it is:

Java
 
public record Book(String title, String isbn) {}
public record Author(String name, String genre, List<Book> books) {}


That’s all! The Jackson library (which is the default JSON library in Spring Boot) will automatically marshal instances of type Author/Book into JSON. In the bundled code, you can practice the complete example via the localhost:8080/authors endpoint address.

Using Records With Templates

Thymeleaf is probably the most used templating engine in Spring Boot applications. Thymeleaf pages (HTML pages) are typically populated with data carried by POJO classes, which means that Java records should work as well.

Let’s consider the previous Author and Book records, and the following controller endpoint:

Java
 
@GetMapping("/bookstore")
public String bookstorePage(Model model) {
  
  model.addAttribute("authors",
  bookstoreService.fetchAuthors());
  
  return "bookstore";
}


The List<Author> returned via fetchAuthors() is stored in the model under a variable named authors. This variable is used to populate bookstore.html as follows:

HTML
 
...
<ul th:each="author : ${authors}">
  <li th:text="${author.name} + ' (' + ${author.genre} + ')'" />
  <ul th:each="book : ${author.books}">
    <li th:text="${book.title}" />
  </ul>
</ul>
...


Done! You can check out the application Java Coding Problems SE.

Using Records for Configuration

Let’s assume that in application.properties we have the following two properties (they could be expressed in YAML as well):

Properties files
 
bookstore.bestseller.author=Joana Nimar
bookstore.bestseller.book=Prague history


Spring Boot maps such properties to POJO via @ConfigurationProperties. But, a record can be used as well. For instance, these properties can be mapped to the BestSellerConfig record as follows:

Java
 
@ConfigurationProperties(prefix = "bookstore.bestseller")
public record BestSellerConfig(String author, String book) {}


Next, in BookstoreService (a typical Spring Boot service), we can inject BestSellerConfig and call its accessors:

Java
 
@Service
public class BookstoreService {
  
  private final BestSellerConfig bestSeller;

  public BookstoreService(BestSellerConfig bestSeller) {
    this.bestSeller = bestSeller;
  }
  
  public String fetchBestSeller() {
     return bestSeller.author() + " | " + bestSeller.book();
  }
}


In the bundled code, we have added a controller that uses this service as well.

Record and Dependency Injection

In the previous examples, we have injected the BookstoreService service into BookstoreController using the typical mechanism provided by SpringBoot – dependency injection via constructor (it can be done via @Autowired as well):

Java
 
@RestController
public class BookstoreController {
  
  private final BookstoreService bookstoreService;
  
  public BookstoreController(BookstoreService bookstoreService) {
    this.bookstoreService = bookstoreService;
  }
  
  @GetMapping("/authors")
  public List<Author> fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}


But, we can compact this class by re-writing it as a record as follows:

Java
 
@RestController
public record BookstoreController(BookstoreService bookstoreService) {
  
  @GetMapping("/authors")
  public List<Author> fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}


The canonical constructor of this record will be the same as our explicit constructor. The application is available on GitHub.

Feel free to challenge yourself to find more use cases of Java records in Spring Boot applications.

 

 

 

 

Top