-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
This is a small extract from my demo project from GitHub including some tests:
@RestController
class HelloController(private val service: HelloService) {
@PutMapping("/hello/{id}")
suspend fun update(@PathVariable("id") id: Long): Unit = service.update(id)
@GetMapping("/hello/{id}")
suspend fun find(@PathVariable("id") id: Long): HelloEntity? = service.find(id)
}
@Service
class HelloService(private val helloRepository: HelloRepository) {
@Transactional
suspend fun update(id: Long) {
helloRepository.updateMessage(id, "Hello, Spring Boot!")
}
@Transactional
suspend fun find(id: Long): HelloEntity? = helloRepository.suspendFindById(id)
}
@Entity
class HelloEntity(@Id var id: Long? = null, var message: String = "Hello")
@Repository
interface HelloRepository : ListCrudRepository<HelloEntity, Long> {
@Modifying
@Query("update HelloEntity e set e.message = :message where e.id = :id")
suspend fun updateMessage(id: Long, message: String): Int
@Query("select e from HelloEntity e where e.id = :id")
suspend fun suspendFindById(id: Long): HelloEntity?
@Query("select e from HelloEntity e")
fun findAllFlow(): Flow<HelloEntity>
}
I found multiple problems:
- Having a method like
fun findAllFlow(): Flow<HelloEntity>
results in startup failure asIllegaleStateException: Reactive Repositories are not supported by JPA
- Having a method like
suspend fun suspendFindById(id: Long): HelloEntity?
returningnull
cause the underlying entity is not found results inInvalidDataAccessApiUsageException: Reactive source object must not be null
- Same method as before but this time a record is found:
ConversionFailedException: Failed to convert from type [com.example.demo.HelloEntity] to type [reactor.core.publisher.Flux<?>] for value [com.example.demo.HelloEntity@15045e40]
- As you can see from the demo code, the Service is annotated with
@Transactional
. When calling the serviceupdate
method, an error is triggered from some of the Spring Data repository infrastructure code:TransactionRequiredException: Executing an update/delete query
. Seems like the transaction is not properly propagated
At the moment suspend functions are pretty unusable at all from my app. Is this something which should be supported? Would definitely appreciate it. The only thing I found is within the Spring Data Commons Reference Documentation, which seems to outline support.
Some more background information: We use a lot of suspending functions in our Kotlin Spring Boot app which get invoked within the controller. At the moment we use blocking JPA repository methods and wrap them manually in a withContext(Dispatcher.IO)
call, which is not just tedious, but also error prone.
Being able to natively use them within the repository would help us in reducing complexity here.
For instance, JooQ also supports Kotlin Coroutines even for blocking JDBC drivers.
Other considered resources: