Search code examples
spring-bootkotlinspring-webfluxspring-data-mongodbspring-data-mongodb-reactive

SpringData MongoDB @TypeAlias ceased to work after upgrade


I'm trying to solve project problems after upgrading from Spring Boot 2.3.1.RELEASE to Spring Boot 2.5.0 (doesn't work either for 2.4.0+) with @TypeAlias seem to be ignored.

I use Kotlin and reactive manner to achieve this. I got set basePackages to com.example.ajax for @EntityScan, @SpringBootApplication and @EnableReactiveMongoRepositories.

Here is example what I'm trying to achieve and it worked back in 2.3.1 (don't mind the structure):

sealed class ContactDBO

@TypeAlias("personalContact")
data class PersonalContactDBO(
    @Field("name") val name: String
) : ContactDBO()

@TypeAlias("organizationContact")
data class OrganizationContactDBO(
    @Field("identifier") val identifier: Long
) : ContactDBO()

@Document(collection = "contacts")
@TypeAlias("contacts")
data class ContactsDBO(

    @Id
    @Field("id")
    val managerId: UUID,

    @Field("managedContact")
    val contact: ContactDBO
)

and when i use find from repository (which is custom and based on reactiveMongoTemplate), this exception pop-ups:

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.example.ajax.ContactDBO using constructor fun <init>(): com.example.ajax.ContactDBO with arguments
        at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:79)
        Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.MonoFlatMap] :
        reactor.core.publisher.Mono.flatMap(Mono.java:2859)
        org.springframework.data.mongodb.core.ReactiveMongoTemplate.lambda$executeFindOneInternal$88(ReactiveMongoTemplate.java:2757)
Error has been observed at the following site(s):
        |_           Mono.flatMap ⇢ at org.springframework.data.mongodb.core.ReactiveMongoTemplate.lambda$executeFindOneInternal$88(ReactiveMongoTemplate.java:2757)
        |_           Mono.flatMap ⇢ at org.springframework.data.mongodb.core.ReactiveMongoTemplate.createMono(ReactiveMongoTemplate.java:649)
        |_        Mono.onErrorMap ⇢ at org.springframework.data.mongodb.core.ReactiveMongoTemplate.createMono(ReactiveMongoTemplate.java:650)
        |_     Mono.switchIfEmpty ⇢ at reactor.kotlin.core.publisher.MonoExtensionsKt.switchIfEmpty(MonoExtensions.kt:138)
...
Stack trace:
                at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:79)
                at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:89)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:369)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readDocument(MappingMongoConverter.java:342)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter$ConversionContext.convert(MappingMongoConverter.java:1916)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1641)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter$AssociationAwareMongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1690)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter$AssociationAwareMongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1653)
                at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:74)
                at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:53)
                at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.extractInvocationArguments(KotlinClassGeneratingEntityInstantiator.java:228)
                at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.createInstance(KotlinClassGeneratingEntityInstantiator.java:202)
                at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:89)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:369)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readDocument(MappingMongoConverter.java:342)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:278)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:274)
                at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:102)
                at org.springframework.data.mongodb.core.ReactiveMongoTemplate$ReadDocumentCallback.doWith(ReactiveMongoTemplate.java:3155)
                at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
                at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
                at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
                at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:160)
                at com.mongodb.reactivestreams.client.internal.BatchCursorPublisher.lambda$first$0(BatchCursorPublisher.java:106)
                at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:171)
                at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
                at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
                at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:160)
                at com.mongodb.reactivestreams.client.internal.MongoOperationPublisher.lambda$sinkToCallback$30(MongoOperationPublisher.java:550)
                at com.mongodb.internal.operation.AsyncQueryBatchCursor.next(AsyncQueryBatchCursor.java:207)
                at com.mongodb.internal.operation.AsyncQueryBatchCursor.next(AsyncQueryBatchCursor.java:146)
                at com.mongodb.reactivestreams.client.internal.BatchCursor.lambda$next$0(BatchCursor.java:35)
                at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:57)
                at reactor.core.publisher.Mono.subscribe(Mono.java:4150)
                at reactor.core.publisher.Mono.subscribeWith(Mono.java:4265)
                at reactor.core.publisher.Mono.subscribe(Mono.java:3982)
                at com.mongodb.reactivestreams.client.internal.BatchCursorPublisher.lambda$first$1(BatchCursorPublisher.java:109)
                at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:57)
                at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
                at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
                at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:127)
                at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
                at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
                at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
                at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:160)
                at com.mongodb.reactivestreams.client.internal.MongoOperationPublisher.lambda$sinkToCallback$30(MongoOperationPublisher.java:550)
                at com.mongodb.reactivestreams.client.internal.OperationExecutorImpl.lambda$execute$2(OperationExecutorImpl.java:73)
                at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
                at com.mongodb.internal.operation.FindOperation$3.onResult(FindOperation.java:755)
                at com.mongodb.internal.operation.OperationHelper$ReferenceCountedReleasingWrappedCallback.onResult(OperationHelper.java:532)
                at com.mongodb.internal.operation.CommandOperationHelper$10.onResult(CommandOperationHelper.java:483)
                at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
                at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor$2.onResult(DefaultServer.java:286)
                at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
                at com.mongodb.internal.connection.CommandProtocolImpl$1.onResult(CommandProtocolImpl.java:84)
                at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection$2.onResult(DefaultConnectionPool.java:530)
                at com.mongodb.internal.connection.UsageTrackingInternalConnection$2.onResult(UsageTrackingInternalConnection.java:142)
                at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
                at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:462)
                at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:439)
                at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:744)
                at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:711)
                at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:581)
                at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:578)
                at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:322)
                at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:269)
                at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:578)
                at com.mongodb.internal.connection.InternalStreamConnection.access$1100(InternalStreamConnection.java:78)
                at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:701)
                at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:686)
                at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:581)
                at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:578)
                at com.mongodb.connection.netty.NettyStream.readAsync(NettyStream.java:322)
                at com.mongodb.connection.netty.NettyStream.handleReadResponse(NettyStream.java:350)
                at com.mongodb.connection.netty.NettyStream.access$1200(NettyStream.java:104)
                at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:409)
                at com.mongodb.connection.netty.NettyStream$InboundBufferHandler.channelRead0(NettyStream.java:406)
                at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
                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.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
                at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
                at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
                at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
                at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
                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)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.ajax.ContactDBO]: Is it an abstract class?; nested exception is java.lang.InstantiationException
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:216)
        at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:77)
        at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:89)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:369)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readDocument(MappingMongoConverter.java:342)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$ConversionContext.convert(MappingMongoConverter.java:1916)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1641)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$AssociationAwareMongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1690)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$AssociationAwareMongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1653)
        at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:74)
        at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:53)
        at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.extractInvocationArguments(KotlinClassGeneratingEntityInstantiator.java:228)
        at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.createInstance(KotlinClassGeneratingEntityInstantiator.java:202)
        at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:89)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:369)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readDocument(MappingMongoConverter.java:342)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:278)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:274)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:102)
        at org.springframework.data.mongodb.core.ReactiveMongoTemplate$ReadDocumentCallback.doWith(ReactiveMongoTemplate.java:3155)
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:387)
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815)
        at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:387)
        at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:160)
        at com.mongodb.reactivestreams.client.internal.BatchCursorPublisher.lambda$first$0(BatchCursorPublisher.java:106)
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:171)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:387)
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:387)
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:387)

Solution

  • Looks like annotation @Document fixes it.

    @Document
    @TypeAlias("personalContact")
    data class PersonalContactDBO(
        @Field("name") val name: String
    ) : ContactDBO()
    
    @Document
    @TypeAlias("organizationContact")
    data class OrganizationContactDBO(
        @Field("identifier") val identifier: Long
    ) : ContactDBO()