12

What is "the kotlin way" to define JPA entity ID?

@Entity
data class User (
        @Id @GeneratedValue
        var id: Long? = null,
        ...
)

Or is there any better one to avoid nullable id?

Ondřej Míchal
  • 573
  • 2
  • 5
  • 14

2 Answers2

18

You can use a 0 value rather than a null value.

@Entity
data class User (
        @Id @GeneratedValue
        var id: Long = 0,
        ...
)

Autogeneration should still find the next sequence.

Kotlin compiles to Java, which has both, a primitive type long and a Class Long

As per the Java Persistence Specification in section 11.1.21 Id Annotation both can be used for the Id:

The field or property to which the Id annotation is applied should be one of the following types: any Java primitive type; any primitive wrapper type; java.lang.String; java.util.Date; java.sql.Date; java.math.BigDecimal; java.math.BigInteger[109].

There is an advantage in using the Class over the primitive, as null has a more unambiguous meaning. But from the spec both are possible and you have to decide weather you favor Kotlins nullsafety over the the jpa style or the other way around.

phisch
  • 4,571
  • 2
  • 34
  • 52
  • Is that a rule of thumb without any side effects or disadvantages? – Ondřej Míchal Apr 11 '18 at 13:44
  • As far as I know this is identical to a java primitive which can not be null. The default for long is 0. – phisch Apr 11 '18 at 13:49
  • Did the solution work for you or are there still open points to your question? – phisch Apr 17 '18 at 20:30
  • 4
    But in https://stackoverflow.com/questions/20421735/jpa-entity-id-long-or-long and https://stackoverflow.com/questions/3535791/primitive-or-wrapper-for-hibernate-primary-keys/3537407#3537407 people tend to prefer null variants. So is this really the _preferred_ way or the _possible_ way? – Ondřej Míchal Apr 19 '18 at 06:06
  • Nice answer. FYI, for people using UUID datatype instead of Long datatype can use `UUID(0,0)` in kotlin to initialize the id variable with dummy value which will anyhave be overrridden by autogenerator when saving the object to database – firstpostcommenter Mar 15 '22 at 20:38
0

Usually, data class is useful to ruturn more that one result from a method , but not for entities (just my opinion).

Sometimes it is not a good idea to set a default value for the id field.

After some time experimenting with Kotlin and entities (actually, with documents for MongoDb, but anyway it has id), Looks like the better way is to use lateinit var. You can create the top class of entity hierarchy:

open class Identifiable {
    lateinit var id: Long // or String or UUID

    //explicitly define equals & hash code here
}

But be careful, for equals, hashcode and if you want to provide toString method in heirs, then it is a good idea to provide extra nullable field, something like:

open class Identifiable {
    lateinit var id: Long // or String or UUID

    val nullableId: Long?
        get() {
            return if(this::id.isInitialized) id else null
        }
    //explicitly define equals & hash code here with nullableId
}

class User {
    override fun toString() = "User(id=${nullableId})"
}

In this case, you will avoid an exception when you will try to log your created but not saved in DB entity

Ivan Osipov
  • 726
  • 8
  • 6