Home > database >  How does hibernate change a val in a kotlin class?
How does hibernate change a val in a kotlin class?

Time:11-19

In the following code, how can hibernate change the value of the val member id? Even the reference to the object is a val so I cannot see how a different object might be being substituted.

import jakarta.persistence.*
import java.util.UUID

@Entity
class Bar (val v: Int = 0) {
  @Id @GeneratedValue @Column(columnDefinition="UUID default gen_random_uuid()")
  val id = UUID.fromString("00000000-0000-0000-0000-000000000000")
}

fun main () {
  val emf = HibernatePersistenceProvider().createContainerEntityManagerFactory(
    MyPersistenceUnitInfo(), Properties()
  )
  emf.createEntityManager().let { em ->
    em.transaction.begin()
    val b = Bar(7)
    println(b.id)  // prints 00000000-0000-0000-0000-000000000000
    em.persist(b)
    println(b.id)  // prints 82a7bc5a-f92d-4d7f-872a-3eb3ba7a5541
    em.transaction.commit()
    em.close()
  }
}

I am indeed using the JPA plugin in my build.gradle.kts as follows:

plugins {
    kotlin("jvm") version "latest.release"
    kotlin("plugin.serialization") version "latest.release"
    id("com.google.cloud.tools.jib") version "latest.release"
    id("com.google.cloud.artifactregistry.gradle-plugin") version "latest.release"
    id("org.jetbrains.kotlin.plugin.jpa") version "latest.release"
    application
}

But I am not using the "all open" plugin, if that matters.

Finally I'm still confused how val id within a val b references changes due the em.persist(b) call as shown by the two printlns

CodePudding user response:

If you disassemble the compiled class Bar with javap you will see that the signature is:

public final class foo.Bar {
   private final int v;
   private final java.util.UUID id;
   public foo.Bar(int);
   public foo.Bar(int, int, kotlin.jvm.internal.DefaultConstructorMarker);
   public final int getV();
   public final java.util.UUID getId();
   public foo.Bar();
}

... so your assumptions on the generated class are correct. But final fields are not protected from modification with reflection, so Hibernate can change the value of the id field anyhow...

If you set a breakpoint in the java.lang.reflect.Field.set(Object obj, Object value) method and run your test with the debugger, you will see the call and the access path that Hibernate uses...

  • Related