You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TL;DR: When using combination of Kotlin and R2dbc, interface-based and class-based projection does not work as described in documentation.
Spring Data Version: 3.2.0
Example:
@Table("user")
@Immutable
data classUserEntity(
@Id
valid:Long = 0L,
valname:String,
valloginId:String,
)
interfaceUserProjection {
val id:Longval name:String
}
data classUserDto(
valid:Long,
valname:String,
)
interfaceUserRepository : CoroutineCrudRepository<UserEntity, Long> {
suspendfunfindByLoginId(loginId:String): List<UserDto> // (1) this causes startup failure
suspendfungetByLoginId(loginId:String): List<UserProjection> // (2) this throws runtime exception
}
For (1), the whole application fails to start with exception:
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.lang.Object my.package.UserRepository.findByLoginId(java.lang.String,kotlin.coroutines.Continuation); Reason: Failed to create query for method public abstract java.lang.Object my.package.UserRepository.findByLoginId(java.lang.String,kotlin.coroutines.Continuation); No property 'loginId' found for type 'UserDto'
at org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:115)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:99)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:88)
at java.base/java.util.Optional.map(Optional.java:260)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:88)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:357)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:279)
at org.springframework.data.util.Lazy.getNullable(Lazy.java:135)
at org.springframework.data.util.Lazy.get(Lazy.java:113)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:285)
at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean.afterPropertiesSet(R2dbcRepositoryFactoryBean.java:159)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771)
... 30 common frames omitted
Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.lang.Object my.package.UserRepository.findByLoginId(java.lang.String,kotlin.coroutines.Continuation); No property 'loginId' found for type 'UserDto'
at org.springframework.data.r2dbc.repository.query.PartTreeR2dbcQuery.<init>(PartTreeR2dbcQuery.java:74)
at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory$R2dbcQueryLookupStrategy.resolveQuery(R2dbcRepositoryFactory.java:179)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:111)
... 42 common frames omitted
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property 'loginId' found for type 'UserDto'
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:90)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:443)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:419)
at org.springframework.data.mapping.PropertyPath.lambda$from$0(PropertyPath.java:372)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:354)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:332)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:81)
at org.springframework.data.repository.query.parser.PartTree$OrPart.lambda$new$0(PartTree.java:259)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:260)
at org.springframework.data.repository.query.parser.PartTree$Predicate.lambda$new$0(PartTree.java:389)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:390)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:103)
at org.springframework.data.r2dbc.repository.query.PartTreeR2dbcQuery.<init>(PartTreeR2dbcQuery.java:70)
... 44 common frames omitted
For (2), exception is like:
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method my.package.UserEntity.<init>, parameter loginId
at my.package.UserEntity.<init>(TestUserRepository.kt)
at my.package.UserEntity.<init>(TestUserRepository.kt:10)
at my.package.UserEntity_Instantiator_n2pr7c.newInstance(Unknown Source)
at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.createInstance(KotlinClassGeneratingEntityInstantiator.java:100)
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:98)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:454)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:348)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:311)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:298)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:294)
at org.springframework.data.r2dbc.core.R2dbcEntityTemplate.lambda$getRowsFetchSpec$13(R2dbcEntityTemplate.java:795)
at io.asyncer.r2dbc.mysql.MySqlResult.lambda$map$1(MySqlResult.java:87)
The text was updated successfully, but these errors were encountered:
mp911de
changed the title
Projection failure when using r2dbc with entities in Kotlin with non-null fields
Interface projection fails to instantiate data class with non-null constraints
Dec 5, 2023
These are actually two issues, I created #1688 to track the problem with properties not existent in the projection type which is an actual bug.
Up to now, we instantiate the underlying entity type with a smaller set of properties to then apply a projection on top. Due to class design restrictions, especially Kotlin's non-null by default, we should use a different mechanism that doesn't require entity instantiation.
Previously, we instantiated the underlying entity. Now, we either read results directly into the result type or use a Map-backed projection.
Closes#1687
TL;DR: When using combination of Kotlin and R2dbc, interface-based and class-based projection does not work as described in documentation.
Spring Data Version: 3.2.0
Example:
For (1), the whole application fails to start with exception:
For (2), exception is like:
The text was updated successfully, but these errors were encountered: