Skip to content

Reading entity with null value for primitive field fails since #4464 #4658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bala-striva opened this issue Mar 11, 2024 · 1 comment
Closed
Labels
status: declined A suggestion or change that we don't feel we should currently apply

Comments

@bala-striva
Copy link

When reading an entity with a ReactiveMongoRepository with a primitive field (e.g.: long) fails if the field is set to null in mongodb.
This was working in 2.7.14 as org.springframework.data.mongodb.util.BsonUtils#hasValue returned false when the document contained an explicit null value.

After upgrading to spring boot 3 the following error occurs

java.lang.NullPointerException: Cannot invoke "java.lang.Number.longValue()" because the return value of "sun.invoke.util.ValueConversions.primitiveConversion(sun.invoke.util.Wrapper, Object, boolean)" is null
    at java.base/sun.invoke.util.ValueConversions.unboxLong(Unknown Source) ~[na:na]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ? Handler repository.AccountController#findAccountByIdentifier(String, AccountFindByIdentifierDTO) [DispatcherHandler]
Original Stack Trace:
        at java.base/sun.invoke.util.ValueConversions.unboxLong(Unknown Source) ~[na:na]
        at domain.Account_Accessor_6u3zcq.setProperty(Unknown Source) ~[classes/:0.0.1-SNAPSHOT]
        at org.springframework.data.mapping.model.InstantiationAwarePropertyAccessor.setProperty(InstantiationAwarePropertyAccessor.java:80) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:60) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readProperties(MappingMongoConverter.java:626) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.populateProperties(MappingMongoConverter.java:544) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:522) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readDocument(MappingMongoConverter.java:487) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:423) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:419) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:119) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at org.springframework.data.mongodb.core.ReactiveMongoTemplate$ReadDocumentCallback.doWith(ReactiveMongoTemplate.java:3120) ~[spring-data-mongodb-4.2.2.jar:4.2.2]
        at reactor.core.publisher.FluxMergeSequential$MergeSequentialMain.onNext(FluxMergeSequential.java:208) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:880) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxCreate$BufferAsyncSink.next(FluxCreate.java:805) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxCreate$SerializedFluxSink.next(FluxCreate.java:163) ~[reactor-core-3.6.2.jar:3.6.2]
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source) ~[na:na]
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(Unknown Source) ~[na:na]
        at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) ~[na:na]
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source) ~[na:na]
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) ~[na:na]
        at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source) ~[na:na]
        at com.mongodb.reactivestreams.client.internal.BatchCursorFlux.lambda$recurseCursor$5(BatchCursorFlux.java:102) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:171) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:176) ~[reactor-core-3.6.2.jar:3.6.2]
        at com.mongodb.reactivestreams.client.internal.BatchCursor.lambda$next$1(BatchCursor.java:50) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at com.mongodb.internal.operation.AsyncQueryBatchCursor.next(AsyncQueryBatchCursor.java:178) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.reactivestreams.client.internal.BatchCursor.lambda$next$2(BatchCursor.java:42) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.Mono.subscribe(Mono.java:4512) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.Mono.subscribeWith(Mono.java:4578) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.Mono.subscribe(Mono.java:4339) ~[reactor-core-3.6.2.jar:3.6.2]
        at com.mongodb.reactivestreams.client.internal.BatchCursorFlux.recurseCursor(BatchCursorFlux.java:112) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at com.mongodb.reactivestreams.client.internal.BatchCursorFlux.lambda$subscribe$0(BatchCursorFlux.java:61) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at reactor.core.publisher.LambdaMonoSubscriber.onNext(LambdaMonoSubscriber.java:171) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:245) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:305) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[reactor-core-3.6.2.jar:3.6.2]
        at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:176) ~[reactor-core-3.6.2.jar:3.6.2]
        at com.mongodb.reactivestreams.client.internal.MongoOperationPublisher.lambda$sinkToCallback$33(MongoOperationPublisher.java:525) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at com.mongodb.reactivestreams.client.internal.OperationExecutorImpl.lambda$execute$2(OperationExecutorImpl.java:94) ~[mongodb-driver-reactivestreams-4.11.1.jar:na]
        at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:47) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.function.AsyncCallbackSupplier.lambda$whenComplete$1(AsyncCallbackSupplier.java:97) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.function.RetryingAsyncCallbackSupplier$RetryingCallback.onResult(RetryingAsyncCallbackSupplier.java:116) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:47) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.function.AsyncCallbackSupplier.lambda$whenComplete$1(AsyncCallbackSupplier.java:97) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:47) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.function.AsyncCallbackSupplier.lambda$whenComplete$1(AsyncCallbackSupplier.java:97) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.operation.FindOperation.lambda$exceptionTransformingCallback$6(FindOperation.java:369) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.operation.AsyncOperationHelper.lambda$transformingReadCallback$19(AsyncOperationHelper.java:442) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:47) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.lambda$executeAsync$0(DefaultServer.java:249) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:47) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.CommandProtocolImpl.lambda$executeAsync$0(CommandProtocolImpl.java:88) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.lambda$sendAndReceiveAsync$1(DefaultConnectionPool.java:802) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.UsageTrackingInternalConnection.lambda$sendAndReceiveAsync$1(UsageTrackingInternalConnection.java:155) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:47) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.InternalStreamConnection.lambda$sendCommandMessageAsync$0(InternalStreamConnection.java:555) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:849) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:812) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.InternalStreamConnection$3.completed(InternalStreamConnection.java:671) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.internal.connection.InternalStreamConnection$3.completed(InternalStreamConnection.java:668) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:332) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.connection.netty.NettyStream.handleReadResponse(NettyStream.java:359) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.connection.netty.NettyStream.access$1100(NettyStream.java:112) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:435) ~[mongodb-driver-core-4.11.1.jar:na]
        at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:432) ~[mongodb-driver-core-4.11.1.jar:na]
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.105.Final.jar:4.1.105.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.105.Final.jar:4.1.105.Final]
        at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]

Is this expected with the change in #4464 (https://github.com/spring-projects/spring-data-mongodb/pull/4512/files#diff-c90dac2b22039f287a63d2212d415a2d1d9aae1d8d8ba69eb034ba1ad0c00b4bL563)?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 11, 2024
@mp911de
Copy link
Member

mp911de commented Mar 11, 2024

You're referring to #4571 where we now read all values from a Document. Previously, our hasValue check used get(field) != null as check and that left pre-initialized fields with their values although the MongoDB document indicated a null value.

The current behavior is by design. If fields in the MongoDB document can be null, then your model must adopt to that by using wrapper types instead of primitives.

@mp911de mp911de closed this as not planned Won't fix, can't repro, duplicate, stale Mar 11, 2024
@mp911de mp911de added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged labels Mar 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

No branches or pull requests

3 participants