Spring Data Java 8 Support

1. Overview

Spring Data now supports core Java 8 features – such as OptionalStream API and CompletableFuture.

In this quick article, we’ll go through some examples of how we can use these with the framework.

2. Optional

Let’s start with the CRUD repository methods – which now wrap results in an Optional:

public interface CrudRepository<T, ID> extends Repository<T, ID> {
    
    Optional<T> findById(ID id);
    
}

When returning an Optional instance, it’s a useful hint that there’s a possibility that the value might not exist. More information on Optional can be found here.

All we now have to do is to specify return type as an Optional:

public interface UserRepository extends JpaRepository<User, Integer> {
    
    Optional<User> findOneByName(String name);
    
}

3. Stream API

Spring Data also provides the support for one of the most important features of Java 8 – the Stream API.

In the past, whenever we needed to return more than one result, we needed to return a collection:

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    List<User> findAll();
    // ...
}

One of the problems with this implementation was the memory consumption.

We had to eagerly load and keep all retrieved objects in it.

We could improve by leveraging paging:

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    Page<User> findAll(Pageable pageable);
    // ...
}

In some scenarios, that’s enough, but in others – pagination is really not the way to go, due to the high number of requests necessary to retrieve the data.

Thanks to Java 8 Stream API and JPA providers – we can now define that our repository method returns just a Stream of objects:

public interface UserRepository extends JpaRepository<User, Integer> {
    // ...
    Stream<User> findAllByName(String name);
    // ...
}

Spring Data uses provider-specific implementation to stream the result (Hibernate uses ScrollableResultSet, EclipseLink uses ScrollableCursor). It reduces the amount of memory consumption and query calls to a database. Because of that, it’s also much faster than two solutions mentioned earlier.

Processing data with a Stream requires us to close a Stream when we finish it.

It can be done by calling the close() method on a Stream or by using try-with-resources:

try (Stream<User> foundUsersStream 
  = userRepository.findAllByName(USER_NAME_ADAM)) {
 
assertThat(foundUsersStream.count(), equalTo(3l));

We must also remember to call a repository method within a transaction. Otherwise, we’ll get an exception:

org.springframework.dao.InvalidDataAccessApiUsageException: You’re trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction.

4. CompletableFuture

Spring Data repositories can run asynchronously with the support of Java 8’s CompletableFuture and Spring mechanism for asynchronous method execution:

@Async
CompletableFuture<User> findOneByStatus(Integer status);

A client which calls this method will return a future immediately but a method will continue an execution in a different thread.

More info about CompletableFuture processing can be found here.

5. Conclusion

In this tutorial, we showed how Java 8 features work together with Spring Data.

The full implementation of the examples is available over on Github.

Related posts:

Guide to the Java Clock Class
How to Return 404 with Spring WebFlux
Giới thiệu Google Guice – Aspect Oriented Programming (AOP)
Java Program to Implement Attribute API
Hướng dẫn Java Design Pattern – Strategy
Java Program to Implement Min Heap
Map to String Conversion in Java
Java Program to Implement the Bin Packing Algorithm
Spring REST API + OAuth2 + Angular (using the Spring Security OAuth legacy stack)
The Registration Process With Spring Security
Intro to Inversion of Control and Dependency Injection with Spring
Java Program to Implement Merge Sort Algorithm on Linked List
Mệnh đề Switch-case trong java
Java Program to Check Multiplicability of Two Matrices
Java List UnsupportedOperationException
Guide to the ConcurrentSkipListMap
Java Program to Implement Branch and Bound Method to Perform a Combinatorial Search
A Quick Guide to Spring MVC Matrix Variables
Java Program to Generate a Graph for a Given Fixed Degree Sequence
Convert Character Array to String in Java
Spring Web Annotations
Câu lệnh điều khiển vòng lặp trong Java (break, continue)
Spring Cloud Series – The Gateway Pattern
Java Program to Implement the Alexander Bogomolny’s UnOrdered Permutation Algorithm for Elements Fro...
Java Program to Implement Quick Sort with Given Complexity Constraint
Spring REST API with Protocol Buffers
Spring Boot - Build Systems
A Custom Data Binder in Spring MVC
A Guide to Java HashMap
Java Program to Implement Randomized Binary Search Tree
Java Program to Implement Sparse Matrix
Java Program to Implement Sorted Circular Doubly Linked List