Git Product home page Git Product logo

infobip / infobip-spring-data-querydsl Goto Github PK

View Code? Open in Web Editor NEW
264.0 17.0 53.0 739 KB

Infobip Spring Data Querydsl provides new functionality that enables the user to leverage the full power of Querydsl API on top of Spring Data repository infrastructure.

License: Apache License 2.0

Java 98.75% TSQL 0.42% Kotlin 0.82%
spring-data querydsl jpa spring-data-jpa java spring-data-jdbc jdbc spring-data-r2dbc r2dbc

infobip-spring-data-querydsl's Introduction

Infobip Spring Data Querydsl

Maven Central Coverage Status Known Vulnerabilities

Infobip Spring Data Querydsl provides new functionality that enables the user to leverage the full power of Querydsl API on top of Spring Data repository infrastructure.

Contents

  1. Changelog
  2. Note on general usage
  3. JDBC module:
  4. R2DBC module:
  5. JPA module:
  6. Annotation processor
  7. Further reading
  8. Running tests
  9. Contributing
  10. License

Changelog

For changes check the changelog.

Note on general usage

For the sake of brevity, all examples use repository methods directly.

In production code persistence layer (SQL) shouldn't leak to service layer. See this answer by Oliver Drotbohm (Spring Data Project Lead @ Pivotal) on how to approach encapsulating persistence logic.

JDBC module:

Requirements:

  • Java 17 with parameter names preserved in byte code (used to map columns to constructor parameters)
  • Spring Data JDBC
  • entities must have an all argument constructor (@AllArgsConstructor), can have others as well
  • entity class and all argument constructor must be public (limitation of Querydsl)

Setup:

  1. Dependency:
<dependency>
   <groupId>com.infobip</groupId>
   <artifactId>infobip-spring-data-jdbc-querydsl-boot-starter</artifactId>
   <version>${infobip-spring-data-jdbc-querydsl.version}</version>
</dependency>
  1. Refactor repository interfaces to either use new base repository or fragments approach:
  • new base repository approach:
interface TRepository extends QuerydslJdbcRepository<T, ID> {
}
  • fragments:
interface TRepository extends PagingAndSortingRepository<T, ID>, QuerydslPredicateExecutor<T>, QuerydslJdbcFragment<T> {
}
  1. Done

Features and examples:

All examples have corresponding tests in the project and can be found here.

Inner Join:

Inner join example:

List<Person> actual = repository.query(query -> query
        .select(repository.entityProjection())
        .from(person)
        .innerJoin(personSettings)
        .on(person.id.eq(personSettings.personId))
        .where(personSettings.id.eq(johnDoeSettings.getId()))
        .fetch());
);

Projections

For examples how to construct projections refer to the official documentation - section result handling.

Here is an example that uses constructor:

public record PersonProjection(
    String firstName,
    String lastName
) {

}
...

List<PersonProjection> actual = repository.query(query -> query
        .select(Projections.constructor(PersonProjection.class, person.firstName,
                                        person.lastName))
        .from(person)
        .fetch());

Query

Optional<Person> actual = repository.queryOne(query -> query
        .select(repository.entityProjection())
        .from(person)
        .where(person.firstName.in("John", "Jane"))
        .orderBy(person.firstName.asc(), person.lastName.asc())
        .limit(1)
        .offset(1));
List<Person> actual = repository.queryMany(query -> query
        .select(repository.entityProjection())
        .from(person)
        .where(person.firstName.in("John", "Jane"))
        .orderBy(person.firstName.asc(), person.lastName.asc())
        .limit(1)
        .offset(1));

Update

repository.update(query -> query
        .set(person.firstName, "John")
        .where(person.firstName.eq("Johny"))
        .execute());

Delete

long numberOfAffectedRows = repository.deleteWhere(person.firstName.like("John%"));

Transactional support

Queries execution is always done inside the repository implementation (loan pattern) in a transaction so transactions don't have to be handled manually (like they do if you are manually managing SQLQuery and other Querydsl constructs).

Embedded support

Entity fields marked with @org.springframework.data.relational.core.mapping.Embedded are inlined in Q classes:

Model:

@Table("Person")
public record PersonWithEmbeddedFirstAndLastName(

        @With
        @Id
        Long id,

        @Embedded(onEmpty = Embedded.OnEmpty.USE_EMPTY)
        FirstAndLastName firstAndLastName
) {
    
}
public record FirstAndLastName(
        String firstName,
        String lastName
) {

}

Query (note the missing .personWithEmbeddedFirstAndLastName field in Q instance):

repository.findAll(personWithEmbeddedFirstAndLastName.firstName.in("John", "Johny"));

@MappedCollection support

Model:

public record Student(
        @Id
        Long id,

        String name,

        @MappedCollection(idColumn = "StudentId", keyColumn = "CourseId")
        Set<StudentCourse> courses
) {

   void addItem(Course course) {
      var studentCourse = new StudentCourse(null, AggregateReference.to(course.id()), null);
      courses.add(studentCourse);
   }

}
public record Course(
        @Id
        Long id,
        String name
) {

}
public record StudentCourse(
        @Id
        Long id,

        AggregateReference<Course, Long> courseId,

        Long studentId
) {

}

Query:

List<Student> actual = studentRepository.query(query -> query.select(studentRepository.entityProjection())
                                                             .from(student)
                                                             .innerJoin(studentCourse)
                                                             .on(student.id.eq(studentCourse.studentId))
                                                             .fetch());

Streaming

streamAll is a new method added to repository for more convenient use.

@Transactional
public void transactionalAnnotatedMethodRequiredForConsumingStream() {
   try (Stream<Person> stream = repository.streamAll()) {
      // use stream
   }
}

Extension:

To create a custom base repository interface you'll need to create:

  • custom base interface
  • custom annotation for enabling
  • custom factory bean class and potentially factory class depending on requirements

Take a look at extension package in tests as an example on how this can be achieved.

R2DBC module:

Requirements:

  • Java 17 with parameter names preserved in byte code (used to map columns to constructor parameters)
  • Spring Data R2DBC
  • entities must have an all argument constructor (@AllArgsConstructor), can have others as well
  • entity class and all argument constructor must be public (limitation of Querydsl)
  • if you're not using Flyway, you need to provide a SQLTemplates bean

Setup:

  1. Dependency:
<dependency>
   <groupId>com.infobip</groupId>
   <artifactId>infobip-spring-data-r2dbc-querydsl-boot-starter</artifactId>
   <version>${infobip-spring-data-r2dbc-querydsl.version}</version>
</dependency>
  1. Refactor repository interfaces to either use new base repository or fragments approach:
  • new base repository approach:
interface TRepository extends QuerydslR2dbcRepository<T, ID> {
}
  • fragments:
interface TRepository extends ReactiveSortingRepository<T, ID>, ReactiveQuerydslPredicateExecutor<T>, QuerydslR2dbcFragment<T> {
}
  1. Done

Features and examples:

All examples have corresponding tests in the project and can be found here.

Inner Join:

Inner join example:

Flux<Person> actual = repository.query(query -> query.select(repository.entityProjection())
                                                          .from(person)
                                                          .innerJoin(personSettings)
                                                          .on(person.id.eq(personSettings.personId))
                                                          .where(personSettings.id.eq(johnDoeSettings.getId())))
                                     .all();

Projections

For examples how to construct projections refer to the official documentation - section result handling.

Here is an example that uses constructor:

public record PersonProjection(
    String firstName,
    String lastName
) {

}
...

Flux<PersonProjection> actual = repository.query(query -> query
        .select(constructor(PersonProjection.class, person.firstName, person.lastName))
        .from(person))
                                          .all();

Query

Flux<Person> actual = repository.query(query -> query.select(repository.entityProjection())
                                                     .from(person)
                                                     .where(person.firstName.in("John", "Jane"))
                                                     .orderBy(person.firstName.asc(),
                                                              person.lastName.asc())
                                                     .limit(1)
                                                     .offset(1))
                                .all();

Update

Mono<Integer> numberOfAffectedRows = repository.update(query -> query.set(person.firstName, "John")
                                                                     .where(person.firstName.eq("Johny")));

Delete

Mono<Integer> numberOfAffectedRows = repository.deleteWhere(person.firstName.like("John%"));

Transactional support

Queries execution is always done inside the repository implementation (loan pattern) in a transaction so transactions don't have to be handled manually (like they do if you are manually managing SQLQuery and other Querydsl constructs).

Extension:

To create a custom base repository interface you'll need to create:

  • custom base interface
  • custom annotation for enabling
  • custom factory bean class and potentially factory class depending on requirements

Take a look at extension package in tests as an example on how this can be achieved.

JPA module:

Requirements:

  • Java 17
  • Spring Data JPA

Setup:

  1. Dependency:
<dependency>
   <groupId>com.infobip</groupId>
   <artifactId>infobip-spring-data-jpa-querydsl-boot-starter</artifactId>
   <version>${infobip-spring-data-jpa-querydsl.version}</version>
</dependency>

As this project depends on querydsl-apt with jpa classifier you don't need to set up explicit Maven build phase for Q classes generation. For building Q classes without Maven, make sure your IDE has Annotation processing enabled.

  1. Refactor repository interfaces to either use new base repository or fragments approach:
  • new base repository approach:
interface TRepository extends ExtendedQueryDslJpaRepository<T, ID> {
}
  • fragments:
interface TRepository extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T>, QuerydslJpaFragment<T> {
}
  1. Done

If you need other features from @EnableJpaRepositories you can use:

@EnableJpaRepositories(repositoryFactoryBeanClass = ExtendedQuerydslJpaRepositoryFactoryBean.class)

Features and examples:

All examples have corresponding tests in the project and can be found here.

Native queries with Querydsl:

Example which uses union clause (unions aren't available in JPA):

List<Person> actual = repository.jpaSqlQuery(query -> query
        .union(
                repository.jpaSqlSubQuery(subQuery ->
                                                  subQuery.select(person)
                                                          .from(person)
                                                          .where(person.firstName.like("John"))),
                repository.jpaSqlSubQuery(subQuery ->
                                                  subQuery.select(person)
                                                          .from(person)
                                                          .where(person.firstName.like("Jan%")))
        )
        .orderBy(person.firstName.asc(), person.lastName.asc())
        .fetch()
);

Projections

For examples how to construct projections refer to the official documentation - section result handling.

Here is an example that uses constructor:

public record PersonProjection(
    String firstName,
    String lastName
) {

}
...
 
List<PersonProjection> actual = repository.query(query -> query
                                          .select(Projections.constructor(PersonProjection.class, person.firstName, person.lastName))
                                          .from(person)
                                          .fetch());

Query

Query exposes full API of JPAQuery (QueryDslPredicateExecutor only exposes where clause (Predicate) and order clause (OrderSpecifier)).

This along with Querydsl 4 API improvement can lead to code that looks more like regular SQL:

List<Person> actual = repository.query(query -> query
        .select(person)
        .from(person)
        .where(person.firstName.in("John", "Jane"))
        .orderBy(person.firstName.asc(), person.lastName.asc())
        .limit(1)
        .offset(1)
        .fetch());

Update

repository.update(query -> query
        .set(person.firstName, "John")
        .where(person.firstName.eq("Johny"))
        .execute());

Delete

long numberOfAffectedRows = repository.deleteWhere(person.firstName.like("John%"));

List instead of Iterable return type

QueryDslPredicateExecutor#findAll methods return Iterable which can be cumbersome to use. Those methods were overridden and now return a List which is easier to use and is easier to convert to Stream.

Transactional support

Query execution is always done inside the repository implementation (loan pattern) in a transaction so transactions don't have to be handled manually (like they do if you are manually managing JPAQuery and other Querydsl constructs).

Stored procedure builder

JPA support for stored procedures is quite cumbersome and it also requires a reference to EntityManager which leads to code like this:

@PersistenceContext
private EntityManager entityManager
...
 
@SuppressWarnings("unchecked")
public List<Person> delete(Person personToDelete) {
    return (List<Person>) entityManager
            .createStoredProcedureQuery("Person_Delete")
            .registerStoredProcedureParameter("FirstName", String.class, ParameterMode.IN)
            .registerStoredProcedureParameter("LastName", String.class, ParameterMode.IN)
            .setParameter("FirstName", personToDelete.getFirstName())
            .setParameter("LastName", personToDelete.getLastName())
            .getResultList(); // returns untyped List => unchecked
}

For this case, executeStoredProcedure method was added which supports Q class attributes:

public List<Person> delete(Person personToDelete) {
    return repository.executeStoredProcedure(
            "Person_Delete",
            builder -> builder.addInParameter(person.firstName, personToDelete.getFirstName())
                              .addInParameter(person.lastName, personToDelete.getLastName())
                              .getResultList());
}

Streaming

streamAll is a new method added to repository for more convenient use.

@Transactional
public void transactionalAnnotatedMethodRequiredForConsumingStream() {
   try (Stream<Person> stream = repository.streamAll()) {
      // use stream
   }
}

Extension:

To create a custom base repository interface you'll need to create:

  • custom base interface
  • custom annotation for enabling
  • custom factory bean class and potentially factory class depending on requirements

Take a look at extension package in tests as an example on how this can be achieved.

Annotation processor

Annotation processor infobip-spring-data-jdbc-annotation-processor is used by R2DBC and JDBC modules to generate Querydsl Q classes. Without annotation processor this process can be quite cumbersome as connecting to database would be required during the build phase.

Annotation processor generates Q classes for all classes that have @Id annotated fields. Reason why @Id is used and not some custom annotation is for simplicity of use and implementation and because @Id is required by Spring Data JDBC:

Spring Data JDBC uses the ID to identify entities. The ID of an entity must be annotated with Spring Data’s @Id annotation.

Current implementation of Annotation Processor uses pascal casing based naming strategy for table and column names.

To customize this behavior across whole project add following annotation to one of your classes:

@ProjectTableCaseFormat(CaseFormat.LOWER_UNDERSCORE)
@ProjectColumnCaseFormat(CaseFormat.LOWER_UNDERSCORE)
public class SomeClassOnCompilationPath {
...
}

SomeClassOnCompilationPath can be any class that is being compiled in the project.

Note that for customizing single table/column mapping Table and Column can be used.

If this behavior needs to be changed across multiple projects, or you simply wish to customize annotation processor following steps can be taken:

  1. create a new Maven module (or a Maven project if you want to reuse across multiple projects)
  2. add dependency to infobip-spring-data-jdbc-annotation-processor-common
  3. create implementation of com.querydsl.sql.codegen.NamingStrategy
  4. create annotation processor that extends the base one:
@AutoService(Processor.class)
public class CustomSpringDataJdbcAnnotationProcessor extends SpringDataJdbcAnnotationProcessorBase {

    public CustomSpringDataJdbcAnnotationProcessor() {
        super(CustomNamingStrategy.class);
    }
}
  1. in module (or project) that needs to use this new processor exclude the default annotation processor dependency and include your own:
<dependency>
	<groupId>com.infobip</groupId>
    <!-- infobip-spring-data-jdbc-querydsl-boot-starter is used as an example here, same pattern applies for other modules --> 
	<artifactId>infobip-spring-data-jdbc-querydsl-boot-starter</artifactId>
	<version>${infobip-spring-data-jdbc-querydsl-boot-starter.version}</version>
	<exclusions>
		<exclusion>
			<groupId>com.infobip</groupId>
			<artifactId>infobip-spring-data-jdbc-annotation-processor</artifactId>
		</exclusion>
	</exclusions>
</dependency>

<!-- include dependency to custom annotation processor -->

infobip-spring-data-jdbc-annotation-processor can be used as an example codebase for custom annotation processor. It includes tests that can be used for custom annotation processor as well.

In case you want to manually generate Q classes you can still exclude infobip-spring-data-jdbc-annotation-processor and do the process manually (e.g. like this).

Further reading

Running tests

To run tests you need to have docker installed. Containers are automatically started using testcontainers.

Contributing

If you have an idea for a new feature or want to report a bug please use the issue tracker.

Pull requests are welcome!

License

This library is licensed under the Apache License, Version 2.0.

infobip-spring-data-querydsl's People

Contributors

dependabot[bot] avatar dirkluijk avatar lpandzic avatar mscheong01 avatar sallgoood avatar snyk-bot avatar xeounxzxu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

infobip-spring-data-querydsl's Issues

Spring Data JDBC: support for `Embedded` entities?

Are embedded entities for Spring Data JDBC supported? https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.entity-persistence.embedded-entities

I don't see it mentioned anywhere, but it doesn't seem to work for me, using Kotlin classes:

data class SomeEntity @PersistenceConstructor constructor(
        @Id @JvmField
        var id: UUID? = null,

        // ...

        @Embedded(onEmpty = Embedded.OnEmpty.USE_EMPTY)
        val event: AuditEvent,

        // ...
)

data class AuditEvent @PersistenceConstructor constructor(
        val eventType: String,
        val eventId: String,
        val auditDateTime: OffsetDateTime = now()
)

Generated class:

/**
 * QSomeEntity is a Querydsl query type for QSomeEntity
 */
@Generated("com.querydsl.sql.codegen.MetaDataSerializer")
public class QSomeEntity extends com.querydsl.sql.RelationalPathBase<QSomeEntity> {

    private static final long serialVersionUID = -1427592166;
    public static final QSomeEntity someEntity = new QSomeEntity("SomeEntity");

    public final ComparablePath<java.util.UUID> id = createComparable("id", java.util.UUID.class);

    // ...

    public final SimplePath<AuditEvent> event = createSimple("event", AuditEvent.class);

    // ...
}

The problem is that it tries to query for the column event which does not exists. It should query for event_type, event_id and audit_date_time instead.

I'm using version 5.4.2 with Spring Data JDBC.

is there a way to make `SpringDataJdbcAnnotationProcessor` generate superType ?

I try to create a super class for all domain, like a BaseDomain class including auditing columns. sample is here (on branch how-to-make-BaseDomain-work, run mvn clean test get errors).

Because r2dbc does not have annotations like MappedSuperclass in JPA, I tried to use com.querydsl.core.annotations.QuerySupertype annotation and com.querydsl.apt.QuerydslAnnotationProcessor processor, but failed.

@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QUser extends EntityPathBase<User> {
// ...
}
Caused by: java.lang.ClassCastException: class com.example.demo.domain.QUser cannot be cast to class com.querydsl.sql.RelationalPathBase (com.example.demo.domain.QUser and com.querydsl.sql.RelationalPathBase are in unnamed module of loader 'app')

How to work with transactions? Found some strange behavior.

I'm using spring-boot-starter-data-jdbc and infobip-spring-data-jdbc-querydsl-boot-starter(5.4.2) together.
In my tests with org.springframework.transaction.annotation.Transactional annotation I have the following code:

@Test
@Transactional
void test() {
    repository.save(ReportList.builder().userName("username").build());

    var reports = repository.query(query -> query
            .select(entityProjection())
            .from(QReportList.reportList)
            .fetch());
}

Expected result: variable reports is not empty
Actual result: variable reports is empty

If I remove @Transactional (or use default findAll method from QuerydslJdbcRepository) it starts to return results.
Am I doing something wrong?

try to integrate r2dbc and querydsl and h2

Hi @lpandzic, I created an example here (note the branch is infobip-spring-data-r2dbc-querydsl-h2-not-work), Just run UserRepositoryTest junit test, and then can see exceptions liks below:

13:49:20.616 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'r2dbcMappingContext' via factory method to bean named 'r2dbcCustomConversions'
13:49:20.638 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'r2dbcConverter' via factory method to bean named 'r2dbcMappingContext'
13:49:20.638 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'r2dbcConverter' via factory method to bean named 'r2dbcCustomConversions'
13:49:20.666 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'reactiveDataAccessStrategy' via factory method to bean named 'r2dbcConverter'
13:49:20.682 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'r2dbcEntityTemplate' via factory method to bean named 'r2dbcDatabaseClient'
13:49:20.682 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'r2dbcEntityTemplate' via factory method to bean named 'reactiveDataAccessStrategy'
13:49:20.729 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userRepository'
13:49:20.820 [main] DEBUG org.springframework.data.repository.core.support.RepositoryFactorySupport - Initializing repository instance for com.example.demo.repository.UserRepository…
13:49:20.837 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository' defined in com.example.demo.repository.UserRepository defined in @EnableR2dbcRepositories declared on H2ConnectionConfig: Invocation of init method failed; nested exception is org.springframework.data.repository.core.support.UnsupportedFragmentException: Repository com.example.demo.repository.UserRepository implements org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor but R2dbcRepositoryFactory does not support Reactive Querydsl!
13:49:20.840 [main] ERROR org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@53dbe163] to prepare test instance [com.example.demo.repository.UserRepositoryTest@16c63f5]
java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$8(ClassBasedTestDescriptor.java:363)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:368)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$9(ClassBasedTestDescriptor.java:363)
	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.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	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.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:362)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:283)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:282)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:272)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:271)
	at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:102)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:101)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository' defined in com.example.demo.repository.UserRepository defined in @EnableR2dbcRepositories declared on H2ConnectionConfig: Invocation of init method failed; nested exception is org.springframework.data.repository.core.support.UnsupportedFragmentException: Repository com.example.demo.repository.UserRepository implements org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor but R2dbcRepositoryFactory does not support Reactive Querydsl!
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:934)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:127)
	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:275)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
	... 71 common frames omitted
Caused by: org.springframework.data.repository.core.support.UnsupportedFragmentException: Repository com.example.demo.repository.UserRepository implements org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor but R2dbcRepositoryFactory does not support Reactive Querydsl!
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$RepositoryValidator.validate(RepositoryFactorySupport.java:819)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.validate(RepositoryFactorySupport.java:522)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:330)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:322)
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:230)
	at org.springframework.data.util.Lazy.get(Lazy.java:114)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:328)
	at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean.afterPropertiesSet(R2dbcRepositoryFactoryBean.java:179)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
	... 86 common frames omitted
13:49:20.853 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@4b3ed2f0 testClass = UserRepositoryTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4fad9bb2 testClass = UserRepositoryTest, locations = '{}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[ImportsContextCustomizer@517d4a0d key = [com.example.demo.H2ConnectionConfig]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@c9d0d6, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7a1a14a4, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@63fbfaeb, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@466276d8], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]], class annotated with @DirtiesContext [false] with mode [null].

How to customize projection query in the new version?

In the new version (5.4.0) because
deprecated QuerydslJdbcFragment#query .
replaced by QuerydslJdbcFragment#queryOne and QuerydslJdbcFragment#queryMany,but it cannot customize projection.

And how to customize projection query?
Please help me.

How to apply `Sort` instead of `QSort`

Hi, small question.

I am able to apply sorting using QSort successfully, for example:

import com.bol.foo.QFoo.foo

fooRepository.findAll(
  foo.someField.eq("bar"),
  QPageRequest.of(2, 25, foo.otherField.asc())
)

This works perfect, and it uses the generated mapping from QFoo.foo.

However, when I use Springs default Sort, things get messy:

fooRepository.findAll(
  foo.someField.eq("bar"),
  PageRequest.of(2, 25, Sort.by(Sort.Order.asc("otherField")))
)

In this case, it seems it uses an incorrect database column field otherField instead of other_field (I use the default naming from Spring JDBC).

Note: the reason I want to use the default Sort from Spring is because it integrates better into Spring Web (e.g. automatic argument resolving, configuration, annotating default sorts, etc) and because the QSort from QueryDSL includes a lot of sensitive stuff that get's included in the JSON serialisation (I might want to report that over there).

Test code doesn't run. Please confirm

hi

I ran a test run to test out this wonderful project.

But that test doesn't seem to be running.

In order to test this project, besides Docker, do I need another setting?

Test Run Class

QuerydslR2dbcRepositoryTest.java

Img

스크린샷 2023-01-12 오후 10 42 37

Error Message

org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [final com.infobip.spring.data.r2dbc.PersonRepository repository] in constructor [public com.infobip.spring.data.r2dbc.QuerydslR2dbcRepositoryTest(com.infobip.spring.data.r2dbc.PersonRepository,com.infobip.spring.data.r2dbc.PersonSettingsRepository,com.infobip.spring.data.r2dbc.NoArgsRepository)]: Failed to load ApplicationContext for [MergedContextConfiguration@6056232d testClass = com.infobip.spring.data.r2dbc.QuerydslR2dbcRepositoryTest, locations = [], classes = [com.infobip.spring.data.r2dbc.Main], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@71ba6d4e, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@d86a6f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@7d0b7e3c, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@9da1, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@cb0755b, org.springframework.boot.test.context.SpringBootTestAnnotation@f16ddca2], contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]

	at org.junit.jupiter.engine.execution.ParameterResolutionUtils.resolveParameter(ParameterResolutionUtils.java:159)
	at org.junit.jupiter.engine.execution.ParameterResolutionUtils.resolveParameters(ParameterResolutionUtils.java:103)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:59)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:363)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:310)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:286)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:278)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:277)
	at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$before$2(ClassBasedTestDescriptor.java:203)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:202)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:84)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:148)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.IllegalStateException: Failed to load ApplicationContext for [MergedContextConfiguration@6056232d testClass = com.infobip.spring.data.r2dbc.QuerydslR2dbcRepositoryTest, locations = [], classes = [com.infobip.spring.data.r2dbc.Main], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@71ba6d4e, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@d86a6f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@7d0b7e3c, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@9da1, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@cb0755b, org.springframework.boot.test.context.SpringBootTestAnnotation@f16ddca2], contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:141)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127)
	at org.springframework.test.context.junit.jupiter.SpringExtension.getApplicationContext(SpringExtension.java:283)
	at org.springframework.test.context.junit.jupiter.SpringExtension.resolveParameter(SpringExtension.java:269)
	at org.junit.jupiter.engine.execution.ParameterResolutionUtils.resolveParameter(ParameterResolutionUtils.java:136)
	... 51 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Container startup failed
	at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:345)
	at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:326)
	at com.infobip.testcontainers.InitializerBase.start(InitializerBase.java:38)
	at com.infobip.testcontainers.spring.mssql.MSSQLServerContainerInitializer.initialize(MSSQLServerContainerInitializer.java:39)
	at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:603)
	at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:383)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
	at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47)
	at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1386)
	at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:543)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:183)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
	... 55 more
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
	at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:88)
	at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:338)
	... 70 more
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
	at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:537)
	at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:340)
	at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
	... 71 more
Caused by: java.lang.IllegalStateException: Container exited with code 1
	at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:509)
	... 73 more

No way to specify parameters in @EnableExtendedRepositories annotation

Since @EnableExtendedRepositories now replaces @EnableJpaRepositories, there is no way to specify parameters originally found in EnableJpaRepositories annotation.

@EnableExtendedRepositories should contain parameters like:

  • basePackages
  • repositoryBaseClass
  • transactionManagerRef
  • entityManagerFactoryRef
  • and others.

Or provide any other way of achieving the same goal :)

Gradle 6.x gives errors

When we add the library with Gradle

compile 'com.infobip:infobip-spring-data-jdbc-querydsl:4.0.1-SNAPSHOT'

Could not find querydsl-apt-4.3.1-jpa.jar (com.querydsl:querydsl-apt:4.3.1).
Searched in the following locations:
file:/home/randika/.m2/repository/com/querydsl/querydsl-apt/4.3.1/querydsl-apt-4.3.1-jpa.jar

openjdk version "11.0.8" 2020-07-14 LTS
org.springframework.boot' version '2.3.4.RELEASE'

org.springframework.data.repository.CrudRepository#save IllegalArgumentException

@Configuration
@EnableTransactionManagement
@EnableQuerydslJdbcRepositories
public class JdbcConfig {
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public NamingStrategy namingStrategy() {
        return new NamingStrategy() {
            @Override
            @Nonnull
            public String getColumnName(@Nonnull RelationalPersistentProperty property) {
                Assert.notNull(property, "Property must not be null.");
                return ParsingUtils.reconcatenateCamelCase(property.getName(), "_");
            }
        };
    }
}
@Repository
public interface MiUserRepo extends QuerydslJdbcRepository<MiUser, Long> {

}

Querydsl-sql generated dto

package com.xxx.rd.micat.system.generated.querydsl;

import javax.validation.constraints.Size;
import javax.annotation.processing.Generated;
import javax.validation.constraints.NotNull;
import com.querydsl.sql.Column;
import org.springframework.data.annotation.Id;

/**
 * MiUser is a Querydsl bean type
 */
@Generated("com.querydsl.codegen.BeanSerializer")
public class MiUser {

    public MiUser() {
    }

    public MiUser(Long createdBy, java.sql.Timestamp createdTs, Boolean enabled, String fullName, Long groupId, Long id, String intro, Long lastModifiedBy, java.sql.Timestamp lastModifiedTs, String name, String password, String remark, Long tenantId, String username, Long version) {
        this.createdBy = createdBy;
        this.createdTs = createdTs;
        this.enabled = enabled;
        this.fullName = fullName;
        this.groupId = groupId;
        this.id = id;
        this.intro = intro;
        this.lastModifiedBy = lastModifiedBy;
        this.lastModifiedTs = lastModifiedTs;
        this.name = name;
        this.password = password;
        this.remark = remark;
        this.tenantId = tenantId;
        this.username = username;
        this.version = version;
    }

    @Column("created_by")
    @NotNull
    private Long createdBy;

    @Column("created_ts")
    @NotNull
    private java.sql.Timestamp createdTs;

    @Column("enabled")
    private Boolean enabled;

    @Column("full_name")
    @Size(max=50)
    private String fullName;

    @Column("group_id")
    private Long groupId;

    @Column("id")
    @NotNull
    private Long id;

    @Column("intro")
    @Size(max=200)
    private String intro;

    @Column("last_modified_by")
    private Long lastModifiedBy;

    @Column("last_modified_ts")
    private java.sql.Timestamp lastModifiedTs;

    @Column("name")
    @Size(max=50)
    private String name;

    @Column("password")
    @NotNull
    @Size(max=100)
    private String password;

    @Column("remark")
    @Size(max=200)
    private String remark;

    @Column("tenant_id")
    @NotNull
    private Long tenantId;

    @Column("username")
    @NotNull
    @Size(max=50)
    private String username;

    @Column("version")
    private Long version;

    public Long getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(Long createdBy) {
        this.createdBy = createdBy;
    }

    public java.sql.Timestamp getCreatedTs() {
        return createdTs;
    }

    public void setCreatedTs(java.sql.Timestamp createdTs) {
        this.createdTs = createdTs;
    }

    public Boolean getEnabled() {
        return enabled;
    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public Long getGroupId() {
        return groupId;
    }

    public void setGroupId(Long groupId) {
        this.groupId = groupId;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getIntro() {
        return intro;
    }

    public void setIntro(String intro) {
        this.intro = intro;
    }

    public Long getLastModifiedBy() {
        return lastModifiedBy;
    }

    public void setLastModifiedBy(Long lastModifiedBy) {
        this.lastModifiedBy = lastModifiedBy;
    }

    public java.sql.Timestamp getLastModifiedTs() {
        return lastModifiedTs;
    }

    public void setLastModifiedTs(java.sql.Timestamp lastModifiedTs) {
        this.lastModifiedTs = lastModifiedTs;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public Long getTenantId() {
        return tenantId;
    }

    public void setTenantId(Long tenantId) {
        this.tenantId = tenantId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    @Override
    public String toString() {
         return "createdBy = " + createdBy + ", createdTs = " + createdTs + ", enabled = " + enabled + ", fullName = " + fullName + ", groupId = " + groupId + ", id = " + id + ", intro = " + intro + ", lastModifiedBy = " + lastModifiedBy + ", lastModifiedTs = " + lastModifiedTs + ", name = " + name + ", password = " + password + ", remark = " + remark + ", tenantId = " + tenantId + ", username = " + username + ", version = " + version;
    }

}

DDL:

create table mi_user
(
    id               bigint unsigned auto_increment
        primary key,
    tenant_id        bigint unsigned              not null,
    username         varchar(50)                  not null,
    enabled          bit             default b'0' not null,
    group_id         bigint unsigned              null,
    password         varchar(100)                 not null,
    name             varchar(50)                  null,
    full_name        varchar(50)                  null,
    intro            varchar(200)                 null,
    remark           varchar(200)                 null,
    created_by       bigint unsigned              not null,
    created_ts       timestamp                    not null,
    last_modified_by bigint unsigned              null,
    last_modified_ts timestamp                    null,
    version          bigint unsigned default '0'  not null
);

Test:

@SpringBootTest
@Transactional
@Slf4j
class MicatApplicationTests {

    @Autowired
    private MiUserRepo miUserRepo;

    @Test
    void test() {
        List<MiUser> list = miUserRepo.findAll();
        assertEquals(0, list.size());

        MiUser demoUser = new MiUser();
        demoUser.setUsername("demo");
        demoUser.setPassword("demo");
        demoUser.setEnabled(true);
        demoUser.setTenantId(1L);
        demoUser.setCreatedBy(1L);
        demoUser.setCreatedTs(Timestamp.from(Instant.now()));
        demoUser.setVersion(0L);
        miUserRepo.save(demoUser); // error
    }
}
java.lang.IllegalArgumentException: After saving the identifier must not be null!

	at org.springframework.util.Assert.notNull(Assert.java:201)
	at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:343)
	at org.springframework.data.jdbc.core.JdbcAggregateTemplate.save(JdbcAggregateTemplate.java:150)
	at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.save(SimpleJdbcRepository.java:60)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
	at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529)
	at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:599)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at jdk.proxy2/jdk.proxy2.$Proxy109.save(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at jdk.proxy2/jdk.proxy2.$Proxy109.save(Unknown Source)
	at com.xxx.rd.micat.system.MicatApplicationTests.test(MicatApplicationTests.java:47)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

support complex sql(window functions)

i want to use this to replace mybatis xml SQL, does it support complex SQL,like:

SELECT
*
FROM
(
SELECT
SUM(total) over (
PARTITION BY date,

		IF (`rank` <= 3, `rank`, 4)
		) total,

	IF (`rank` <= 4, 1, 0) flag,
	date,
	id1,
	id2,
	id3,
	one,
	two,
	three,
	`end_point`,
	`rank`
FROM
	(
		SELECT
			total,
			date,
			one,
			`two`,
			`three`,
			`id1`,
			`id2`,
			`id3`,
			`end_point`,
			ROW_NUMBER () over (
				PARTITION BY date
				ORDER BY
					total DESC
			) AS `rank`
		FROM
			(
				SELECT
					sum(VALUE) AS total,
					`date`,
					`one`,
					`two`,
					`three`,
					`id1`,
					`id2`,
					`id3`,
					`end_point`
				FROM
					xx.tableA
				WHERE
					1 = 1
				AND `date` BETWEEN ?
				AND ?
				AND uri =?
				AND line_type =?
				AND (1 = 0 OR b3_id IN(?))
				GROUP BY
					b3_id,
					`date`
			) t
	) t
) t

WHERE
flag = 1
ORDER BY
date ASC,
rank DESC

I can't run the test program.

I can't run the test program, cause I got en error :
import static com.infobip.spring.data.r2dbc.QPerson.person; import static com.infobip.spring.data.r2dbc.QPersonSettings.personSettings;

I can't find these Class in the project, nor in maven rep.

Database Major Version Conditional Questions

The current code for R2dbcSQLTemplatesConfiguration.

@ConditionalOnClass(Flyway.class)
@Configuration
public class R2dbcSQLTemplatesConfiguration {

    @ConditionalOnBean(Flyway.class)
    @Bean
    public SQLTemplates sqlTemplates(Flyway flyway) throws SQLException {
        var jdbcConnectionFactory = new JdbcConnectionFactory(flyway.getConfiguration().getDataSource(),
                                                              flyway.getConfiguration(),
                                                              null);
        var sqlTemplatesRegistry = new SQLTemplatesRegistry();
        var metaData = jdbcConnectionFactory.openConnection().getMetaData();

        var templates = sqlTemplatesRegistry.getTemplates(metaData);

        if (templates instanceof SQLServerTemplates || metaData.getDatabaseMajorVersion() > 11) {
            return new SQLServer2012Templates();
        }

        return templates;
    }

} 

The condition of the if in your code is strange. The two conditions are an OR operation.

  • templates instanceof SQLServerTemplates
  • metaData.getDatabaseMajorVersion() > 11

With these conditions, the SQLServer2012Templates instance is registered as a bean when using Postgres 14.5.
In my opinion, the two conditions should be an AND operation.
please confirm this if condition code.

How to support one-to-many relationship for spring data jdbc

@Table
@Getter
@Builder
@AllArgsConstructor
public class User {
@Id private Long id;
private String username;
@Builder.Default private Set<RoleRef> roles = new HashSet<>();
}

@Table("user_role")
@Getter
@AllArgsConstructor
public class RoleRef {
@Id private Long id;
private AggregateReference<Role, Long> role;
}

@Table
@Getter
@Builder
@AllArgsConstructor
public class Role {
@Id private Long id;
@Column("role_name")
private String roleName;
}

CREATE TABLE user (
id bigint(20) NOT NULL AUTO_INCREMENT,
username varchar(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

CREATE TABLE role (
id bigint(20) NOT NULL AUTO_INCREMENT,
role_name varchar(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

user_role :
CREATE TABLE user_role (
user bigint(20) NOT NULL,
role bigint(20) NOT NULL,
id bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

QUser class has 'roles' field, but table 'user' no Column named 'roles'.
how to use innerJoin Query?

How do with the @Transient attribute

I use r2dbc infobip-spring-data-querydsl. But in my entity I hava attribute with @transient, this attribute is not a table column.
But when I run the select , I get the error.
for example
My entity is as following

@table("customer_order")
@DaTa
@AllArgsConstructor
@NoArgsConstructor

public class OrderPO {
@id
@column("id")
private Long id;
@column("customer_id")
private Long customerId;
@column("customer_name")
private String customerName;
@column("ordr_code")
private String ordrCode;
@column("address")
private String address;
@column("customer_mobile")
private String customerMobile;
@column("total_pirce")
private Float totalPirce;
@column("create_time")
private LocalDateTime createTime;

  @Transient
  private List<OrderItemPO> orderItemList;

  public void create()
  {
      this.createTime=LocalDateTime.now();
  }

}

I run following program

Flux orderPOFlux = orderDao.query(query ->query.
select(orderDao.entityProjection()).
from(qOrderPO).
orderBy(qOrderPO.id.desc()).
where(booleanBuilder).
limit(pageSize).
offset((page-1)*pageSize)).all();

I get error:

Unknown column 'OrderPO.OrderItemList' in 'field list'
Error has been observed at the following site(s):
|_ checkpoint ⇢ SQL "select OrderPO.id, OrderPO.customer_id, OrderPO.customer_name, OrderPO.ordr_code, OrderPO.address, OrderPO.customer_mobile, OrderPO.total_pirce, OrderPO.create_time, OrderPO.OrderItemList
from customer_order OrderPO
where OrderPO.id is not null
order by OrderPO.id desc
limit 1
offset 0" [DatabaseClient]

This error is not happen in JPA version. Can you help me? Thank you

Custom JDBC table names naming strategy

In my Spring Data JDBC project I have custom NamingStrategy (predefined prefix is added to entity name):

private static final String TABLE_NAME_PREFIX = "foo_";

@Bean
    public NamingStrategy namingStrategy() {
        return new NamingStrategy() {

            @Override
            public String getTableName(Class<?> type) {

                Assert.notNull(type, "Type must not be null");
                return TABLE_NAME_PREFIX + ParsingUtils.reconcatenateCamelCase(type.getSimpleName(), "_");
            }
        };
    }

I want to have the same table names generated by AnnotationProcessor in Q-classes.
What is recommended way to adjust it in AnnotationProcessor?

It seems that enough should be:

  1. writing my own ExtendedTypeFactory implementation which extends CustomExtendedTypeFactory and overrides one method: getTableNameEntityType model).
  2. overriding createTypeFactory method of SpringDataJdbcAnnotationProcessorBase and use implementation of ExtendedTypeFactory (created in first step) instead of CustomExtendedTypeFactory

But it turns out it is impossible due to CustomExtendedTypeFactory class visibility issue. What is the reason this class is not an public class?

Parameter 0 of method setReactiveTransactionManager in com.infobip.spring.data.r2dbc.QuerydslR2dbcRepositoryFactoryBean required a bean of type 'org.springframework.transaction.ReactiveTransactionManager' that could not be found.

Hi

I use to implementation("com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:6.2.0")

The project could not be executed due to the following error.

I wonder if you know how to fix it.

thanks

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method setReactiveTransactionManager in com.infobip.spring.data.r2dbc.QuerydslR2dbcRepositoryFactoryBean required a bean of type 'org.springframework.transaction.ReactiveTransactionManager' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.transaction.ReactiveTransactionManager' in your configuration.

this code is kotlin configuration

@Configuration
@EnableR2dbcRepositories(
    basePackages = [
        "com.example.webflux.repository"
    ]
)
class R2dbcDataSourceConfiguration constructor(
    @Qualifier("read.datasource-com.example.webflux.config.ReadDataSourceProperties")
    private val readDataSourceProperties: BaseDataSourceProperties,
    @Qualifier("write.datasource-com.example.webflux.config.WriteDataSourceProperties")
    private val writeDataSourceProperties: BaseDataSourceProperties,
) : AbstractR2dbcConfiguration() {

    @Bean(name = ["connectionFactory"])
    override fun connectionFactory(): ConnectionFactory = MultiRoutingConnectionFactory().apply {

        val factories: HashMap<String, ConnectionFactory> = hashMapOf(
            WriteDataSourceProperties.KEY to writeConnectionFactory(),
            ReadDataSourceProperties.KEY to readConnectionFactory()
        )

        this.setTargetConnectionFactories(factories)

        this.setDefaultTargetConnectionFactory(writeConnectionFactory())
    }

    @Bean(name = ["writeConnectionFactory"])
    fun writeConnectionFactory() = getConnectionFactory(properties = writeDataSourceProperties)


    @Bean(name = ["readConnectionFactory"])
    fun readConnectionFactory() = getConnectionFactory(properties = readDataSourceProperties)

    private fun getConnectionFactory(properties: BaseDataSourceProperties): ConnectionFactory {

        val options: ConnectionFactoryOptions = ConnectionFactoryOptions.builder()
            .option(DRIVER, properties.driver())
            .option(HOST, properties.host())
            .option(PORT, properties.port())
            .option(USER, properties.username())
            .option(PASSWORD, properties.password())
            .option(DATABASE, properties.database()) 
            .option(CONNECT_TIMEOUT, Duration.ofSeconds(3))
            .build()

        return ConnectionFactories.get(options)
    }

    @Bean
    fun transactionManager(
        @Qualifier("connectionFactory")
        connectionFactory: ConnectionFactory,
    ): TransactionManager = R2dbcTransactionManager(connectionFactory)
}

Error generating Q classes

**type Class does not take parameters**

Getting this error while generating Q Classes

public QStudent(Class<? extends Student> type, PathMetadata metadata, PathInits inits) { super(type, metadata, inits); this.className = inits.isInitialized("className") ? new QClass(forProperty("className")) : null; this.section = inits.isInitialized("section") ? new QSection(forProperty("section")) : null; }

this is the generated code showing error

`SimpleQuerydslR2dbcFragment` always uses `TransactionalRowsFetchSpec`

createQuery() of SimpleQuerydslR2dbcFragment returns new TransactionalRowsFetchSpec<>(databaseClient.sql(sql).map(mapper), TransactionalOperator.create(reactiveTransactionManager));.

This makes any query using this method are executed with a transaction even when it is just select query which doesn't needs transaction practically.

Also, it uses TransactionalOperator.create(reactiveTransactionManager) which executes TransactionDefinition.withDefaults() inside. So, transactionDefinition made by outer scope can be ignored.

Did I miss something? If so, please let me know how I use this awesome library correctly.
If these operations are intended, could you explain the reason?

Support PagingAndSortingRepository of spring data jdbc

Hi,

First of all, thank you for creating the great library, it makes dynamic query in spring-data-jdbc much more easily.

As of the current version (4.0.0), QuerydslJdbcRepository extends CrudRepository. There is PagingAndSortingRepository of spring-data-jdbc provides paging and sorting in addition to CrudRepository, so is it possible for QuerydslJdbcRepository to extends PagingAndSortingRepository so that we can leverage the full power of spring-data-jdbc?

Thanks again.

repository.findAll(Predicate) produce SQL Syntax error.

I have a problem when I perform a request with Predicate (repository.findAll(Predicate)).

2020-12-01 15:35:56.096 ERROR 14304 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.jdbc.BadSqlGrammarException: null; bad SQL grammar [
from product Product
where Product is not null and Product.Price < ?]; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from product Product
where Product is not null and Product.Price < 1500.0' at line 1] with root cause

java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from product Product
where Product is not null and Product.Price < 1500.0' at line 1

version 6 could not generate QTable

Hello,
I used R2DBC and infobip-spring-data-r2dbc-querydsl-boot-starter with version 5.4.2 and it worked well but I increased version to 6.X.X(tried from 6.1.3. to 6.0.0) then disappeared Q-Class.

When I downgrade to 5.4.2, the Q-Class generation works fine again.

Is there any difference in usage?

I don't know if this will help, I'm using Kotlin and Kapt preprocessor.

build.gradle.kts

dependencies {
    implementation(kotlin("reflect"))
    implementation(kotlin("stdlib-jdk8"))
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")

    implementation("org.springframework.cloud:spring-cloud-starter-zookeeper-discovery")
    implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")

    // implementation("com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:5.4.2")

    // synchronized querydsl version to 5.0.0
    implementation("com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:6.1.3")  {
        exclude(group = "com.querydsl", module="querydsl-core")
        exclude(group = "com.querydsl", module="querydsl-apt")
    }
    implementation("com.querydsl:querydsl-core:5.0.0")
    implementation("com.querydsl:querydsl-apt:5.0.0")

    runtimeOnly("io.r2dbc:r2dbc-postgresql")
    kapt("javax.annotation:javax.annotation-api")
    // kapt("com.infobip:infobip-spring-data-jdbc-annotation-processor:5.4.2")
    kapt("com.infobip:infobip-spring-data-jdbc-annotation-processor:6.1.3")
}

Warning messages at preprocessing(did not show in 5.4.2 version):

[WARN] Can't find annotation processor class com.infobip.spring.data.jdbc.annotation.processor.SpringDataJdbcAnnotationProcessor: com/mysema/codegen/model/Type

SQLTemplate

@Configuration
open class QueryDslR2dbcConfig {
    @Bean
    open fun sqlTemplates(): SQLTemplates {
        return PostgreSQLTemplates()
    }
}

Entity table

@Table("users")
data class User(
    @Id
    var id: String,
    var name: String
) : Serializable

QTable(generated in 5.4.2. did not created in 6.X.X)

@Generated("com.querydsl.sql.codegen.MetaDataSerializer")
public class QUser extends com.querydsl.sql.RelationalPathBase<QUser> {

    private static final long serialVersionUID = -463085864;

    public static final QUser user = new QUser("User");

    public final StringPath id = createString("id");

    public final StringPath name = createString("name");

    public QUser(String variable) {
        super(QUser.class, forVariable(variable), null, "users");
        addMetadata();
    }

    public QUser(String variable, String schema, String table) {
        super(QUser.class, forVariable(variable), schema, table);
        addMetadata();
    }

    public QUser(String variable, String schema) {
        super(QUser.class, forVariable(variable), schema, "users");
        addMetadata();
    }

    public QUser(Path<QUser> path) {
        super(path.getType(), path.getMetadata(), null, "users");
        addMetadata();
    }

    public QUser(PathMetadata metadata) {
        super(QUser.class, metadata, null, "users");
        addMetadata();
    }

    public void addMetadata() {
        addMetadata(id, ColumnMetadata.named("Id").withIndex(1));
        addMetadata(name, ColumnMetadata.named("Name").withIndex(2));
    }

}

[BUG] infobip-spring-data-r2dbc-querydsl-boot-starter can not work with @ org.springframework.data.annotation.Transient

exampel is here, checkout branch feature/Transient-annotation-bug and then run command mvn clean -Dmaven.test.skip=true package && java -jar r2dbc-querydsl-lombok-mapstruct-server/target/r2dbc-querydsl-lombok-mapstruct-server-0.0.1-SNAPSHOT.jar can see the error message.

in this example com.example.demo.repository.OrderRepository extends ReactiveCrudRepository so Order can support @Transient but UserRepository extends QuerydslR2dbcRepository cannot.

R2dbc Querydsl use Projections but log not print relation table

hi , i use to r2dbc querydsl

when i use to single table dynamic projections , this is success work

but when i use to relationship table use to left join , this is fail work

this querydsl code

스크린샷 2022-10-29 오후 10 46 37

this logs code

스크린샷 2022-10-29 오후 10 46 46

this log is relationship table left join but this log not print left join

am I using it wrong?

thanks 😀

Spring Boot 3 RC1 w/ R2DBC generation issue

When CustomMetaDataSerializer generates the classes, some constructors are missing

    public QAbstractIdEntity(String variable) {
        super((Class) AbstractIdEntity.class, forVariable(variable), null, "AbstractIdEntity");
        addMetadata();
    }

    @SuppressWarnings("all")
    public QAbstractIdEntity(String variable, String schema, String table) {
        super(AbstractIdEntity.class, forVariable(variable), schema, table);
        addMetadata();
    }

    public QAbstractIdEntity(String variable, String schema) {
        super(AbstractIdEntity.class, forVariable(variable), schema, "AbstractIdEntity");
        addMetadata();
    }

Note: the first ctor has the (Class) cast, but the next two dont

The entity classes:

@Getter
@Setter
public abstract class AbstractTemporalEntity
        implements TemporalEntity
{

    @NotNull
    @CreatedDate
    private LocalDateTime createdAt;

    @NotNull
    @LastModifiedDate
    private LocalDateTime updatedAt;

}
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public abstract class AbstractIdEntity<ID>
        extends AbstractTemporalEntity
        implements IdentityEntity<ID>
{

    @Id
    public ID id;

    protected AbstractIdEntity(ID id) {
        this.id = id;
    }

}

Why my webflux application can not run after adding r2dbc querydsl boot starter

I made a webflux application and support r2dbc.
Everything is OK. The application can start normally.
But after adding "infobip-spring-data-r2dbc-querydsl-boot-starter", the application can not be started. When I clicked run button in IDEA, after a while the application stop automatically.
Can you help me. Thank you!

runtime error multiple data source

hi
please help me.
i used multiple data source
primey datasource: mysql

spring.datasource.jdbc-url=jdbc:mysql://localhost:3306/databaseName
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

datasource1: sqlserver

spring.datasource2.jdbc-url=jdbc:sqlserver://localhost:1433;databaseName=MyDatabase
spring.datasource2.username=xxxxxxx
spring.datasource2.password=xxxxxxx
spring.datasource2.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

configigurations:

@configuration
@EnableJdbcRepositories(
jdbcOperationsRef = "namedParameterJdbcOperations",
basePackages = {"com.sms.gateway.common.repository"})
public class DataJdbcConfiguration extends AbstractJdbcConfiguration {

@Primary
@Bean
public JdbcTemplate mysqlJdbcTemplate(DataSource dsMssql) {
    return new JdbcTemplate(dsMssql);
}

@Primary
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
    return DataSourceBuilder.create()
            .build();
}

@Primary
@Bean
NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) {
    return new NamedParameterJdbcTemplate(dataSource);
}

}

@configuration
@EnableJdbcRepositories(
jdbcOperationsRef = "mssqlDbJdbcOperations",
basePackages = {"com.sms.gateway.common.archived.repository"})
public class ArchivedConfiguration extends AbstractJdbcConfiguration {

@Bean(name = "smsServerMssqlDbJdbcTemplate")
public JdbcTemplate smsServerMssqlJdbcTemplate(@Qualifier("smsServerMssqlDb") DataSource dsMssql) {
    return new JdbcTemplate(dsMssql);
}

@Bean(name = "smsServerMssqlDb")
@ConfigurationProperties(prefix = "spring.datasource2")
public DataSource smsServerDataSource() {
    return DataSourceBuilder.create()
            .build();
}

@Bean(name = "mssqlDbJdbcOperations")
NamedParameterJdbcOperations namedParameterJdbcOperations(@Qualifier("smsServerMssqlDb") DataSource dataSource) {
    return new NamedParameterJdbcTemplate(dataSource);
}

}

error:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.relational.core.dialect.Dialect]: Factory method 'jdbcDialect' threw exception; nested exception is java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.4.jar:5.3.4]
... 51 common frames omitted
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1004) ~[HikariCP-3.4.5.jar:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:109) ~[HikariCP-3.4.5.jar:na]
at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:158) ~[spring-jdbc-5.3.4.jar:5.3.4]
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:116) ~[spring-jdbc-5.3.4.jar:5.3.4]
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:79) ~[spring-jdbc-5.3.4.jar:5.3.4]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:330) ~[spring-jdbc-5.3.4.jar:5.3.4]
at org.springframework.data.jdbc.repository.config.DialectResolver$DefaultDialectProvider.getDialect(DialectResolver.java:107) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
at org.springframework.data.jdbc.repository.config.DialectResolver.lambda$getDialect$0(DialectResolver.java:77) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1632) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543) ~[na:na]
at org.springframework.data.jdbc.repository.config.DialectResolver.getDialect(DialectResolver.java:79) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
at org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration.jdbcDialect(AbstractJdbcConfiguration.java:144) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
at com.sms.gateway.common.archived.ArchivedConfiguration$$EnhancerBySpringCGLIB$$6b355c23.CGLIB$jdbcDialect$7() ~[classes/:na]
at com.sms.gateway.common.archived.ArchivedConfiguration$$EnhancerBySpringCGLIB$$6b355c23$$FastClassBySpringCGLIB$$e97ae8b7.invoke() ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.3.4.jar:5.3.4]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.3.4.jar:5.3.4]
at com.sms.gateway.common.archived.ArchivedConfiguration$$EnhancerBySpringCGLIB$$6b355c23.jdbcDialect() ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.4.jar:5.3.4]
... 52 common frames omitted

Thanks.

@Transient field breaks application context

Hi!
I'm using infobip-spring-data-jdbc-querydsl-boot-starter 6.2.1 version with querydsl 5.0.0
And when I use @Transient like in the following block:

@Table("entity")
@Data
@Builder
@RequiredArgsConstructor
public class Entity {

    @Id
    private final Long id;

    @Transient
    private final boolean isNew;
}

I get exception:

Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: java.lang.NullPointerException
	at com.querydsl.core.types.ConstructorExpression.getParameterTypes(ConstructorExpression.java:59)
	at com.querydsl.core.types.ConstructorExpression.<init>(ConstructorExpression.java:74)
	at com.querydsl.core.types.Projections.constructor(Projections.java:121)
	at com.infobip.spring.data.common.QuerydslExpressionFactory.getConstructorExpression(QuerydslExpressionFactory.java:54)
	at com.infobip.spring.data.jdbc.QuerydslJdbcRepositoryFactory.getRepositoryFragments(QuerydslJdbcRepositoryFactory.java:73)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepositoryComposition(RepositoryFactorySupport.java:371)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:276)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:323)
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:230)
	at org.springframework.data.util.Lazy.get(Lazy.java:114)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:329)
	at org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean.afterPropertiesSet(JdbcRepositoryFactoryBean.java:201)
	at com.infobip.spring.data.jdbc.QuerydslJdbcRepositoryFactoryBean.afterPropertiesSet(QuerydslJdbcRepositoryFactoryBean.java:161)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782)
	... 162 more

Looks like #18 problem.

org.springframework.data.relational.core.mapping '@Table' name property

Hi. I use spring data jdbc and 'infobip-spring-data-querydsl:7.2.0' (also, infobip-spring-data-jdbc-annotation-processor.)

When i generate Q class, most of entities are created well. But, Entities with @table( name = "somthing") annotation, Q class's constructor generated like this.

public QSlotGroup(String variable) {
    super(SlotGroup.class, forVariable(variable), null, "");
    addMetadata();
}

As you see, table name Field fill with "".

public RelationalPathBase(Class<? extends T> type, PathMetadata metadata, String schema,
        String table) {
    super(type, metadata);
    this.schema = schema;
    this.table = table;
    this.schemaAndTable = new SchemaAndTable(schema, table);
}

@Table(name = "slot_group") -> @Table("slot_group")

public QSlotGroup(String variable) {
    super(SlotGroup.class, forVariable(variable), null, "slot_group");
    addMetadata();
}

I solved it by changing it like this, but I think there may be other solutions or improvements, so I'm writing this issue.

remove @Transactional(readOnly = true) from QuerydslJdbcRepository

After the recent library upgrade, my integration tests which call the save() method started failing with:
org.postgresql.util.PSQLException: ERROR: cannot execute INSERT in a read-only transaction

Found that @Transactional(readOnly = true) was added to QuerydslJdbcRepository in the following commit ead317f#diff-20e913bdb291b1677a4ab45059b3989e660e2996d71033de31c7e1e62839d569R15

I understand that I could add @transactional(readOnly = false) on top of each test but QuerydslJdbcRepository class is for all CRUD operations and shouldn't be defaulted to readOnly=true.

I'm proposing to delete that annotation to make the caller handle transactions when needed.

Note: org.springframework.data.repository.CrudRepository doesn't have any @transactional.

Spring Boot 3 RC1 w/ R2DBC mapping error

Hello,

Calling the following:

dao().getRepository().query(query -> query
					  .select(
		                            entity1.currencyId,
		                            entity1.defaultCurrency,
		                            entity1.depositEnabled,
		                            entity1.withdrawEnabled,
		                            entity2.title
					  )
					  .from(entity1)
					  .innerJoin(entity2)
					  .on(entity1.currencyId.eq(entity2.currencyCode))
					  .where(entity1.memberId.eq(testId)))
.all()
.collectList()

Generates an exception:

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.querydsl.core.Tuple using constructor NO_CONSTRUCTOR with arguments 
	at org.springframework.data.mapping.model.ReflectionEntityInstantiator.instantiateClass(ReflectionEntityInstantiator.java:102) ~[spring-data-commons-3.0.0-RC1.jar:3.0.0-RC1]
	at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:53) ~[spring-data-commons-3.0.0-RC1.jar:3.0.0-RC1]
	at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:98) ~[spring-data-commons-3.0.0-RC1.jar:3.0.0-RC1]
	at org.springframework.data.relational.core.conversion.BasicRelationalConverter.createInstance(BasicRelationalConverter.java:132) ~[spring-data-relational-3.0.0-RC1.jar:3.0.0-RC1]
	at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.createInstance(MappingR2dbcConverter.java:319) ~[spring-data-r2dbc-3.0.0-RC2.jar:3.0.0-RC2]

Class cannot be cast to class com.querydsl.sql.RelationalPathBase

I have the same problem as issue#67 (#67)

Repository class:

@org.springframework.stereotype.Repository
public interface MediaCreativeReportQuerydslRepository extends QuerydslJdbcRepository<MediaCreativeReportDb, UUID> {
}

MediaCreativeReportDb class:

@org.springframework.data.relational.core.mapping.Table
@Data
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@com.querydsl.core.annotations.QueryEntity
@com.infobip.spring.data.jdbc.annotation.processor.ProjectTableCaseFormat(CaseFormat.LOWER_UNDERSCORE)
@com.infobip.spring.data.jdbc.annotation.processor.ProjectColumnCaseFormat(CaseFormat.LOWER_UNDERSCORE)
public class MediaCreativeReportDb {
    @org.springframework.data.annotation.Id
    private UUID id;
    // some fields
}

Generated by annotation processor class:

@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QMediaCreativeReportDb extends EntityPathBase<MediaCreativeReportDb> {
    // ...
}

Service class:

@Service
@RequiredArgsConstructor
public class MediaCreativeReportServiceImpl implements MediaCreativeReportService {

    private final MediaCreativeReportQuerydslRepository querydslRepository;

    @Override
    public Page<MediaCreativeReportResponseDto> filter(MediaCreativeReportRequestDto dto) {
        QMediaCreativeReportDb report = QMediaCreativeReportDb.mediaCreativeReportDb;

        SQLQuery<MediaCreativeReportDb> where = querydslRepository.query(sqlQuery -> sqlQuery.select(querydslRepository.entityProjection()))
                .from(report)
                .where(whereStatementStringPath(report.creative_id, dto.creativeId()))
                .where(whereStatementComparablePath(report.ord_id, dto.ordId()));
        System.out.println(where);
        return null;
    }

But i have this error message:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'VMediaCreativeReportController' defined in file [C:\Users\akonyukhov\IdeaProjects\register-service\build\classes\java\main\ru\atc\rkn\service\register\controller\inner\VMediaCreativeReportController.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mediaCreativeReportServiceImpl' defined in file [C:\Users\akonyukhov\IdeaProjects\register-service\build\classes\java\main\ru\atc\rkn\service\register\querydsl\MediaCreativeReportServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mediaCreativeReportQuerydslRepository' defined in ru.atc.rkn.service.register.querydsl.MediaCreativeReportQuerydslRepository defined in @EnableJdbcRepositories declared on QuerydslJdbcRepositoriesRegistrar.EnableJdbcRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.ClassCastException: class ru.atc.rkn.service.register.querydsl.QMediaCreativeReportDb cannot be cast to class com.querydsl.sql.RelationalPathBase (ru.atc.rkn.service.register.querydsl.QMediaCreativeReportDb and com.querydsl.sql.RelationalPathBase are in unnamed module of loader 'app')
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.18.jar:5.3.18]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.18.jar:5.3.18]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.18.jar:5.3.18]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.6.jar:2.6.6]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) ~[spring-boot-2.6.6.jar:2.6.6]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) ~[spring-boot-2.6.6.jar:2.6.6]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-2.6.6.jar:2.6.6]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.6.jar:2.6.6]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.6.jar:2.6.6]
	at ru.atc.rkn.service.register.RegisterService.main(RegisterService.java:20) ~[main/:na]

Error after adding querydsl-sql-spatial

When I add new dependency.

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-sql-spatial</artifactId>
    <version>${querydsl.version}</version>
</dependency>

After exec mvn clean compile, compile error.

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5:compile (default-compile) on project dat-admin: Fatal error compiling: java.lang.IllegalArgumentException: com.querydsl.sql.Configuration is not registered -> [Help 1]

After add custom maven plugin with same error:

<plugin>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-maven-plugin</artifactId>
    <version>${querydsl.version}</version>
    <configuration>
        <spatial>true</spatial>
    </configuration>
</plugin>

[boot-starter] Cannot use custom JPA repositories

// My custom repository
@NoRepositoryBean
public interface MyRepository<T, ID> extends
        JpaSpecificationExecutor<T>,
        ExtendedQuerydslJpaRepository<T, ID> {
}

// MyJpaRepositoryFactoryBean extents ExtendedQuerydslJpaRepositoryFactoryBean
public class MyJpaRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable>
        extends ExtendedQuerydslJpaRepositoryFactoryBean<T, S, ID> {

    public MyJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }
}

@EnableJpaRepositories(repositoryFactoryBeanClass = MyJpaRepositoryFactoryBean.class)
public class AppServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppServerApplication.class, args);
    }
}

But I got error when start:

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'apiAccessLogRepository', defined in a.b.core.repository.ApiAccessLogRepository defined in @EnableJpaRepositories declared on QuerydslJpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration, could not be registered. A bean with that name has already been defined in com.elva.core.repository.ApiAccessLogRepository defined in @EnableJpaRepositories declared on AppServerApplication and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

Looks like the boot starter already decalred @EnableJpaRepositories annotation in QuerydslJpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration

Help! How do i disable the @EnableExtendedJpaRepositories annotation or change the repositoryFactoryBeanClass, to use my custom JPA repositories?

QuerydslJdbcRepositoryFactory can't find a static field of the same type in class

I have a problem:

Caused by: java.lang.IllegalArgumentException: Did not find a static field of the same type in class com.develop.jinamaven.jinamaven.qEntities.QCategoryTable at com.infobip.spring.data.jdbc.QuerydslJdbcRepositoryFactory.getRelationalPathBase(QuerydslJdbcRepositoryFactory.java:133) ~[infobip-spring-data-jdbc-querydsl-3.0.0.jar:na]

And I don't know how to solve it. The maven plugin generates QEntities but QuerydslJdbcRepositoryFactory can't find the static field but the field exists.
image
QuerydslJdbcRepositoryFactory tries to perform

ReflectionUtils.findField(queryType, queryType.getSimpleName().substring(1));

image
And obviously it returns null, because the field is categoryTable and it tries to find CategoryTable. The expression was successful

ReflectionUtils.findField(queryType, Character.toLowerCase(queryType.getSimpleName().charAt(1)) + queryType.getSimpleName().substring(2)

image
Can someone help me?

Spring + R2DBC + Flyway: bean of type 'com.querydsl.sql.SQLTemplates' that could not be found.

I have the same issue even using flyway.

    ***************************
    APPLICATION FAILED TO START
    ***************************

    Description:

    Parameter 0 of method querydslSqlConfiguration in com.infobip.spring.data.r2dbc.R2dbcConfiguration required a bean of type 'com.querydsl.sql.SQLTemplates' that could not be found.


    Action:

    Consider defining a bean of type 'com.querydsl.sql.SQLTemplates' in your configuration.

Spring: 2.4.2
querydsl: 4.4.0
infobip: 5.4.0

I'm using the autoconfiguration provided by spring to create Flyway bean, before when I was not trying to introduce querydsl everything was running fine, flyway is applying the migrations, even in tests I have a junit5 extension that uses flyway to clean the db and migrate after each test, and everything regarding flyway is setup fine.

Dependencies:

	kapt("org.springframework.boot:spring-boot-configuration-processor")
	implementation("org.springframework.boot:spring-boot-starter-actuator")
	implementation("org.springframework.boot:spring-boot-starter-jdbc")
	implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
	implementation("org.springframework.boot:spring-boot-starter-security")
	implementation("org.springframework.boot:spring-boot-starter-validation")
	implementation("org.springframework.boot:spring-boot-starter-webflux")
	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
	implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
	implementation("org.jetbrains.kotlin:kotlin-reflect")
	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
	implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
	implementation("org.flywaydb:flyway-core")
	runtimeOnly("io.r2dbc:r2dbc-postgresql")
	runtimeOnly("org.postgresql:postgresql")

	// query dsl
	implementation("org.springframework.data:spring-data-relational")
	implementation("com.querydsl:querydsl-apt:$queryDslVersion")
	implementation("com.querydsl:querydsl-sql:$queryDslVersion")
	implementation("com.infobip:infobip-spring-data-jdbc-annotation-processor:$infobipQueryDslVersion")
	implementation("com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:$infobipQueryDslVersion")
	//

Originally posted by @creativelikeadog in #17 (comment)

Spring Data JDBC: Embedded Entity and ProjectTableCaseFormat is not working

Hi , this is all my config:

maven dependency

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

...

 <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-core</artifactId>
            <version>5.0.0</version>
        </dependency>

        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>5.0.0</version>
        </dependency>

        <dependency>
            <groupId>com.infobip</groupId>
            <artifactId>infobip-spring-data-jdbc-querydsl-boot-starter</artifactId>
            <version>6.1.2</version>
        </dependency>

JdbcConfig

@Configuration
@ProjectTableCaseFormat(CaseFormat.LOWER_UNDERSCORE)
@ProjectColumnCaseFormat(CaseFormat.LOWER_UNDERSCORE)
public class JdbcConfig extends AbstractJdbcConfiguration {

    @Bean
    NamingStrategy namingStrategy() {
        return new NamingStrategy(){
            @Override
            public String getTableName(Class<?> type) {
                return NamingStrategy.super.getTableName(type);
            }

            @Override
            public String getReverseColumnName(RelationalPersistentProperty property) {
                return NamingStrategy.super.getReverseColumnName(property).toLowerCase() + "_id";
            }

            @Override
            public String getKeyColumn(RelationalPersistentProperty property) {
                return "sort_order";
            }
        };
    }
}

Main

@SpringBootApplication
public class QuerydslDemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(QuerydslDemoApplication.class, args);
        AuthProviderRepository repository = ctx.getBean(AuthProviderRepository.class);
   
        Object resp = repository.queryMany(q -> q
                .select(repository.entityProjection())
                .from(authProvider));
        System.out.println(resp);
    }
}

Entities

@Getter
@AllArgsConstructor
public class AuthProvider {

    @Id
    private Long id;
    private Long tenantId;
    private String name;
    private String endpoint;
    private String healthUrl;

    @Embedded.Empty
    private SecretInfo secretInfo;

    @MappedCollection(idColumn = "auth_provider_id", keyColumn = "authorized_at")
    private Iterable<AuthorizedTenant> authorizedTenants;

}


@Value
@Builder
public class AuthorizedTenant {

    @Id
    @With
    private Long id;
    private Long tenantId;
    private Long authorizedAt;

}

@Value(staticConstructor = "from")
public class SecretInfo {

    private String accessKey;
    private String secretKey;

}

Repository

public interface AuthProviderRepository extends QuerydslJdbcRepository<AuthProvider, Long> {

}

The errror message :


...
Caused by: com.querydsl.core.QueryException: Caught SQLSyntaxErrorException for select AuthProvider.Id, AuthProvider.TenantId, AuthProvider.Name, AuthProvider.Endpoint, AuthProvider.HealthUrl, AuthProvider.SecretInfo, AuthProvider.AuthorizedTenants
from AuthProvider AuthProvider
...

Caused by: java.sql.SQLSyntaxErrorException: Table 'mydb.authprovider' doesn't exist

If I use @Table on Entity class for customizing, like @Table("auth_provider"), then errror message is :


Caused by: com.querydsl.core.QueryException: Caught SQLSyntaxErrorException for select AuthProvider.id, AuthProvider.tenant_id, AuthProvider.name, AuthProvider.endpoint, AuthProvider.health_url, AuthProvider.secret_info, AuthProvider.authorized_tenants
from auth_provider AuthProvider
	at com.querydsl.sql.DefaultSQLExceptionTranslator.translate(DefaultSQLExceptionTranslator.java:50)
	at com.querydsl.sql.Configuration.translate(Configuration.java:507)
	at com.querydsl.sql.AbstractSQLQuery.getResults(AbstractSQLQuery.java:311)
	at com.infobip.spring.data.jdbc.QuerydslJdbcPredicateExecutor.query(QuerydslJdbcPredicateExecutor.java:175)
	at com.infobip.spring.data.jdbc.QuerydslJdbcPredicateExecutor.queryMany(QuerydslJdbcPredicateExecutor.java:163)

...

Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'AuthProvider.secret_info' in 'field list'
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
...

[bug] JDBC Configured NamingStrategy produces errors.

Hello,
when using PascalCaseNamingStrategy all existing queries are broken due to fact that the field names are generated inorrectly.
When I configure the naming strategy to use spring's default then old queries are ok but if I create new query using repository.queryOne(...) then it's not working because of bad field names.

here is test (note: branch is feature/querydsl-infobip).

Generated query is

select UserEntity.Id, UserEntity.FirstName, UserEntity.LastName
from users UserEntity
where UserEntity.FirstName = ?

but it should be

select UserEntity.Id, UserEntity.first_name, UserEntity.last_name
from users UserEntity
where UserEntity.first_name = ?

IllegalArgumentException: Did not find a static field of the same type in class org.example.entity.QExamInfo

infobip-spring-data-jdbc-querydsl-boot-starter: 6.2.1
querydsl-maven-plugin:4.1.4

log details:

Caused by: java.lang.IllegalArgumentException: Did not find a static field of the same type in class org.example.entity.QExamInfo
	at com.infobip.spring.data.common.QuerydslExpressionFactory.getRelationalPathBaseFromQueryClass(QuerydslExpressionFactory.java:131)
	at com.infobip.spring.data.common.QuerydslExpressionFactory.getRelationalPathBaseFromQueryRepositoryClass(QuerydslExpressionFactory.java:114)
	at com.infobip.spring.data.jdbc.QuerydslJdbcRepositoryFactory.getRepositoryFragments(QuerydslJdbcRepositoryFactory.java:70)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepositoryComposition(RepositoryFactorySupport.java:434)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:300)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:322)
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:230)

because the generated bean use upper camel:

public class QExamInfo extends com.querydsl.sql.RelationalPathBase<ExamInfo> {

    private static final long serialVersionUID = -401254998;

    public static final QExamInfo ExamInfo = new QExamInfo("ExamInfo");

    public final StringPath applyDate = createString("applyDate");

    public final StringPath applyDoctor = createString("applyDoctor");

while the com.infobip.spring.data.common.QuerydslExpressionFactory#getRelationalPathBaseFromQueryClass use lower camel

   private RelationalPathBase<?> getRelationalPathBaseFromQueryClass(Class<?> queryClass) {
        String fieldName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, queryClass.getSimpleName().substring(1));
        Field field = ReflectionUtils.findField(queryClass, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Did not find a static field of the same type in " + queryClass);
        }

How to ignore fields when updating

    @CreatedBy
    @JsonIgnore
    private Long createdBy;

    @CreatedDate
    @JsonIgnore
    private LocalDateTime createdDate;

Is there any way to ignore then (raw sql is contains: set created_by = null, set created_date = null) when updating.

Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'created_by' cannot be null
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117) ~[mysql-connector-java-8.0.26.jar:8.0.26]
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.26.jar:8.0.26]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.26.jar:8.0.26]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092) ~[mysql-connector-java-8.0.26.jar:8.0.26]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040) ~[mysql-connector-java-8.0.26.jar:8.0.26]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1350) ~[mysql-connector-java-8.0.26.jar:8.0.26]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025) ~[mysql-connector-java-8.0.26.jar:8.0.26]

UseLiteral in SimpleQuerydslR2dbcFragment and ReactiveQuerydslR2dbcPredicateExecutor

SimpleQuerydslR2dbcFragment and ReactiveQuerydslR2dbcPredicateExecutor do not use prepared statement bindings but literals.

is there any reason for setUseLiterals(true)?

hibernate 2nd cache with predicate findAll

@NoRepositoryBean
public interface ExtendedCommonEntityDataPolicyDao<
    T extends AbstractPersistableEntity, Q extends EntityPath<?>
>
    extends ExtendedQuerydslJpaRepository<T, Long>, QuerydslBinderCustomizer<Q> {
// ...
}
@Repository
@Primary
public interface SysGrpDao extends ExtendedCommonEntityDataPolicyDao<SysGrp, QSysGrp> {
    /* Query */
}

findAll method not hint 2nd cache.

but Spring's findById it working.

@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
default Page<T> policyFindAll(@Nonnull Pageable pageable) {
    return findAll(pageable);
}

not working even with @QueryHints

No property jpaSqlSubQuery found for type

My spring boot application with spring boot 2.4.3 as following

The entity

@DaTa
@entity
@table(name="customer",indexes = {
@Index(name="customer_name",columnList="name"),
@Index(name="customer_customer_type",columnList="customerType")
})
public class CustomerPO{
@id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String name;
private String moble;
@Enumerated(EnumType.STRING)
private CustomerType customerType; //客户类型
private Date createTime;
}

The Repository
@repository
public interface CustomerDao extends ExtendedQuerydslJpaRepository<CustomerPO,Long> {
}

I have add following dependency and get QClass in "target/generated-sources/annotion"

< dependency >
< groupId >com.infobip< /groupId>
< artifactId >infobip-spring-data-jpa-querydsl</ artifactId>
< version >5.0.4< / version>
</ dependency >

But when I run my application in IDEA, I get following error:Caused by:

org.springframework.data.mapping.PropertyReferenceException: No property jpaSqlSubQuery found for type CustomerPO!
at org.springframework.data.mapping.PropertyPath.(PropertyPath.java:90)

Can you help me? Thank you!

ClassCastException: cannot be cast to class com.querydsl.sql.RelationalPathBase

Here my generated "QEntity" class:

public class QQdCF extends EntityPathBase<QdCF> {
 // ...
}

Here my repository:

@Repository
public interface QdCFRepository extends QuerydslR2dbcRepository<QdCF, Long> {
	
}

My service:

@RequiredArgsConstructor
@Service
public class QdCFService {

	private final PresenterMapper presenterMapper;
	private final QueryMapper queryMapper;
	private final QdCFRepository qdcfRepository;
	
	public Mono<PageableResponseModel<QdCFPresenter>> getQdCFSearchQueryDsl(
		QdCFSearchFormModel form,
		Pageable pageable
	) {
		Function<List<QdCFPresenter>, PageableResponseModel<QdCFPresenter>> toResponse =
			(items) -> PageableResponseModel.<QdCFPresenter>builder().size(items.size()).page(form.getPage()).results(items).build();

		return this.qdcfRepository.findAll(this.queryMapper.toPredicate(form))
			.map(this.presenterMapper::toPresenter)
			.collectList()
			.map(toResponse);
	}

Everything is straighforward.

Nevertheless, I'm getting this error message on startup:

Caused by: java.lang.ClassCastException: class cat.gencat.clt.git.backend.model.persistency.QQdCF cannot be cast to class com.querydsl.sql.RelationalPathBase (cat.gencat.clt.git.backend.model.persistency.QQdCF and com.querydsl.sql.RelationalPathBase are in unnamed module of loader 'app')

	at com.infobip.spring.data.common.QuerydslExpressionFactory.getRelationalPathBaseFromQueryClass(QuerydslExpressionFactory.java:177) ~[infobip-spring-data-common-7.2.0.jar:na]

	at com.infobip.spring.data.common.QuerydslExpressionFactory.getRelationalPathBaseFromQueryRepositoryClass(QuerydslExpressionFactory.java:157) ~[infobip-spring-data-common-7.2.0.jar:na]

	at com.infobip.spring.data.r2dbc.QuerydslR2dbcRepositoryFactory.getRepositoryFragments(QuerydslR2dbcRepositoryFactory.java:67) ~[infobip-spring-data-r2dbc-querydsl-7.2.0.jar:na]

	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepositoryComposition(RepositoryFactorySupport.java:436) ~[spring-data-commons-2.7.2.jar:2.7.2]

	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:301) ~[spring-data-commons-2.7.2.jar:2.7.2]

	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:323) ~[spring-data-commons-2.7.2.jar:2.7.2]

	at org.springframework.data.util.Lazy.getNullable(Lazy.java:231) ~[spring-data-commons-2.7.2.jar:2.7.2]

	at org.springframework.data.util.Lazy.get(Lazy.java:115) ~[spring-data-commons-2.7.2.jar:2.7.2]

	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:329) ~[spring-data-commons-2.7.2.jar:2.7.2]

	at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean.afterPropertiesSet(R2dbcRepositoryFactoryBean.java:179) ~[spring-data-r2dbc-1.5.2.jar:1.5.2]

	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.22.jar:5.3.22]

	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.22.jar:5.3.22]

	... 44 common frames omitted

Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.