Contents
QueryDSL is a neat and practical tool for easy database-access. In this little example I integrated it into a Kotlin-based Spring Boot project built with Maven.
You can look at the code on Github
Requirements
For this example I created a project with Spring Initializr and chose Kotlin support and the JPA dependency. The current example uses Spring Boot 4.1, Kotlin 2.4, Java 17+, and the maintained OpenFeign QueryDSL fork.
Add the current QueryDSL library to your pom.xml. The version properties used by the example are:
<properties>
<java.version>17</java.version>
<kotlin.version>2.4.21</kotlin.version>
<querydsl.version>5.1.0</querydsl.version>
<openfeign.querydsl.version>7.7</openfeign.querydsl.version>
</properties>
The QueryDSL dependency itself is:
<dependency>
<groupId>io.github.openfeign.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${openfeign.querydsl.version}</version>
</dependency>
The Entity
I just required a simple entity to test the generation of Q-classes by QueryDSL. I used Kotlins data class syntax to create a jpa-compatible entity with a few lines.
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
@Entity
data class TestEntity (
val name: String,
val exampleValue: Double
) {
@Id @GeneratedValue
val id: Int? = null
}
The Repository
Spring offers easy access to database entities via repositories, this includes QueryDSL Support.
import com.felixzett.mmkqe.entity.TestEntity
import org.springframework.data.querydsl.QuerydslPredicateExecutor
import org.springframework.data.repository.CrudRepository
interface TestEntityRepository:
CrudRepository<TestEntity, Int>,
QuerydslPredicateExecutor<TestEntity>
The QuerydslPredicateExecutor defines which entities predicate we can use to structure advanced queries.
The Consumers
I created a simple service in which the repository is injected. The main reason for the service is testing if the Q-classes are generated before kotlin classes are processed. If this would not be the case we could not use Q-classes except in test-code.
import com.felixzett.mmkqe.entity.QTestEntity
import com.felixzett.mmkqe.entity.TestEntity
import com.felixzett.mmkqe.repository.TestEntityRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
@Service
class TestEntityService @Autowired constructor(
private val testEntityRepository: TestEntityRepository
){
fun getTestEntityByName(name: String): TestEntity? {
return testEntityRepository.findOne(
QTestEntity.testEntity.name.eq(name)
).get()
}
}
Additionally I created a test that uses the QueryDSL support so that I can be sure it works with the default H2 Database Spring-Boot provides.
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest
class TestEntityRepositoryTest {
@Autowired
private lateinit var testEntityRepository: TestEntityRepository
@BeforeEach
fun setup() {
testEntityRepository.save(TestEntity("test", 8.0))
}
@Test
fun test() {
val testEntities = testEntityRepository.findAll()
assertEquals(1, testEntities.count())
}
}
Build script changes
I needed to change the build plugins, so that the Kotlin Annotation Processor in conjunction with QueryDSL creates the needed Q-classes before the sources are compiled
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<compilerPlugins>
<plugin>jpa</plugin>
<plugin>spring</plugin>
</compilerPlugins>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<jvmTarget>${java.version}</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>kapt</id>
<phase>generate-sources</phase>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<includeCompileClasspath>false</includeCompileClasspath>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>io.github.openfeign.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${openfeign.querydsl.version}</version>
<classifier>jpa</classifier>
</annotationProcessorPath>
<annotationProcessorPath>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
<sourceDir>target/generated-sources/kapt/test</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
Thats it! After all these changes I could use QueryDSL with my repositories. The test ensures the integration and has a little example on how to use it.