Minimal Maven Kotlin Querydsl Example

Published

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 Initilizr and chose Kotlin support and the JPA Dependency

Add the current QueryDSL Library to your pom.xml

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
    <version>4.3.1</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 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
}

The Repository

Spring offers easy access to database entities via repositories, this includes QueryDSL Support.

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

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>
        </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>

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.