Kotlin JPA pattern
The problem
Kotlin does many wonderful things for you. For example, the data classes
            create helpful constructors, and automatically implement
            equals and hashCode in a reasonable
            way.
Similarly, JPA works magic—expecially in the context of Spring Data.
So how do I test that my Kotlin entity is correctly annotated for JPA? The simplest thing would be a "round trip" test: create an entity, save it to a database, read it back, and confirm the object has the same values. Let's start with a simple entity, and the simplest possible test:
@Entity
data class Greeting(
        val content: String,
        @Id @GeneratedValue
        val: Int id = 0)
        @DataJpaTest
@ExtendWith(SpringExtension::class)
internal class GreetingRepositoryIT(
        @Autowired val repository: GreetingRepository,
        @Autowired val entityManager: EntityManager) {
    @DisplayName("WHEN saving a greeting properly annotated")
    @Nested
    inner class Roundtrip {
        @Test
        fun `THEN is can be read back`() {
            val greeting = Greeting("Hello, world!")
            repository.saveAndFlush(greeting.copy())
            entityManager.clear()
            assertThat(repository.findOne(Example.of(greeting)).get())
                    .isEqualTo(greeting)
        }
    }
}
        Some things to note:
- To ensure we truly read from the database, and not the entity manager's in-memory cache, flush the object and clear the cache.
- As saving also updates the entity's id field, save a copy, so our original is untouched.
- Be careful to use saveAndFlushon the Spring repository, rather thanentityManager.flush(), which requires a transaction, and would add unneeded complexity to the test.
But this test fails! Why?
The unsaved entity (remember, we made a copy to keep the
            original pristine) does not have a value for id,
            and the entity read back does. Hence, the automatically
            generated equals method says the two objects
            differ because of id (null in the
            original vs some value from the database).
Further, the Spring Data QBE (QBE) search
            for our entity includes id in the search criteria. Even
            changing equals would not address this.
What to do?
The solution
It turns out we need to address two issues:
- The generated equalstakes id into account, but we are only interested in the data values, not the database administrivia.
- The test look up in the database includes the SQL
                id column. Although we could try
                repository.getOne(saved.id), I'd prefer to keep using QBE, if the code is reasonable.
To address equals, we can rely on 
            an interesting fact about Kotlin data classes: only
            default constructor parameters are used, not properties in the
            class body, when generating equals and
            hashCode. Hence, I write the entity like this,
            and equals does not include id, while
            JPA is stil happy as it relies on getter reflection:
@Entity
data class Greeting(
        val content: String) {
    @Id
    @GeneratedValue
    val id = 0
}
        To address the test, we can ask QBE to ignore id when fetching our saved entity back from the database:
@DataJpaTest
@ExtendWith(SpringExtension::class)
internal class GreetingRepositoryIT(
        @Autowired val repository: GreetingRepository,
        @Autowired val entityManager: EntityManager) {
    @DisplayName("WHEN saving a greeting properly annotated")
    @Nested
    inner class Roundtrip {
        @Test
        fun `THEN is can be read back`() {
            val greeting = Greeting("Hello, world!")
            repository.saveAndFlush(greeting.copy())
            entityManager.clear()
            val matcher = ExampleMatcher.matching()
                    .withIgnoreNullValues()
                    .withIgnorePaths("id")
            val example = Example.of(greeting, matcher);
            assertThat(repository.findOne(example).get()).isEqualTo(greeting)
        }
    }
}
        In a larger database, I'd look into providing an
            entity.asExample() to avoid duplicating
            ExampleMatcher in each test.
Java approach
The closest to Kotlin's data classes for JPA entities is Lombok's
            @Data annotation, together with
            @EqualsAndHashCode(exclude = "id") and
            @Builder(toBuilder = true), however the
            expressiveness is lower, and clutter higher.
The test would
            be largely the same modulo language, replacing
            greeting.copy() with
            greeting.toBuilder().build(). Alternatively,
            rather than a QBE matcher, one could write
            greeting.toBuilder().id(null).build().
This last fact leads to an alternative with Kotlin: include
            id in the data class' default constructor, and in
            the test compare the QBE result as
            findOne(example).get().copy(id = null) without
            a matcher.
Conclusion
What Kotlin JPA patterns have you discovered?
 
