{"id":19337262,"url":"https://github.com/infobip/infobip-spring-data-querydsl","last_synced_at":"2025-05-15T14:05:08.490Z","repository":{"id":40486532,"uuid":"106394569","full_name":"infobip/infobip-spring-data-querydsl","owner":"infobip","description":"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.","archived":false,"fork":false,"pushed_at":"2025-05-02T05:04:30.000Z","size":749,"stargazers_count":290,"open_issues_count":4,"forks_count":55,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-05-02T05:28:49.585Z","etag":null,"topics":["java","jdbc","jpa","querydsl","r2dbc","spring-data","spring-data-jdbc","spring-data-jpa","spring-data-r2dbc"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/infobip.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-10T09:10:59.000Z","updated_at":"2025-05-02T05:04:34.000Z","dependencies_parsed_at":"2023-11-28T11:30:56.457Z","dependency_job_id":"6bcdd665-6af5-4ce8-8813-c032319deff9","html_url":"https://github.com/infobip/infobip-spring-data-querydsl","commit_stats":null,"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infobip%2Finfobip-spring-data-querydsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infobip%2Finfobip-spring-data-querydsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infobip%2Finfobip-spring-data-querydsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infobip%2Finfobip-spring-data-querydsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infobip","download_url":"https://codeload.github.com/infobip/infobip-spring-data-querydsl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254355334,"owners_count":22057354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","jdbc","jpa","querydsl","r2dbc","spring-data","spring-data-jdbc","spring-data-jpa","spring-data-r2dbc"],"created_at":"2024-11-10T03:13:52.111Z","updated_at":"2025-05-15T14:05:08.460Z","avatar_url":"https://github.com/infobip.png","language":"Java","funding_links":[],"categories":["\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[],"readme":"# Infobip Spring Data Querydsl\n\n[![](https://github.com/infobip/infobip-spring-data-querydsl/workflows/maven/badge.svg)](https://github.com/infobip/infobip-spring-data-querydsl/actions?query=workflow%3Amaven)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.infobip/infobip-spring-data-querydsl/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.infobip/infobip-spring-data-querydsl)\n[![Coverage Status](https://coveralls.io/repos/github/infobip/infobip-spring-data-querydsl/badge.svg?branch=master)](https://coveralls.io/github/infobip/infobip-spring-data-querydsl?branch=master)\n[![Known Vulnerabilities](https://snyk.io/test/github/infobip/infobip-spring-data-querydsl/badge.svg)](https://snyk.io/test/github/infobip/infobip-spring-data-querydsl)\n\nInfobip 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.\n\n## Contents\n\n1. [Changelog](#Changelog)\n1. [Note on general usage](#NoteOnGeneralUsage)\n1. [JDBC module:](#JDBC)\n    * [Requirements](#JDBCRequirements)\n    * [Setup](#JDBCSetup)\n    * [Features and examples](#JDBCFeaturesAndExamples)\n        * [Inner Join](#JDBCInnerJoin)\n        * [Projections](#JDBCProjections)\n        * [Query](#JDBCQuery)\n        * [Update](#JDBCUpdate)\n        * [Delete](#JDBCDelete)\n        * [Transactional support](#JDBCTransactionalSupport)\n        * [Embedded support](#JDBCEmbeddedSupport)\n        * [@MappedCollection](#MappedCollection)\n        * [Streaming](#JDBCStreaming)\n    * [Extension](#JDBCExtension)\n1. [R2DBC module:](#R2DBC)\n   * [Requirements](#R2DBCRequirements)\n   * [Setup](#R2DBCSetup)\n   * [Features and examples](#R2DBCFeaturesAndExamples)\n      * [Inner Join](#R2DBCInnerJoin)\n      * [Projections](#R2DBCProjections)\n      * [Query](#R2DBCQuery)\n      * [Update](#R2DBCUpdate)\n      * [Delete](#R2DBCDelete)\n      * [Transactional support](#R2DBCTransactionalSupport)\n   * [Extension](#R2DBCExtension)\n1. [JPA module:](#JPA)\n    * [Requirements](#JPARequirements)\n    * [Setup](#JPASetup)\n    * [Features and examples:](#JPAFeaturesAndExamples)\n        * [Native queries with Querydsl](#JPANativeQueriesWithQuerydsl)\n        * [Projections](#JPAProjections)\n        * [Query](#JPAQuery)\n        * [Update](#JPAUpdate)\n        * [Delete](#JPADelete)\n        * [List instead of Iterable return type](#JPAListInsteadOfIterableReturnType)\n        * [Transactional support](#JPATransactionalSupport)\n        * [Stored procedure builder](#JPAStoredProcedureBuilder)\n        * [Streaming](#JPAStreaming)\n    * [Extension](#JPAExtension)\n1. [Annotation processor](#AnnotationProcessor)\n1. [Further reading](#FurtherReading)\n1. [Running tests](#RunningTests)\n1. [Contributing](#Contributing)\n1. [License](#License)\n\n\u003ca id=\"Changelog\"\u003e\u003c/a\u003e\n##  Changelog\n\nFor changes check the [changelog](CHANGELOG.md).\n\n\u003ca id=\"NoteOnGeneralUsage\"\u003e\u003c/a\u003e\n##  Note on general usage\n\nFor the sake of brevity, all examples use repository methods directly.\n\nIn production code persistence layer (SQL) shouldn't leak to service layer.\nSee [this answer](https://stackoverflow.com/a/26563841/607767) by Oliver Drotbohm (Spring Data Project Lead @ Pivotal) on how to approach encapsulating persistence logic.\n\n\u003ca id=\"JDBC\"\u003e\u003c/a\u003e\n##  JDBC module:\n\n\u003ca id=\"JDBCRequirements\"\u003e\u003c/a\u003e\n###  Requirements:\n\n- Java 17 with [parameter names preserved in byte code](https://stackoverflow.com/a/20594685/607767) (used to map columns to constructor parameters)\n- Spring Data JDBC\n- entities must have an all argument constructor (`@AllArgsConstructor`), can have others as well\n- entity class and all argument constructor must be public (limitation of Querydsl)\n\n\u003ca id=\"JDBCSetup\"\u003e\u003c/a\u003e\n###  Setup:\n\n1. Dependency:\n\n```xml\n\u003cdependency\u003e\n   \u003cgroupId\u003ecom.infobip\u003c/groupId\u003e\n   \u003cartifactId\u003einfobip-spring-data-jdbc-querydsl-boot-starter\u003c/artifactId\u003e\n   \u003cversion\u003e${infobip-spring-data-jdbc-querydsl.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n2. Refactor repository interfaces to either use new base repository or fragments approach:\n\n* new base repository approach:   \n\n```java\ninterface TRepository extends QuerydslJdbcRepository\u003cT, ID\u003e {\n}\n```\n\n* fragments:\n\n```java\ninterface TRepository extends PagingAndSortingRepository\u003cT, ID\u003e, QuerydslPredicateExecutor\u003cT\u003e, QuerydslJdbcFragment\u003cT\u003e {\n}\n```\n\n3. Done\n\n\u003ca id=\"JDBCFeaturesAndExamples\"\u003e\u003c/a\u003e\n###  Features and examples:\n\nAll examples have corresponding tests in the project and can be found [here](infobip-spring-data-jdbc-querydsl/src/test/java/com/infobip/spring/data/jdbc).\n\n\u003ca id=\"JDBCInnerJoin\"\u003e\u003c/a\u003e\n###  Inner Join:\n\nInner join example:\n\n```\nList\u003cPerson\u003e actual = repository.query(query -\u003e query\n        .select(repository.entityProjection())\n        .from(person)\n        .innerJoin(personSettings)\n        .on(person.id.eq(personSettings.personId))\n        .where(personSettings.id.eq(johnDoeSettings.getId()))\n        .fetch());\n);\n```\n\n\u003ca id=\"JDBCProjections\"\u003e\u003c/a\u003e\n###  Projections\n\nFor examples how to construct projections refer to the official documentation - [section result handling](http://www.querydsl.com/static/querydsl/latest/reference/html_single/#result_handling).\n\nHere is an example that uses constructor:\n\n```$xslt\npublic record PersonProjection(\n    String firstName,\n    String lastName\n) {\n\n}\n...\n\nList\u003cPersonProjection\u003e actual = repository.query(query -\u003e query\n        .select(Projections.constructor(PersonProjection.class, person.firstName,\n                                        person.lastName))\n        .from(person)\n        .fetch());\n```\n\n\u003ca id=\"JDBCQuery\"\u003e\u003c/a\u003e\n###  Query\n\n```\nOptional\u003cPerson\u003e actual = repository.queryOne(query -\u003e query\n        .select(repository.entityProjection())\n        .from(person)\n        .where(person.firstName.in(\"John\", \"Jane\"))\n        .orderBy(person.firstName.asc(), person.lastName.asc())\n        .limit(1)\n        .offset(1));\n```\n\n```\nList\u003cPerson\u003e actual = repository.queryMany(query -\u003e query\n        .select(repository.entityProjection())\n        .from(person)\n        .where(person.firstName.in(\"John\", \"Jane\"))\n        .orderBy(person.firstName.asc(), person.lastName.asc())\n        .limit(1)\n        .offset(1));\n```\n\n\u003ca id=\"JDBCUpdate\"\u003e\u003c/a\u003e\n###  Update\n\n```\nrepository.update(query -\u003e query\n        .set(person.firstName, \"John\")\n        .where(person.firstName.eq(\"Johny\"))\n        .execute());\n```\n\n\u003ca id=\"JDBCDelete\"\u003e\u003c/a\u003e\n###  Delete\n\n```\nlong numberOfAffectedRows = repository.deleteWhere(person.firstName.like(\"John%\"));\n```\n\n\u003ca id=\"JDBCTransactionalSupport\"\u003e\u003c/a\u003e\n###  Transactional support\n\nQueries execution is always done inside the repository implementation (loan pattern) in a transaction so transactions don't have to be \nhandled manually (like they do if you are manually managing SQLQuery and other Querydsl constructs).\n\n\u003ca id=\"JDBCEmbeddedSupport\"\u003e\u003c/a\u003e\n###  Embedded support\n\nEntity fields marked with `@org.springframework.data.relational.core.mapping.Embedded` are inlined in Q classes:\n\nModel:\n```java\n@Table(\"Person\")\npublic record PersonWithEmbeddedFirstAndLastName(\n\n        @With\n        @Id\n        Long id,\n\n        @Embedded(onEmpty = Embedded.OnEmpty.USE_EMPTY)\n        FirstAndLastName firstAndLastName\n) {\n    \n}\n```\n\n\n```java\npublic record FirstAndLastName(\n        String firstName,\n        String lastName\n) {\n\n}\n```\n\nQuery (note the missing .personWithEmbeddedFirstAndLastName field in Q instance):\n\n```java\nrepository.findAll(personWithEmbeddedFirstAndLastName.firstName.in(\"John\", \"Johny\"));\n```\n\n\u003ca id=\"MappedCollection\"\u003e\u003c/a\u003e\n###  @MappedCollection support\n\nModel:\n\n```java\npublic record Student(\n        @Id\n        Long id,\n\n        String name,\n\n        @MappedCollection(idColumn = \"StudentId\", keyColumn = \"CourseId\")\n        Set\u003cStudentCourse\u003e courses\n) {\n\n   void addItem(Course course) {\n      var studentCourse = new StudentCourse(null, AggregateReference.to(course.id()), null);\n      courses.add(studentCourse);\n   }\n\n}\n```\n\n```java\npublic record Course(\n        @Id\n        Long id,\n        String name\n) {\n\n}\n```\n\n```java\npublic record StudentCourse(\n        @Id\n        Long id,\n\n        AggregateReference\u003cCourse, Long\u003e courseId,\n\n        Long studentId\n) {\n\n}\n```\n\nQuery:\n\n```java\nList\u003cStudent\u003e actual = studentRepository.query(query -\u003e query.select(studentRepository.entityProjection())\n                                                             .from(student)\n                                                             .innerJoin(studentCourse)\n                                                             .on(student.id.eq(studentCourse.studentId))\n                                                             .fetch());\n```\n\n\u003ca id=\"JDBCStreaming\"\u003e\u003c/a\u003e\n###  Streaming\n\n`streamAll` is a new method added to repository for more convenient use.\n\n```\n@Transactional\npublic void transactionalAnnotatedMethodRequiredForConsumingStream() {\n   try (Stream\u003cPerson\u003e stream = repository.streamAll()) {\n      // use stream\n   }\n}\n```\n\n\u003ca id=\"JDBCExtension\"\u003e\u003c/a\u003e\n###  Extension:\n\nTo create a custom base repository interface you'll need to create:\n*  custom base interface\n*  custom annotation for enabling\n*  custom factory bean class and potentially factory class depending on requirements\n\nTake a look at [extension package in tests](infobip-spring-data-jdbc-querydsl/src/test/java/com/infobip/spring/data/jdbc/extension) as an example on how this can be achieved.\n\n\u003ca id=\"R2DBC\"\u003e\u003c/a\u003e\n##  R2DBC module:\n\n\u003ca id=\"R2DBCRequirements\"\u003e\u003c/a\u003e\n###  Requirements:\n\n- Java 17 with [parameter names preserved in byte code](https://stackoverflow.com/a/20594685/607767) (used to map columns to constructor parameters)\n- Spring Data R2DBC\n- entities must have an all argument constructor (`@AllArgsConstructor`), can have others as well\n- entity class and all argument constructor must be public (limitation of Querydsl)\n- if you're not using Flyway, you need to provide a SQLTemplates bean\n\n\u003ca id=\"R2DBCSetup\"\u003e\u003c/a\u003e\n###  Setup:\n\n1. Dependency:\n\n```xml\n\u003cdependency\u003e\n   \u003cgroupId\u003ecom.infobip\u003c/groupId\u003e\n   \u003cartifactId\u003einfobip-spring-data-r2dbc-querydsl-boot-starter\u003c/artifactId\u003e\n   \u003cversion\u003e${infobip-spring-data-r2dbc-querydsl.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n2. Refactor repository interfaces to either use new base repository or fragments approach:\n\n* new base repository approach:\n\n```java\ninterface TRepository extends QuerydslR2dbcRepository\u003cT, ID\u003e {\n}\n```\n\n* fragments:\n\n```java\ninterface TRepository extends ReactiveSortingRepository\u003cT, ID\u003e, ReactiveQuerydslPredicateExecutor\u003cT\u003e, QuerydslR2dbcFragment\u003cT\u003e {\n}\n```\n\n3. Done\n\n\u003ca id=\"R2DBCFeaturesAndExamples\"\u003e\u003c/a\u003e\n###  Features and examples:\n\nAll examples have corresponding tests in the project and can be found [here](infobip-spring-data-r2dbc-querydsl/src/test/java/com/infobip/spring/data/r2dbc).\n\n\u003ca id=\"R2DBCInnerJoin\"\u003e\u003c/a\u003e\n###  Inner Join:\n\nInner join example:\n\n```\nFlux\u003cPerson\u003e actual = repository.query(query -\u003e query.select(repository.entityProjection())\n                                                          .from(person)\n                                                          .innerJoin(personSettings)\n                                                          .on(person.id.eq(personSettings.personId))\n                                                          .where(personSettings.id.eq(johnDoeSettings.getId())))\n                                     .all();\n```\n\n\u003ca id=\"R2DBCProjections\"\u003e\u003c/a\u003e\n###  Projections\n\nFor examples how to construct projections refer to the official documentation - [section result handling](http://www.querydsl.com/static/querydsl/latest/reference/html_single/#result_handling).\n\nHere is an example that uses constructor:\n\n```$xslt\npublic record PersonProjection(\n    String firstName,\n    String lastName\n) {\n\n}\n...\n\nFlux\u003cPersonProjection\u003e actual = repository.query(query -\u003e query\n        .select(constructor(PersonProjection.class, person.firstName, person.lastName))\n        .from(person))\n                                          .all();\n```\n\n\u003ca id=\"R2DBCQuery\"\u003e\u003c/a\u003e\n###  Query\n\n```\nFlux\u003cPerson\u003e actual = repository.query(query -\u003e query.select(repository.entityProjection())\n                                                     .from(person)\n                                                     .where(person.firstName.in(\"John\", \"Jane\"))\n                                                     .orderBy(person.firstName.asc(),\n                                                              person.lastName.asc())\n                                                     .limit(1)\n                                                     .offset(1))\n                                .all();\n```\n\n\u003ca id=\"R2DBCUpdate\"\u003e\u003c/a\u003e\n###  Update\n\n```\nMono\u003cInteger\u003e numberOfAffectedRows = repository.update(query -\u003e query.set(person.firstName, \"John\")\n                                                                     .where(person.firstName.eq(\"Johny\")));\n```\n\n\u003ca id=\"R2DBCDelete\"\u003e\u003c/a\u003e\n###  Delete\n\n```\nMono\u003cInteger\u003e numberOfAffectedRows = repository.deleteWhere(person.firstName.like(\"John%\"));\n```\n\n\u003ca id=\"R2DBCTransactionalSupport\"\u003e\u003c/a\u003e\n###  Transactional support\n\nQueries execution is always done inside the repository implementation (loan pattern) in a transaction so transactions don't have to be\nhandled manually (like they do if you are manually managing SQLQuery and other Querydsl constructs).\n\n\u003ca id=\"R2DBCExtension\"\u003e\u003c/a\u003e\n###  Extension:\n\nTo create a custom base repository interface you'll need to create:\n*  custom base interface\n*  custom annotation for enabling\n*  custom factory bean class and potentially factory class depending on requirements\n\nTake a look at [extension package in tests](infobip-spring-data-r2dbc-querydsl/src/test/java/com/infobip/spring/data/r2dbc/extension) as an example on how this can be achieved.\n\n\n\u003ca id=\"JPA\"\u003e\u003c/a\u003e\n##  JPA module:\n\n\u003ca id=\"JPARequirements\"\u003e\u003c/a\u003e\n###  Requirements:\n\n- Java 17\n- Spring Data JPA\n\n\u003ca id=\"JPASetup\"\u003e\u003c/a\u003e\n###  Setup:\n\n1. Dependency:\n\n```xml\n\u003cdependency\u003e\n   \u003cgroupId\u003ecom.infobip\u003c/groupId\u003e\n   \u003cartifactId\u003einfobip-spring-data-jpa-querydsl-boot-starter\u003c/artifactId\u003e\n   \u003cversion\u003e${infobip-spring-data-jpa-querydsl.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nAs this project depends on querydsl-apt with jpa classifier you don't need to set up explicit Maven build phase for Q classes generation.\nFor building Q classes without Maven, make sure your IDE has Annotation processing enabled.\n\n2. Refactor repository interfaces to either use new base repository or fragments approach:\n\n* new base repository approach:\n\n```java\ninterface TRepository extends ExtendedQueryDslJpaRepository\u003cT, ID\u003e {\n}\n```\n\n* fragments:\n\n```java\ninterface TRepository extends JpaRepository\u003cT, ID\u003e, QuerydslPredicateExecutor\u003cT\u003e, QuerydslJpaFragment\u003cT\u003e {\n}\n```\n\n3. Done\n\nIf you need other features from `@EnableJpaRepositories` you can use:\n\n```\n@EnableJpaRepositories(repositoryFactoryBeanClass = ExtendedQuerydslJpaRepositoryFactoryBean.class)\n```\n\n\u003ca id=\"JPAFeaturesAndExamples\"\u003e\u003c/a\u003e\n###  Features and examples:\n\nAll examples have corresponding tests in the project and can be found [here](infobip-spring-data-jpa-querydsl/src/test/java/com/infobip/spring/data/jpa).\n\n\u003ca id=\"JPANativeQueriesWithQuerydsl\"\u003e\u003c/a\u003e\n###  Native queries with Querydsl:\n\nExample which uses union clause (unions aren't available in JPA):\n\n```\nList\u003cPerson\u003e actual = repository.jpaSqlQuery(query -\u003e query\n        .union(\n                repository.jpaSqlSubQuery(subQuery -\u003e\n                                                  subQuery.select(person)\n                                                          .from(person)\n                                                          .where(person.firstName.like(\"John\"))),\n                repository.jpaSqlSubQuery(subQuery -\u003e\n                                                  subQuery.select(person)\n                                                          .from(person)\n                                                          .where(person.firstName.like(\"Jan%\")))\n        )\n        .orderBy(person.firstName.asc(), person.lastName.asc())\n        .fetch()\n);\n```\n\n\u003ca id=\"JPAProjections\"\u003e\u003c/a\u003e\n###  Projections\n\nFor examples how to construct projections refer to the official documentation - [section result handling](http://www.querydsl.com/static/querydsl/latest/reference/html_single/#result_handling).\n\nHere is an example that uses constructor:\n\n```$xslt\npublic record PersonProjection(\n    String firstName,\n    String lastName\n) {\n\n}\n...\n \nList\u003cPersonProjection\u003e actual = repository.query(query -\u003e query\n                                          .select(Projections.constructor(PersonProjection.class, person.firstName, person.lastName))\n                                          .from(person)\n                                          .fetch());\n```\n\n\u003ca id=\"JPAQuery\"\u003e\u003c/a\u003e\n###  Query\n\nQuery exposes full API of JPAQuery ([QueryDslPredicateExecutor](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QuerydslPredicateExecutor.html) \nonly exposes where clause (Predicate) and order clause (OrderSpecifier)).\n\nThis along with Querydsl 4 API improvement can lead to code that looks more like regular SQL:\n\n```\nList\u003cPerson\u003e actual = repository.query(query -\u003e query\n        .select(person)\n        .from(person)\n        .where(person.firstName.in(\"John\", \"Jane\"))\n        .orderBy(person.firstName.asc(), person.lastName.asc())\n        .limit(1)\n        .offset(1)\n        .fetch());\n```\n\n\u003ca id=\"JPAUpdate\"\u003e\u003c/a\u003e\n###  Update\n\n```\nrepository.update(query -\u003e query\n        .set(person.firstName, \"John\")\n        .where(person.firstName.eq(\"Johny\"))\n        .execute());\n```\n\n\u003ca id=\"JPADelete\"\u003e\u003c/a\u003e\n###  Delete\n\n```\nlong numberOfAffectedRows = repository.deleteWhere(person.firstName.like(\"John%\"));\n```\n\n\u003ca id=\"JPAListInsteadOfIterableReturnType\"\u003e\u003c/a\u003e\n###  List instead of Iterable return type\n\n[QueryDslPredicateExecutor](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QuerydslPredicateExecutor.html)#findAll methods return Iterable which can be cumbersome to use. \nThose methods were overridden and now return a List which is easier to use and is easier to convert to Stream.\n\n\u003ca id=\"JPATransactionalSupport\"\u003e\u003c/a\u003e\n###  Transactional support\n\nQuery execution is always done inside the repository implementation (loan pattern) in a transaction so transactions don't have to be \nhandled manually (like they do if you are manually managing JPAQuery and other Querydsl constructs).\n\n\u003ca id=\"JPAStoredProcedureBuilder\"\u003e\u003c/a\u003e\n###  Stored procedure builder\n\nJPA support for stored procedures is quite cumbersome and it also requires a reference to EntityManager which leads to code like this:\n\n```\n@PersistenceContext\nprivate EntityManager entityManager\n...\n \n@SuppressWarnings(\"unchecked\")\npublic List\u003cPerson\u003e delete(Person personToDelete) {\n    return (List\u003cPerson\u003e) entityManager\n            .createStoredProcedureQuery(\"Person_Delete\")\n            .registerStoredProcedureParameter(\"FirstName\", String.class, ParameterMode.IN)\n            .registerStoredProcedureParameter(\"LastName\", String.class, ParameterMode.IN)\n            .setParameter(\"FirstName\", personToDelete.getFirstName())\n            .setParameter(\"LastName\", personToDelete.getLastName())\n            .getResultList(); // returns untyped List =\u003e unchecked\n}\n```\n\nFor this case, executeStoredProcedure method was added which supports Q class attributes:\n\n```\npublic List\u003cPerson\u003e delete(Person personToDelete) {\n    return repository.executeStoredProcedure(\n            \"Person_Delete\",\n            builder -\u003e builder.addInParameter(person.firstName, personToDelete.getFirstName())\n                              .addInParameter(person.lastName, personToDelete.getLastName())\n                              .getResultList());\n}\n```\n\n\u003ca id=\"JPAStreaming\"\u003e\u003c/a\u003e\n###  Streaming\n\n`streamAll` is a new method added to repository for more convenient use.\n\n```\n@Transactional\npublic void transactionalAnnotatedMethodRequiredForConsumingStream() {\n   try (Stream\u003cPerson\u003e stream = repository.streamAll()) {\n      // use stream\n   }\n}\n```\n\n\u003ca id=\"JPAExtension\"\u003e\u003c/a\u003e\n###  Extension:\n\nTo create a custom base repository interface you'll need to create:\n*  custom base interface\n*  custom annotation for enabling\n*  custom factory bean class and potentially factory class depending on requirements\n\nTake a look at [extension package in tests](infobip-spring-data-jpa-querydsl/src/test/java/com/infobip/spring/data/jpa/extension) as an example on how this can be achieved.\n\n\u003ca id=\"AnnotationProcessor\"\u003e\u003c/a\u003e\n##  Annotation processor\n\nAnnotation processor [infobip-spring-data-jdbc-annotation-processor](infobip-spring-data-jdbc-annotation-processor) is used by R2DBC and JDBC modules to generate Querydsl Q classes.\nWithout annotation processor this process can be quite cumbersome as connecting to database would be required during the build phase.\n\nAnnotation processor generates Q classes for all classes that have `@Id` annotated fields. \nReason 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](https://docs.spring.io/spring-data/jdbc/docs/current/reference/html/#jdbc.entity-persistence.id-generation):\n\u003e Spring Data JDBC uses the ID to identify entities. The ID of an entity must be annotated with Spring Data’s @Id annotation.\n\nCurrent implementation of Annotation Processor uses pascal casing based naming strategy for table and column names.\n\nTo customize this behavior across whole project add following annotation to one of your classes:\n```\n@ProjectTableCaseFormat(CaseFormat.LOWER_UNDERSCORE)\n@ProjectColumnCaseFormat(CaseFormat.LOWER_UNDERSCORE)\npublic class SomeClassOnCompilationPath {\n...\n}\n```\n`SomeClassOnCompilationPath` can be any class that is being compiled in the project. \n\nNote that for customizing single table/column mapping [Table](https://docs.spring.io/spring-data/jdbc/docs/2.1.8/api/org/springframework/data/relational/core/mapping/Table.html) and [Column](https://docs.spring.io/spring-data/jdbc/docs/2.1.8/api/org/springframework/data/relational/core/mapping/Column.html) can be used.\n\nIf this behavior needs to be changed across multiple projects, or you simply wish to customize annotation processor following steps can be taken:\n1. create a new Maven module (or a Maven project if you want to reuse across multiple projects)\n1. add dependency to `infobip-spring-data-jdbc-annotation-processor-common`\n1. create implementation of `com.querydsl.sql.codegen.NamingStrategy`\n1. create annotation processor that extends the base one:\n```java\n@AutoService(Processor.class)\npublic class CustomSpringDataJdbcAnnotationProcessor extends SpringDataJdbcAnnotationProcessorBase {\n\n    public CustomSpringDataJdbcAnnotationProcessor() {\n        super(CustomNamingStrategy.class);\n    }\n}\n```\n1. in module (or project) that needs to use this new processor exclude the default annotation processor dependency and include your own:\n```xml\n\u003cdependency\u003e\n\t\u003cgroupId\u003ecom.infobip\u003c/groupId\u003e\n    \u003c!-- infobip-spring-data-jdbc-querydsl-boot-starter is used as an example here, same pattern applies for other modules --\u003e \n\t\u003cartifactId\u003einfobip-spring-data-jdbc-querydsl-boot-starter\u003c/artifactId\u003e\n\t\u003cversion\u003e${infobip-spring-data-jdbc-querydsl-boot-starter.version}\u003c/version\u003e\n\t\u003cexclusions\u003e\n\t\t\u003cexclusion\u003e\n\t\t\t\u003cgroupId\u003ecom.infobip\u003c/groupId\u003e\n\t\t\t\u003cartifactId\u003einfobip-spring-data-jdbc-annotation-processor\u003c/artifactId\u003e\n\t\t\u003c/exclusion\u003e\n\t\u003c/exclusions\u003e\n\u003c/dependency\u003e\n\n\u003c!-- include dependency to custom annotation processor --\u003e\n```\n\n[infobip-spring-data-jdbc-annotation-processor](infobip-spring-data-jdbc-annotation-processor) can be used as an example codebase for custom annotation processor. \nIt includes tests that can be used for custom annotation processor as well.\n\nIn 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](https://github.com/infobip/infobip-spring-data-querydsl/commit/9b41403bdea38672caa5a4c57427cdcc2ef8c2a7#diff-ca2587b532ca6c66340cb5032feded4e6b090942f295556d27b480a81d417ba2)).\n\n\n\u003ca id=\"FurtherReading\"\u003e\u003c/a\u003e\n##  Further reading\n\n- [Querydsl documentation](http://www.querydsl.com/static/querydsl/latest/reference/html_single/)\n- [Atlassian Querydsl examples](https://bitbucket.org/atlassian/querydsl-examples)\n- [Querydsl google group](https://groups.google.com/forum/#!forum/querydsl)\n- [Spring Data JPA documentation](http://docs.spring.io/spring-data/jpa/docs/current/reference/html/)\n- [QueryDSL-EntityQL](https://github.com/eXsio/querydsl-entityql)\n\n\u003ca id=\"RunningTests\"\u003e\u003c/a\u003e\n##  Running tests\n\nTo run tests you need to have docker installed.\nContainers are automatically started using [testcontainers](https://github.com/infobip/infobip-testcontainers-spring-boot-starter).\n\n\u003ca id=\"Contributing\"\u003e\u003c/a\u003e\n##  Contributing\n\nIf you have an idea for a new feature or want to report a bug please use the issue tracker.\n\nPull requests are welcome!\n\n\u003ca id=\"License\"\u003e\u003c/a\u003e\n##  License\n\nThis library is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfobip%2Finfobip-spring-data-querydsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfobip%2Finfobip-spring-data-querydsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfobip%2Finfobip-spring-data-querydsl/lists"}