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:

Using the Not Operator in If Conditions in Java
Java Program to Generate a Random Subset by Coin Flipping
Send email with JavaMail
Java Program to Implement Binomial Heap
Java Program to Find Minimum Number of Edges to Cut to make the Graph Disconnected
Ways to Iterate Over a List in Java
HttpClient Connection Management
Map to String Conversion in Java
Java Program to Implement ConcurrentLinkedQueue API
Java Program to Find kth Smallest Element by the Method of Partitioning the Array
Chuyển đổi Array sang ArrayList và ngược lại
Spring Boot - Batch Service
Java Program to Implement Levenshtein Distance Computing Algorithm
Hướng dẫn Java Design Pattern – Proxy
Spring Boot - Bootstrapping
Introduction to Spring Data JPA
Marker Interface trong Java
Predicate trong Java 8
OAuth2 for a Spring REST API – Handle the Refresh Token in AngularJS
Java Program to Implement Traveling Salesman Problem using Nearest neighbour Algorithm
Convert XML to JSON Using Jackson
Introduction to Using Thymeleaf in Spring
Java Program to Find a Good Feedback Edge Set in a Graph
How to Get a Name of a Method Being Executed?
Java Program to Check if an UnDirected Graph is a Tree or Not Using DFS
Java Program to Implement the Edmond’s Algorithm for Maximum Cardinality Matching
Form Validation with AngularJS and Spring MVC
Comparing Long Values in Java
Introduction to Netflix Archaius with Spring Cloud
Java Program to Perform Cryptography Using Transposition Technique
Control Structures in Java
Java – Get Random Item/Element From a List