4

The java.util.Date itself is a mutable object. As such even if Kotlin data class (with date field declared val) prevents me from changing the reference I can modify the date object itself to change its value.

Ways I could come up with:

Use normal class, override getter and setter. In each use the clone method to make a copy of given date.

    @Column(name = "db_date")
    private var dbDate: Date? = null
    get() = dbDate?.clone() as Date
    set(date) {
        field = date?.clone() as Date
    }

Also I can't use the copy method of data class since these classes are hibernate entities. So I need to modify them via setters.

The reason I want to use data classes for my entities is because these implement equals and hashcode by default. We had been using lombok in java for this and now convincing team to create these methods is tough. Even if generation happens by IDE its still going to be checked into source control.

So is there any way I could do custom setters on data class logic. Or any way I can generate equals and hashcode for normal classes without checking them in source control?

Edit: In comments it was pointed out to use java.time.Instant which is Immutable. The issue I am faced with is that this is a Hibernate Entity Class and we are using hibernate 3.6. Instant support came in hibernate 5.2 so we are way behind and migration of hibernate will be a heavy task. What I did notice is that kotlin data classes do allow setters and getters just in a different way. Code below:

@Entity
@Table(name = "my_table")
data class MyTable(
    @Id
    @Column(name = "id")
    var id: Long? = null,


    @Column(name = "my_date")
    private var date: Date? = null,


) {
    fun getDate():Date = gradedDate?.clone() as Date
    fun setDate(date: Date?) {
        this.date = date?.clone() as Date
    }
}
faizan
  • 578
  • 5
  • 14
  • 2
    I would just educate the developers and tell them to treat java.util.Date as an immtable class, and thus never, ever call any of its mutating methods. Or better, stop using java.util.Date, and use java.time.Instant instead (or joda time Instant if you're still not on Java 8). – JB Nizet Oct 14 '17 at 10:20
  • That said, the equals() and hashCode() methods generated for data classes are really not what you want for a JPA entity. – JB Nizet Oct 14 '17 at 10:21
  • @JBNizet Not using the Equals and hashcode for JPA, but if these objects are used in collections like Set or Map then I think they should have proper equals and hashcode. Is that right? – faizan Oct 14 '17 at 10:57
  • The key part here is "proper". java.lang.Object already has "proper" equals() and hashCode() implementations. The ones generated for data classes are "proper", too, but don't work the same way. – JB Nizet Oct 14 '17 at 11:01
  • 2
    As Nizet commented, the `java.time.Date` class is part of the troublesome old date-time classes that are now legacy, supplanted by the java.time classes. And the java.time classes are immutable. In particular, `java.time.Instant` replaces `Date`. Convert by calling `Date::toInstant`. For Android, see the ThreeTen-Backport and ThreeTenABP projects. – Basil Bourque Oct 14 '17 at 16:14
  • @BasilBourque I intend to use Instant instead of Date. The issue I am faced with is that this is a Hibernate Entity Class and we are using hibernate 3.6. Instant support came in hibernate 5.2 so we are way behind and migration of hibernate will be a heavy task. What I did notice is that kotlin data classes do allow setters and getters just in a different way. I will add these to the question details in an edit – faizan Oct 15 '17 at 05:32

2 Answers2

0

You can do it with some hack:

@Entity
@Table(name = "my_table")
data class DateWrapper(

        @Id
        @Column(name = "id")
        val id: Long?,

        @Column(name = "my_date")
        private var _date: Date?
) {

    init {
        _date = _date?.clone() as Date
    }

    val date = _date
}
loc
  • 374
  • 3
  • 11
0

Try using java.sql.Date instead