Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data JPA How to use Kotlin nulls instead of Optional

I'm writing a Spring Boot app with Spring Data JPA and Kotlin, and I've noticed that in CrudRepository there is the following method:

Optional<T> findById(ID id);

I'm using Kotlin, though, which has much more fluent ways of dealing with nulls than Optional. Does anyone know how I would convert that method to work like this?

fun findById(id: ID): T?

When I extend Repository itself and create a repo with that signature I get the error:

java.lang.ClassCastException: java.util.Optional cannot be cast to com.books.Book
like image 207
CorayThan Avatar asked Nov 06 '17 18:11

CorayThan


People also ask

How does JPA handle null values?

The JPA specification defines that during ordering, NULL values shall be handled in the same way as determined by the SQL standard. The standard specifies that all null values shall be returned before or after all non-null values. It's up to the database to pick one of the two options.

Is null in JPQL?

Following example shows how to use IS NULL to find properties values which have not been set.

Should you use Optional in Kotlin?

Depending on whom you ask, using Optional as the type of a field or return type is bad practice in Java. Fortunately, in Kotlin there is no arguing about it. Using nullable types in properties or as the return type of functions is considered perfectly valid and idiomatic in Kotlin.

Does Spring JPA return empty list or null?

The normal behavior is indeed returning an empty list if no results are found. If a List<Object> is the return value of the method in the defined interface, the method should never return Null . The problem is that a parameter is given to the method and is not used anywhere in the Query.

Can I use JPA and spring data with Kotlin?

It provides you with smart completion for method names and quick-fixes for parameters: Also, custom queries with Expression Language variables are now supported: Please try using JPA and Spring Data with Kotlin and share your experience with us. More posts about Kotlin with Spring support in IntelliJ IDEA are coming.

How does the Kotlin compiler generate default method implementations?

The Kotlin compiler generates the default method implementations based on all properties of a data class. When we’re using data classes for JPA entities, some of those properties might be a lazy association with the target entity.

How do I get a nullable type in Kotlin?

Since nullable types in Kotlin are not wrapped in another class like Optional, there’s no need for an equivalent of the get () method - just assign the value where you need it. Again, we have to go out of our way to throw an exception to match the Java API. To provide a default to use when the value is null, use the safe call operator.

How do I unwrap an optional in Kotlin?

When mapping an Optional in Java, sometimes you have to unwrap another Optional. To do this, you use flatMap () instead of map (). With Kotlin’s null system, the value is either present, or null, so there’s nothing to unwrap.


3 Answers

As of Spring Data Lovelace SR4 / Spring Boot 2.1.2, a CrudRepository.findByIdOrNull(id: ID): T? = findById(id).orElse(null) Kotlin extension now provides out of the box a way to retrieve nullable entities in Spring Data.

If for performance reasons you would like to avoid the usage of Optional<T> wrapper, be aware that you have also the possibility to create a custom interface with a findFooById(id: ID): T? function. Query execution is store specific, but and most are using internally nullable values and will avoid the cost of Optional<T> wrapper. Notice this overhead should be negligible for most use cases, so using the builtin extension is recommended method.

See DATACMNS-1346 for more details.

like image 63
Sébastien Deleuze Avatar answered Oct 12 '22 23:10

Sébastien Deleuze


Update 12/2018:

An upcoming change in the Spring Data framework will make this answer obsolete. The update basically does the same as this answer: define an appropriate extension function. Please see Sébastien Deleuze's answer for further details.

Original answer:

As you correctly stated, you don't need Optional in Kotlin, because handling nullability in a concise manner is a build in language feature.

You could create your own extension function to achieve the desired behaviour:

fun <T, ID> CrudRepository<T, ID>.findOne(id: ID): T? = findById(id).orElse(null)

and use it like this:

val fruit: Fruit? = fruitRepository.findOne(id)

Thanks to Giordano who showed me a way to make the function more concise.

like image 20
Willi Mentzel Avatar answered Oct 13 '22 00:10

Willi Mentzel


Short version of Sébastien Deleuze's answer: Just define a function with a nullable return type:

interface UserRepository : Repository<User, String> {

  // throws EmptyResultDataAccessException, if no user is found
  fun findByUsername(username: String): User     

  // return null, if no user is found
  fun findByFirstname(firstname: String?): User? 
}

See Spring Data Reference Documentation.

like image 5
deamon Avatar answered Oct 13 '22 00:10

deamon