Home/Blog

How-to: Setting auto-generated Ids manually in Hibernate

03 May 2020 • 2 min read • Hibernate, How-to

In this tutorial, you will learn how to implement a custom IdentifierGenerator to support auto-generated and manually assigned Ids using Hibernate.

Alfredo Jaar - ¿Es usted feliz?, Tate Modern London © matchilling Alfredo Jaar - ¿Es usted feliz?, Tate Modern London © matchilling

When it comes to picking the right id generation strategy for your technical keys, you have primarily two major choices in Hibernate.

  • Use auto-generated values and let Hibernate or the underlying database engine generate those identifiers for you, or
  • Generate all ids yourself with the help of the Assigned class.

However, a third approach which is a mixture of both foresaid strategies is not supported out-of-the-box by Hibernate.

In some scenarios, it might be helpful to let Hibernate or the underlying database engine generate keys most of the time, but also support manual assignments.

Custom IdentifierGenerator

To have the best of both worlds, we only have to provide our own implementation of the IdentifierGenerator interface, which specifies two methods, generate and supportsJdbcBatchInserts.

Here is an example implementation in Kotlin:

package com.matchilling.lib.hibernate

import org.hibernate.engine.spi.SharedSessionContractImplementor
import org.hibernate.id.IdentifierGenerator
import java.io.Serializable
import java.util.*
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.javaType

class UuidGenerator : IdentifierGenerator {

    override fun generate(
            session: SharedSessionContractImplementor?,
            instance: Any?
    ): Serializable {
        val id = instance!!::class.declaredMemberProperties.find {
            it.name == "id" && it.returnType.javaType.typeName == UUID::class.java.canonicalName
        }?.getter?.call(instance)

        return if (id != null) {
            id as UUID
        } else {
            UUID.randomUUID()
        }
    }

    companion object {
        const val NAME = "uuid"
        const val STRATEGY = "com.matchilling.lib.hibernate.UuidGenerator"
    }
}

Usage

With the new UuidGenerator class in place, we can now annotate our entity class accordingly and start using the generator.

@Entity
data class Person(

        @GeneratedValue(generator = UuidGenerator.NAME)
        @GenericGenerator(
            name = UuidGenerator.NAME,
            strategy = UuidGenerator.STRATEGY
        )
        @Id
        val id: UUID?
)

I hope you find this tutorial useful. The implementation of the shown example, as well as the companion unit tests, can be found on GitHub.


Mathias Schilling

I create business impact through code and help organisations become more effective in delivering solutions to their customer's problems. You can find me on Twitter, LinkedIn, GitHub, Reddit, and Last.fm.