I’m still learning Kotlin, so I didn’t know this, but Kotlin has annotation use-site targets, like @get
, @set
, and @field
.
I wanted to add timestamps via Hibernate, and they weren’t working. When I was trying to add a @(org.hibernate.annotations.)CreationTimestamp
annotation and various other annotations without use-site targets, none of them were working. Couldn’t figure out why. Turns out, when you’re making a data class, you have to specify whether those annotations apply to getters, setters, fields, constructor parameters, etc.
A Kotlin data class that looks like this:
package com.example.test import javax.persistence.* import java.util.UUID import org.hibernate.annotations.CreationTimestamp import org.hibernate.annotations.UpdateTimestamp @Entity data class UselessThing( @Id @GeneratedValue(strategy = GenerationType.AUTO) val id: UUID?, val name: String = "", @CreationTimestamp @Column(updatable = false) val createdDate: Date = Date(), @UpdateTimestamp val modifiedDate: Date = Date() )
Would probably translate to something like this in Java:
// imports omitted public class UselessThing { private UUID id; private String name; private Date createdDate = Date(); private Date modifiedDate = Date(); // This is a constructor. public UselessThing( @Id @GeneratedValue(strategy = GenerationType.AUTO) UUID id, String name, @CreationTimestamp @Column(updatable = false) Date createdDate, @UpdateTimestamp Date modifiedDate) { this.id = id; this.name = name; this.createdDate = createdDate; this.modifiedDate = modifiedDate; } /* getters, setters, copy methods and whatever else Kotlin data classes make */ }
Instead, You’d create a Kotlin data class that looks like this:
package com.example.test import javax.persistence.* import java.util.UUID import org.hibernate.annotations.CreationTimestamp import org.hibernate.annotations.UpdateTimestamp @Entity data class UselessThing( @field: Id @field: GeneratedValue(strategy = GenerationType.AUTO) val id: UUID?, val name: String = "", @field: CreationTimestamp @field: Column(updatable = false) val createdDate: Date = Date(), @field: UpdateTimestamp val modifiedDate: Date = Date() )
The latter, I’m guessing, probably translates to something roughly like this in Java:
// imports omitted public class UselessThing { @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String name; @CreationTimestamp @Column(updatable = false) private Date createdDate = Date(); @UpdateTimestamp private Date modifiedDate = Date(); public UselessThing(UUID id, String name, Date createdDate, Date modifiedDate) { this.id = id; this.name = name; this.createdDate = createdDate; this.modifiedDate = modifiedDate; } /* getters, setters, copy methods and whatever else Kotlin data classes make */ }
The latter, unlike the former, also works.
I encountered another gotcha with timestamps. When the client tried updating a UselessThing (via the .copy()
method to create a new object with updated properties and JpaRepository’s save()
method to persist the object) and didn’t specify a createdDate, the created_date column in the database would get updated every time the entity was updated.
Or something like that. Going over that again now, there must have been something else going on.
Anyway, adding the @Column(updatable = false)
annotation fixed that issue.