Minimales Beispiel einer Maven-Kotlin-Querydsl-Integration

Veröffentlicht

Inhalt

QueryDSL ist ein praktisches Werkzeug für das Vereinfachen von Datenbankzugriffen in JVM-Programmen. In diesem Beispiel habe ich QueryDSL in ein Kotlin-basiertes Spring Boot Projekt mit Maven eingebaut.

Der Code ist verfügbar auf Github

Vorraussetzungen

Für dieses Beispiel habe ich ein Projekt mithilfe des Spring Initilizr generiert und Kotlin und JPA Module ausgewählt.

Füge die aktuelle QueryDSL Bibliothek zur pom.xml hinzu.

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
    <version>4.3.1</version>
</dependency>

Das Entity

Ich brauchte ein simples Entity welches ich zum Testen der Generierung der Q-Klassen von QueryDSL verwende. Dafür habe ich den Kotlin data-class Syntax verwendet um ein simples JPA kompatibles Entity mit wenig Zeilen zu erstellen.

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id

@Entity
data class TestEntity (
        val name: String,
        val value: Double
) {
        @Id @GeneratedValue
        val id: Int? = null
}

Das Repository

Spring Data bietet einfache Möglichkeiten zum Zugriff auf Datenbank-Entities via Repositories, die dann auch QueryDSL Support haben.

import org.springframework.data.querydsl.QuerydslPredicateExecutor
import org.springframework.data.repository.CrudRepository

interface TestEntityRepository:
        CrudRepository<TestEntity, Int>,
        QuerydslPredicateExecutor<TestEntity>

Der QuerydslPredicateExecutor definiert welches Entity wir benutzen um unsere fortgeschrittenen Datenbankabfragen zu formulieren.

Die Konsumenten

Ich habe einen einfachen Service erstellt in welchen das Repository mit Dependency-Injection injiziert wird. Der Service wird nicht benutzt sondern dient dazu beim Kompilieren eine Verwendung der Q-Klassen zu generieren. Wenn die Q-Klassen zur Zeit des Kompilierens nicht generiert waren gibt es einen Fehler. Normalerweise würde erst der Test die Q-Klassen verwenden und es könnte sein dass die Q-Klassen-Generierung zwischen die compile und test-compile Maven-Phasen rutschen, das wiederum zurfolge hätte dass die Klassen zur normalen Kompilierzeit nicht zur Verfügung stehen.

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()
    }
}

Zusätzlich habe ich einen Test erstellt der den QueryDSL Support auf einer H2-Datenbank testet.

import junit.framework.TestCase.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner

@RunWith(SpringRunner::class)
@SpringBootTest
class TestEntityRepositoryTest {
    @Autowired
    private lateinit var testEntityRepository: TestEntityRepository

    @Before
    fun setup() {
        testEntityRepository.save(TestEntity("test", 8.0))
    }

    @Test
    fun test() {
        val testEntities = testEntityRepository.findAll()
        assertEquals(1, testEntities.count())
    }
}

Änderungen am Maven-Skript

Ich musste die Maven-Plugins so anpassen, dass der Kotlin Annotation Processor mit QueryDSL die Q-Klassen generiert bevor der Rest des Programms kompiliert wird.

<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>
        </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>
                    <sourceDirs>
                        <sourceDir>src/main/kotlin</sourceDir>
                    </sourceDirs>
                    <annotationProcessorPaths>
                        <annotationProcessorPath>
                            <groupId>com.querydsl</groupId>
                            <artifactId>querydsl-apt</artifactId>
                            <version>${querydsl.version}</version>
                            <classifier>jpa</classifier>
                        </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>

Das wars! Nach diesen Änderungen kann man QueryDSL mit Spring-Data-Repositories benutzen. Der Test sichert die Integration ab und bietet ein kleines Beispiel der Benutzung.