Keywords: Spring Data JPA | Optional | findById
Abstract: This article details the changes in Spring Data JPA from Spring Boot 2.0, where the findOne() method was replaced by findById() returning Optional. It provides practical code examples for three common usage scenarios: obtaining default values, throwing exceptions, and conditional handling, aiding developers in transitioning smoothly to the new API and preventing NullPointerException.
Historical Changes to the findOne() Method in Spring Data JPA
Starting with Spring Boot 2.0, Spring Data JPA underwent significant changes to the findOne() method. It no longer retains its original signature and behavior. In older versions, the CrudRepository interface defined T findOne(ID primaryKey), which directly returned an entity object. However, in the new version, this method has been removed and replaced by <S extends T> Optional<S> findOne(Example<S> example) from the QueryByExampleExecutor interface, intended for query-by-example searches, not as a replacement for ID-based queries.
Introduction of the New findById() Method and Benefits of Optional
In practice, the functionality for querying by ID has been renamed to findById() and is defined in the CrudRepository interface as Optional<T> findById(ID id). This change introduces Java 8's Optional type, with the key advantage of effectively preventing NullPointerException. Optional is a container object that may or may not contain a non-null value. Methods such as isPresent() check for value presence, get() retrieves the value, and others like orElse() and ifPresent() offer flexible handling.
Three Common Usage Scenarios for Optional
When using the findById() method, developers can choose different Optional handling approaches based on business needs. Below are code examples for three typical scenarios:
Scenario 1: Obtain Entity or Default Value
If the entity is found, return it; otherwise, return a default value. For example, using the orElse() method:
Foo foo = repository.findById(id)
.orElse(new Foo());Or return null to maintain old behavior:
Foo foo = repository.findById(id)
.orElse(null);Scenario 2: Obtain Entity or Throw Exception
When the entity does not exist, throw a custom exception. Use the orElseThrow() method:
return repository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(id));Scenario 3: Conditional Handling Based on Entity Existence
Execute different logic depending on whether the entity exists, without necessarily throwing an exception. Use the isPresent() and get() methods:
Optional<Foo> fooOptional = fooRepository.findById(id);
if (fooOptional.isPresent()) {
Foo foo = fooOptional.get();
// processing with foo
} else {
// alternative processing
}Practical Application Examples and Migration Recommendations
In Spring Boot 2.0 projects, replace existing findOne() calls with findById(). For instance, in the service layer, the original code public Category findOne(Long id) { return categoryRepository.findOne(id); } should be changed to public Optional<Category> findById(Long id) { return categoryRepository.findById(id); }. In controllers, handle the returned Optional object by combining the above scenarios, such as using orElse(null) to adapt to existing model addition logic. This change not only enhances code robustness but also encourages safer programming practices.