Skip to content

Saving Enum-typed Collection-like properties set to null are not translated to String[] #593

@markitovtr1

Description

@markitovtr1

Hi,

I'm having a bit of an issue with Spring Data R2DBC and array text columns, when I have a enum on Kotlin side. Whenever I retrieve an object through Spring Data Repository, I cannot save it back to database if column is mapped as List<MyEnum>. If it is mapped as List<String>, it works fine.

Here is a repo reproducing this issue:
https://github.com/markitovtr1/spring-data-r2dbc-list-enum-save-issue

Versions:
Java: openjdk version "11.0.10" 2021-01-19
OS: Ubuntu 20.04 (WSL2)
Spring Boot: 2.4.5

Exception stack trace:

    java.lang.IllegalArgumentException: Cannot encode null parameter of type [Lissues.springdata.listenum.TestEnum;
        (Coroutine boundary)
        at issues.springdata.listenum.ListEnumApplicationTests$listEnumRepository$saved$1$1.invokeSuspend(ListEnumApplicationTests.kt:23)

        Caused by:
        java.lang.IllegalArgumentException: Cannot encode null parameter of type [Lissues.springdata.listenum.TestEnum;
            at io.r2dbc.postgresql.codec.DefaultCodecs.encodeNull(DefaultCodecs.java:181)
            at io.r2dbc.postgresql.ExtendedQueryPostgresqlStatement.bindNull(ExtendedQueryPostgresqlStatement.java:110)
            at io.r2dbc.postgresql.ExtendedQueryPostgresqlStatement.bindNull(ExtendedQueryPostgresqlStatement.java:47)
            at org.springframework.r2dbc.core.DefaultDatabaseClient$StatementWrapper.bindNull(DefaultDatabaseClient.java:554)
            at org.springframework.r2dbc.core.binding.IndexedBindMarkers$IndexedBindMarker.bindNull(IndexedBindMarkers.java:91)
            at org.springframework.r2dbc.core.binding.Bindings$NullBinding.apply(Bindings.java:250)
            at org.springframework.r2dbc.core.binding.Bindings.lambda$apply$1(Bindings.java:93)
            at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
            at org.springframework.r2dbc.core.binding.Bindings.apply(Bindings.java:93)
            at org.springframework.data.r2dbc.core.DefaultStatementMapper$DefaultPreparedOperation.bindTo(DefaultStatementMapper.java:354)
            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.DefaultDatabaseClient.sumRowsUpdated(DefaultDatabaseClient.java:193)
            at org.springframework.r2dbc.core.DefaultDatabaseClient.access$000(DefaultDatabaseClient.java:65)
            at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$execute$4(DefaultDatabaseClient.java:382)
            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$inConnection$2(DefaultDatabaseClient.java:116)
            at reactor.core.publisher.MonoUsingWhen.deriveMonoFromResource(MonoUsingWhen.java:114)
            at reactor.core.publisher.MonoUsingWhen.access$000(MonoUsingWhen.java:46)
            at reactor.core.publisher.MonoUsingWhen$ResourceSubscriber.onNext(MonoUsingWhen.java:183)
            at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:120)
            at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
            at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
            at reactor.core.publisher.FluxRetry$RetrySubscriber.onNext(FluxRetry.java:86)
            at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:210)
            at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
            at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
            at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
            at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:284)
            at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187)
            at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:232)
            at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203)
            at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:88)
            at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:846)
            at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:608)
            at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:588)
            at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:465)
            at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onComplete(FluxContextWrite.java:126)
            at io.r2dbc.postgresql.util.FluxDiscardOnCancel$FluxDiscardOnCancelSubscriber.onComplete(FluxDiscardOnCancel.java:99)
            at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:150)
            at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:150)
            at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.checkTerminated(FluxWindowPredicate.java:537)
            at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.drainLoop(FluxWindowPredicate.java:485)
            at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.drain(FluxWindowPredicate.java:429)
            at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onComplete(FluxWindowPredicate.java:309)
            at reactor.core.publisher.FluxCreate$BaseSink.complete(FluxCreate.java:439)
            at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:784)
            at reactor.core.publisher.FluxCreate$BufferAsyncSink.complete(FluxCreate.java:732)
            at reactor.core.publisher.FluxCreate$SerializedFluxSink.drainLoop(FluxCreate.java:240)
            at reactor.core.publisher.FluxCreate$SerializedFluxSink.drain(FluxCreate.java:206)
            at reactor.core.publisher.FluxCreate$SerializedFluxSink.complete(FluxCreate.java:197)
            at io.r2dbc.postgresql.client.ReactorNettyClient$Conversation.complete(ReactorNettyClient.java:719)
            at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.emit(ReactorNettyClient.java:984)
            at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:860)
            at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:767)
            at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:118)
            at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
            at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:220)
            at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:220)
            at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:280)
            at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:389)
            at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:401)
            at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:94)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
            at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
            at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
            at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
            at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
            at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
            at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
            at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795)
            at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480)
            at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
            at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
            at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
            at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
            at java.base/java.lang.Thread.run(Thread.java:834)

Metadata

Metadata

Assignees

Labels

in: mappingMapping and conversion infrastructuretype: bugA general bug

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions