I'm working on an existing Spring Boot 2.4 project and trying to bring in Webflux and R2DBC into an existing JPA based app.
I'm able to bring in the Webflux dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
without any issues, my app starts and behaves as it should, was able to perform some tests using Flux/Mono and all is good.
To get full reactivity however, I need to go all the way down to the persistence layer, i.e. also bringing in R2DBC dependency (for postgres)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<version>0.8.6.RELEASE</version>
</dependency>
I have the following as my configuration class:
@Configuration
@EnableR2dbcRepositories(
repositoryBaseClass = ReactiveCrudRepository.class
)
public class R2DBCConfiguration extends AbstractR2dbcConfiguration {
@Bean
@Qualifier("rxConnectionFactory")
@Override
public ConnectionFactory connectionFactory() {
return new PostgresqlConnectionFactory(
PostgresqlConnectionConfiguration
.builder()
.username("user")
.password("password")
.host("localhost")
.port(5432)
.database("my_db")
.build()
);
}
}
With this dependency, my project fails to start, consistently giving the same exception:
Caused by: java.lang.IllegalStateException: Cannot apply reactive transaction to non-reactive return type: interface java.util.List
at org.springframework.transaction.interceptor.TransactionAspectSupport.lambda$invokeWithinTransaction$0(TransactionAspectSupport.java:351)
at java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:324)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:346)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:134)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at com.mycompany.myapplication.service.SettingsServiceImpl$$EnhancerBySpringCGLIB$$5198d258.findAll(<generated>)
at com.mycompany.myapplication.service.RuntimeSettingsServiceImpl.populateMap(RuntimeSettingsServiceImpl.java:96)
at com.mycompany.myapplication.service.RuntimeSettingsServiceImpl.init(RuntimeSettingsServiceImpl.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
... 109 common frames omitted
I'm failing to understand why this is happening - we do use the traditional SimpleJpaRepository implementation for our DAOs / none of which extend ReactiveCrudRepository and thus should not be "seen" as reactive stores from the app point of view.
In any case I was wondering if others have faced a similar scenario and a possible workaround/fix.
Check my answer to this question, and I also provided a working example.
BTW, I do not think it is a good option mixed blocking JPA APIs and none-blocking R2dbc APIs in the sample application.