Hi everyone!
- If plugin version is 2.6.0 or higher this exception OCCURS even if all concrete starters version is 2.5.7.
- If plugin version is 2.5.7 this exception NOT OCCURS even if all concrete starters version is 2.6.0 or higher.
All EnumCodecs and customConverters are set in AbstractR2dbcConfiguration.
Plugins block:
plugins {
idea
// if update from 2.5.7 to 2.6.(0,1) tests will fail on save to repo (23.11.2021)
id("org.springframework.boot") version "2.6.1"
id("com.github.ben-manes.versions") version "0.39.0"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
id("org.asciidoctor.jvm.convert") version "3.3.2"
id("com.google.cloud.tools.jib") version "3.1.4"
id("org.jetbrains.kotlin.jvm") version "1.6.10-RC"
id("org.jetbrains.kotlin.plugin.spring") version "1.6.10-RC"
}
Dependencies block:
dependencies {
implementation("org.springframework.boot:spring-boot-starter:2.6.1")
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc:2.6.1")
implementation("org.springframework.boot:spring-boot-starter-webflux:2.6.1")
implementation("org.springframework.boot:spring-boot-starter-security:2.6.1")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor:2.6.1")
testImplementation("org.springframework.boot:spring-boot-starter-test:2.6.1")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10-RC")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10-RC")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.6.0-RC")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions:1.1.5")
testImplementation("io.projectreactor:reactor-test:3.4.12")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.0")
implementation("io.github.microutils:kotlin-logging-jvm:2.1.15")
implementation("org.hibernate:hibernate-validator:7.0.1.Final")
implementation("one.util:streamex:0.8.0")
implementation("com.github.javafaker:javafaker:1.0.2")
implementation("com.google.firebase:firebase-admin:8.1.0")
implementation("org.postgresql:postgresql:42.3.1")
implementation("io.r2dbc:r2dbc-postgresql:0.8.10.RELEASE")
testImplementation(platform("org.junit:junit-bom:5.8.2"))
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
implementation(platform("org.testcontainers:testcontainers-bom:1.16.2"))
testImplementation("org.testcontainers:testcontainers")
testImplementation("org.testcontainers:r2dbc")
testImplementation("org.testcontainers:postgresql")
testImplementation("org.testcontainers:junit-jupiter")
}
Exception logs:
2021-12-09 15:12:39.276 DEBUG 331051 --- [-1 @coroutine#6] o.s.d.r2dbc.core.NamedParameterExpander : Expanding SQL statement [
INSERT INTO clients
(user_id, verified, phone_number, name, avatar_url, email, description, online_visibility_allowed_for, incoming_call_allowed_for)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9)
] to [
INSERT INTO clients
(user_id, verified, phone_number, name, avatar_url, email, description, online_visibility_allowed_for, incoming_call_allowed_for)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9)
]
Cannot encode parameter of type org.springframework.r2dbc.core.Parameter
java.lang.IllegalArgumentException: Cannot encode parameter of type org.springframework.r2dbc.core.Parameter
at io.r2dbc.postgresql.codec.DefaultCodecs.encode(DefaultCodecs.java:192)
at io.r2dbc.postgresql.ExtendedQueryPostgresqlStatement.bind(ExtendedQueryPostgresqlStatement.java:89)
at io.r2dbc.postgresql.ExtendedQueryPostgresqlStatement.bind(ExtendedQueryPostgresqlStatement.java:47)
at org.springframework.r2dbc.core.DefaultDatabaseClient$StatementWrapper.bind(DefaultDatabaseClient.java:544)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
at org.springframework.data.r2dbc.repository.query.StringBasedR2dbcQuery$ExpandedQuery.bindTo(StringBasedR2dbcQuery.java:227)
at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$execute$2(DefaultDatabaseClient.java:334)
at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$execute$3(DefaultDatabaseClient.java:374)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:46)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:31)
at org.springframework.r2dbc.core.DefaultFetchSpec.lambda$all$2(DefaultFetchSpec.java:88)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:46)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:31)
at org.springframework.r2dbc.core.DefaultDatabaseClient.lambda$inConnectionMany$6(DefaultDatabaseClient.java:138)
at reactor.core.publisher.FluxUsingWhen.deriveFluxFromResource(FluxUsingWhen.java:119)
...
at reactor.core.publisher.Flux.subscribe(Flux.java:8469)
at kotlinx.coroutines.reactive.AwaitKt.awaitOne(Await.kt:190)
at kotlinx.coroutines.reactive.AwaitKt.awaitOne$default(Await.kt:183)
at kotlinx.coroutines.reactive.AwaitKt.awaitSingleOrNull(Await.kt:141)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvokeReactiveToSuspended(RepositoryMethodInvoker.java:185)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:159)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy126.create(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy126.create(Unknown Source)
at by.citech.cryptohf.signalserver.repo.ClientRepo.create$suspendImpl(ClientRepo.kt:105)
at by.citech.cryptohf.signalserver.repo.ClientRepo.create(ClientRepo.kt)
at by.citech.cryptohf.signalserver.repo.ClientRepo$$FastClassBySpringCGLIB$$228d6fca.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at by.citech.cryptohf.signalserver.repo.ClientRepo$$EnhancerBySpringCGLIB$$c9dbe186.create(<generated>)
at by.citech.cryptohf.signalserver.repo.UserRepo.create$suspendImpl(UserRepo.kt:56)
at by.citech.cryptohf.signalserver.repo.UserRepo$create$1.invokeSuspend(UserRepo.kt)
(Coroutine boundary)
at by.citech.cryptohf.signalserver.repo.UserRepo.create$suspendImpl(UserRepo.kt:56)
at kotlin.reflect.full.KCallables.callSuspend(KCallables.kt:56)
at by.citech.cryptohf.signalserver.repo.SimpleDbTest$user repo created and user can be saved$1.invokeSuspend(PostgreContainerTest.kt:46)
Caused by: java.lang.IllegalArgumentException: Cannot encode parameter of type org.springframework.r2dbc.core.Parameter
at io.r2dbc.postgresql.codec.DefaultCodecs.encode(DefaultCodecs.java:192)
at io.r2dbc.postgresql.ExtendedQueryPostgresqlStatement.bind(ExtendedQueryPostgresqlStatement.java:89)
at io.r2dbc.postgresql.ExtendedQueryPostgresqlStatement.bind(ExtendedQueryPostgresqlStatement.java:47)
at org.springframework.r2dbc.core.DefaultDatabaseClient$StatementWrapper.bind(DefaultDatabaseClient.java:544)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
at org.springframework.data.r2dbc.repository.query.StringBasedR2dbcQuery$ExpandedQuery.bindTo(StringBasedR2dbcQuery.java:227)
at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$execute$2(DefaultDatabaseClient.java:334)
at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$execute$3(DefaultDatabaseClient.java:374)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:46)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:31)
at org.springframework.r2dbc.core.DefaultFetchSpec.lambda$all$2(DefaultFetchSpec.java:88)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:46)
at org.springframework.r2dbc.core.ConnectionFunction.apply(ConnectionFunction.java:31)
at org.springframework.r2dbc.core.DefaultDatabaseClient.lambda$inConnectionMany$6(DefaultDatabaseClient.java:138)
at reactor.core.publisher.FluxUsingWhen.deriveFluxFromResource(FluxUsingWhen.java:119)
...
at kotlinx.coroutines.reactive.AwaitKt.awaitSingleOrNull(Await.kt:141)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvokeReactiveToSuspended(RepositoryMethodInvoker.java:185)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:159)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy126.create(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy126.create(Unknown Source)
at by.citech.cryptohf.signalserver.repo.ClientRepo.create$suspendImpl(ClientRepo.kt:105)
at by.citech.cryptohf.signalserver.repo.ClientRepo.create(ClientRepo.kt)
at by.citech.cryptohf.signalserver.repo.ClientRepo$$FastClassBySpringCGLIB$$228d6fca.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at by.citech.cryptohf.signalserver.repo.ClientRepo$$EnhancerBySpringCGLIB$$c9dbe186.create(<generated>)
at by.citech.cryptohf.signalserver.repo.UserRepo.create$suspendImpl(UserRepo.kt:56)
at by.citech.cryptohf.signalserver.repo.UserRepo$create$1.invokeSuspend(UserRepo.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
...
Comment From: wilkinsona
- If plugin version is 2.6.0 or higher this exception OCCURS even if all concrete starters version is 2.5.7.
- If plugin version is 2.5.7 this exception NOT OCCURS even if all concrete starters version is 2.6.0 or higher.
You shouldn't mix versions in this manner, but rely on Spring Boot's dependency management to control the versions for you instead. I suspect the difference in behaviour is either due to a change in R2DBC or Spring Data R2DBC or due to mismatched versions of some dependencies.
If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Comment From: clayly
- If plugin version is 2.6.0 or higher this exception OCCURS even if all concrete starters version is 2.5.7.
- If plugin version is 2.5.7 this exception NOT OCCURS even if all concrete starters version is 2.6.0 or higher.
You shouldn't mix versions in this manner, but rely on Spring Boot's dependency management to control the versions for you instead. I suspect the difference in behaviour is either due to a change in R2DBC or Spring Data R2DBC or due to mismatched versions of some dependencies.
If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Thx for reply. Maybe it's not clear from my report, but the thing that only setting plugin version to 2.6.x makes exception happen. Originally no version for starters were set, like you said. Examples: * plugin version "2.6.X", all starters version inherited: EXCEPTION * plugin version "2.6.X", all starters version "2.5.7": EXCEPTION * plugin version "2.6.X", all starters version "2.6.X": EXCEPTION * plugin version "2.5.7", all starters version "2.5.7": OK * plugin version "2.5.7", all starters version "2.6.X": OK * plugin version "2.5.7", all starters version inherited: OK
Comment From: wilkinsona
Yes, that was clear. Setting the individual starter versions won't affect the versions of their transitive dependencies. Those will still be controlled by Spring Boot's dependency management. By setting the versions on some individual dependencies, you're going to end up with a mixture of versions that may or may not be compatible.
Given that the failure occurs when you use the 2.6.x plugin in all three scenarios, it would appear that a change in one of your application's transitive dependencies is causing the problem. If you can provide a minimal sample, we can try to identify the cause.
Comment From: clayly
Yes, that was clear. Setting the individual starter versions won't affect the versions of their transitive dependencies. Those will still be controlled by Spring Boot's dependency management. By setting the versions on some individual dependencies, you're going to end up with a mixture of versions that may or may not be compatible.
Given that the failure occurs when you use the 2.6.x plugin in all three scenarios, it would appear that a change in one of your application's transitive dependencies is causing the problem. If you can provide a minimal sample, we can try to identify the cause.
I am trying to make simple example. Looks like error not even related to enums. Here is simple schema, entity and repository code:
CREATE TABLE public.clients (
id BIGSERIAL PRIMARY KEY,
client_type TEXT NOT NULL
);
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Column
import org.springframework.data.relational.core.mapping.Table
@Table("clients")
data class Client(
@Id
@Column("id")
val id: Long,
@Column("client_type")
val clientType: String
)
import org.springframework.data.r2dbc.repository.Query
import org.springframework.data.repository.kotlin.CoroutineCrudRepository
import org.springframework.stereotype.Repository
@Repository
interface ClientRepo : CoroutineCrudRepository<Client, Long> {
@Query("INSERT INTO clients (client_type) VALUES ($1)")
suspend fun create(clientType: String)
}
Is it looks legit to you? Do you see any problems with it?
Comment From: philwebb
@clayly We really need the code in a git repository or as an attached zip file so that we can run and debug it locally. Does the code you've pasted above fail with the same stack trace?
Comment From: clayly
@clayly We really need the code in a git repository or as an attached zip file so that we can run and debug it locally. Does the code you've pasted above fail with the same stack trace?
I got it! I worked on simple example, this is basically it. But just in case of some obvious mistakes I decided to ask.
Yes, this code fails on create
method on 2.6.x plugin and works on 2.5.7 plugin.
Comment From: clayly
@clayly We really need the code in a git repository or as an attached zip file so that we can run and debug it locally. Does the code you've pasted above fail with the same stack trace?
Here it is!
spring-r2dbc-postgre-enum-err.zip
Comment From: wilkinsona
Thanks for the sample.
I believe the change in behaviour is due to these changes in Spring Data R2DBC 1.4. As the query is now a PreparedOperation
, this causes Spring Framework's StatementWrapper
to be used. When binding to the statement, it passes the value (a Parameter
) as-is when cannot be handled by the codecs. Prior to those changes, the Parameter's value (a String
) was extracted and that was passed into the statement. The String
can be handled by StringCodec
so the failure did not occur.
I've opened https://github.com/spring-projects/spring-data-r2dbc/issues/694 so that the Spring Data R2DBC team can investigate.