infobip-spring-data-querydsl
infobip-spring-data-querydsl copied to clipboard
someway to define my own repository
Thanks for your amazing project, I feels exceptionally smooth when using r2dbc and querydsl, so I strongly recommend it to my colleagues. However, I have a small question I'd like to ask you.
I want to extend the origin Repository to implement my own Repository, such as ReactivePagingRepository below.
package com.it.gm.cube.app.base
import com.it.gm.cube.bdpc.common.PageResult
import com.it.gm.cube.bdpc.common.PageVo
import com.querydsl.core.types.OrderSpecifier
import com.querydsl.core.types.Predicate
import com.querydsl.sql.RelationalPathBase
import org.springframework.data.repository.NoRepositoryBean
import org.springframework.data.repository.Repository
import reactor.core.publisher.Mono
@NoRepositoryBean
interface ReactivePagingRepository<T, ID>: Repository<T, ID> {
fun <T> simplePaging(
pageVo: PageVo,
count: Long,
table: RelationalPathBase<T>,
predication: Predicate,
orderBy: OrderSpecifier<String>
): Mono<PageResult<T>>
}
And Then implement the interface with
package com.it.gm.cube.app.base
import com.infobip.spring.data.r2dbc.QuerydslR2dbcFragment
import com.it.gm.cube.bdpc.common.PageResult
import com.it.gm.cube.bdpc.common.PageVo
import com.it.gm.cube.bdpc.common.PagingUtil
import com.querydsl.core.types.OrderSpecifier
import com.querydsl.core.types.Predicate
import com.querydsl.sql.RelationalPathBase
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono
@Component
class ReactivePagingRepositoryBean<T, ID>(private val context: ApplicationContext) :
ReactivePagingRepository<T, ID> {
override fun <T> simplePaging(
pageVo: PageVo,
count: Long,
table: RelationalPathBase<T>,
predication: Predicate,
orderBy: OrderSpecifier<String>
): Mono<PageResult<T>> {
val bean = context.getBean(QuerydslR2dbcFragment::class.java)
return if (count == 0L)
Mono.just(PageResult<T>(0, listOf<T>(), 1))
else {
val pagingInfo = PagingUtil.limitOffset(pageVo, count)
bean.query { query ->
query.select(table).from(table).where(predication)
.orderBy(orderBy)
.limit(pagingInfo.limit).offset(pagingInfo.offset)
}.all().collectList().map { PageResult<T>(count, it as List<T>, pagingInfo.currentPage) }
}
}
}
Finally, I use it like this
@Configuration
@EnableR2dbcRepositories(repositoryBaseClass = ReactivePagingRepositoryBean::class)
class DbConfiguration {
private val log by LoggerDelegate()
@Bean
fun sqlTemplates(): SQLTemplates {
return APostgreSQLTemplates()
}
}
@NoRepositoryBean
interface QuerydslRepository<T, ID> : ReactiveSortingRepository<T, ID>, ReactiveCrudRepository<T, ID>,
ReactiveQuerydslPredicateExecutor<T>, ReactivePagingRepository<T, ID>, QuerydslR2dbcFragment<T>
@Configuration
@EnableR2dbcRepositories(repositoryBaseClass = ReactivePagingRepositoryBean::class)
class DbConfiguration {}
interface ApiTreeRepository: QuerydslRepository<ApiTree, Long>
But it raise exception whrn project start.
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property 'simplePaging' found for type 'ApiTree'
there is the project dependency I use -- springboot3.3.3 and
implementation("org.postgresql:r2dbc-postgresql:1.0.5.RELEASE")
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
implementation("com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:9.0.7")
compileOnly("com.infobip:infobip-spring-data-jdbc-annotation-processor:9.0.7")
kapt("com.infobip:infobip-spring-data-jdbc-annotation-processor:9.0.7")
Is there Anyway to achieve this feature? Please tell me, thanks a lot~
Hi, thank you for your kind words. I'd suggest using the fragment (custom repository approach) - https://docs.spring.io/spring-data/jpa/reference/repositories/custom-implementations.html
public interface ReactivePagingRepository<T> {
Mono<T> simplePaging(String string);
}
import org.springframework.context.annotation.Lazy;
import reactor.core.publisher.Mono;
public class ReactivePagingRepositoryImpl<T> implements ReactivePagingRepository<T> {
private final QuerydslR2dbcFragment querydslR2dbcFragment;
public ReactivePagingRepositoryImpl(@Lazy QuerydslR2dbcFragment querydslR2dbcFragment) {
this.querydslR2dbcFragment = querydslR2dbcFragment;
}
@Override
public Mono<T> simplePaging(... parameters) {
... implementation
}
}
This is implementation side, on use side you need to do something like
public interface PersonRepository extends QuerydslR2dbcRepository<Person, Long>, ReactivePagingRepository<Person> {
}
You can of course introduce another abstract interface that extends QuerydslR2dbcRepository<T, ID>, ReactivePagingRepository<T> like QuerydslR2dbcRepository does so your concrete repositories doesn't have to extend both but this approach is arbitrary. To keep the repository implementation clean I'd suggest keeping the repository hierarchies as separate as possible.
it doesn't work for me, the same exception info raised
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cubeTagFactoryController' defined in file [D:\Project\datacube-platform-bdpc\build\classes\kotlin\main\com\it\gm\cube\bdpc\cube\CubeTagFactoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'tagFactoryService' defined in file [D:\Project\datacube-platform-bdpc\build\classes\kotlin\main\com\it\gm\cube\bdpc\cube\service\TagFactoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'tagFactoryRepository' defined in com.it.gm.cube.bdpc.cube.repository.TagFactoryRepository defined in @EnableR2dbcRepositories declared on QuerydslR2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1212) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.12.jar:6.1.12]
.......
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tagFactoryService' defined in file [D:\Project\datacube-platform-bdpc\build\classes\kotlin\main\com\it\gm\cube\bdpc\cube\service\TagFactoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'tagFactoryRepository' defined in com.it.gm.cube.bdpc.cube.repository.TagFactoryRepository defined in @EnableR2dbcRepositories declared on QuerydslR2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1212) ~[spring-beans-6.1.12.jar:6.1.12]
........ 19 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tagFactoryRepository' defined in com.it.gm.cube.bdpc.cube.repository.TagFactoryRepository defined in @EnableR2dbcRepositories declared on QuerydslR2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.12.jar:6.1.12]
....... 19 more
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
at org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:119) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:103) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:92) ~[spring-data-commons-3.3.3.jar:3.3.3]
at java.base/java.util.Optional.map(Optional.java:260) ~[?:?]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:92) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:357) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:286) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:135) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.util.Lazy.get(Lazy.java:113) ~[spring-data-commons-3.3.3.jar:3.3.3]
... 19 more
Check out https://github.com/infobip/infobip-spring-data-querydsl/blob/issue-105-example/infobip-spring-data-r2dbc-custom-fragment/src/test/java/com/infobip/test/QuerydslR2dbcRepositoryTest.java It should fail with https://github.com/infobip/infobip-spring-data-querydsl/blob/issue-105-example/infobip-spring-data-r2dbc-custom-fragment/src/test/java/com/infobip/test/ReactivePagingRepositoryImpl.java#L17 (you can put a breakpoint there and debug).