3

I have a Kotlin SpringBoot project. It's a relatively simple API that persists data to a Postgres JsonB database. I am using the @TypeDef annotation on my entity class, but after upgrading to SpringBoot Version 3.0 with hibernate-core:6.1.7.Final this annotation is no longer available.

Here is my entity class::

import com.vladmihalcea.hibernate.type.json.JsonBinaryType
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.Table
import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef // not available with latest hibernate-core

import java.io.Serializable
import java.security.SecureRandom
import kotlin.math.abs

@Entity
@Table(name = "myTable")
@TypeDef(name = "jsonb", typeClass = JsonBinaryType::class) // not available :(
data class RecommendationEntity(
  @Id
  open var id: Long = abs(SecureRandom().nextInt().toLong()),
  @Type(type = "jsonb")
  @Column(columnDefinition = "jsonb")
  var data: MyModel
)

data class MyModel(
  // nothing special just a POJO
) : Serializable

And here is my build.gradle.kts::

plugins {
  id("XXXXXXXXXX.gradle-spring-boot") version "5.0.1" // in house plugin thatcopies 3.0.2
  kotlin("jvm") version "1.8.10"
  kotlin("plugin.jpa") version "1.8.20-Beta"
  kotlin("plugin.spring") version "1.8.20-Beta"
}

jacoco.toolVersion = "0.8.8"

configurations {
  testImplementation { exclude(group = "org.junit.vintage") }
}

testSets {
  "testSmoke"()
}

// allOpen {
//  annotations("javax.persistence.Entity")
// }

val springDocVersion = "1.6.14"

dependencies {

  implementation("org.springframework.boot:spring-boot-starter-web")
  implementation("org.springframework.boot:spring-boot-starter-webflux")
  implementation("org.springframework.boot:spring-boot-starter-data-jpa")
  implementation("org.springframework.boot:spring-boot-starter-security")
  implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
  implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
  implementation("org.springframework.boot:spring-boot-starter-actuator:3.0.1")

  implementation("com.deepoove:poi-tl:1.12.1") {
    // exclude apache.xmlgraphics batik due to vulnerabilities when imported with poi-tl
    exclude("org.apache.xmlgraphics", "batik-codec")
    exclude("org.apache.xmlgraphics", "batik-transcoder")
  }
  implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
  implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

  implementation("org.flywaydb:flyway-core:9.11.0")
  implementation("org.postgresql:postgresql:42.5.1")
  
  implementation("org.springdoc:springdoc-openapi-webmvc-core:$springDocVersion")
  implementation("org.springdoc:springdoc-openapi-ui:$springDocVersion")
  implementation("org.springdoc:springdoc-openapi-kotlin:$springDocVersion")
  implementation("org.springdoc:springdoc-openapi-data-rest:$springDocVersion")

  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")

  implementation("com.github.doyaaaaaken:kotlin-csv-jvm:1.7.0")
  implementation("com.vladmihalcea:hibernate-types-52:2.21.1")

//  implementation("org.hibernate:hibernate-core:5.6.3.Final")
  // https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core
  implementation("org.hibernate.orm:hibernate-core:6.1.7.Final")
  testImplementation("org.awaitility:awaitility-kotlin:4.2.0")
  testImplementation("org.mock-server:mockserver-netty:5.15.0")
  testImplementation("io.projectreactor:reactor-test")
  testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test")
  testImplementation("org.junit.jupiter:junit-jupiter-params")

  testImplementation("io.jsonwebtoken:jjwt:0.9.1")
  testImplementation("com.natpryce:hamkrest:1.8.0.1")
  testImplementation("org.flywaydb.flyway-test-extensions:flyway-spring-test:7.0.0")
  
}

java {
  toolchain {
    languageVersion.set(JavaLanguageVersion.of(18))
  }
}

tasks {
  withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
    kotlinOptions {
      jvmTarget = "18"
    }
  }
}

tasks.test {
  finalizedBy(tasks.jacocoTestReport)
}

tasks.jacocoTestReport {
  dependsOn(tasks.test)
  reports {
    xml.required.set(true)
  }
}

val SourceSet.kotlin: SourceDirectorySet
  get() = project.extensions.getByType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension>().sourceSets.getByName(
    name
  ).kotlin

sourceSets {
  create("functional-test") {
    kotlin.srcDirs("src/functional-test")
    compileClasspath += sourceSets["main"].output + configurations["testRuntimeClasspath"]
    runtimeClasspath += output + compileClasspath + sourceSets["test"].runtimeClasspath
  }
}

tasks.withType<Jar>() {
  duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

What I've tried::

  • Using hibernate-core:5.6.3.Final instead of 6.1.7.Final where @TypeDef is available, but that gives the error -
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Class org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider does not implement the requested interface jakarta.persistence.spi.PersistenceProvider

I'm quite stumped on this one, and am beginning to think that SpringBoot V3.0 doesn't support Postgres JsonB Nosql :( Can anybody help me with a solution? Or perhaps confirm whether Postgres JsonB Nosql is indeed not supported in the new SpringBoot version? Thanks

1 Answer 1

12

I found the solution here - https://github.com/vladmihalcea/hypersistence-utils/issues/367#issuecomment-1398737096

I bumped the version of my hibernate-types dependency implementation("com.vladmihalcea:hibernate-types-60:2.21.1")

And made changes to my entity class as recommended -

@Entity
@Table(name = "myTable")
// @TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
data class MyEntity(
  @Id
  open var id: Long = abs(SecureRandom().nextInt().toLong()),
//  @Type(type = "jsonb")
//  @Column(columnDefinition = "jsonb")
  @Type(JsonType::class)
  @Column(columnDefinition = "jsonb")
  var data: MyModel
) 

And now the issue is gone!

Sign up to request clarification or add additional context in comments.

3 Comments

Just a note, It should be .class ex: @Type(JsonType.class)
I followed the solution and it helped. I also have a projection which has JsonNode as the type for the jsonb column, any help on how to make projections work with springboot 3 upgrade?
but why we are depending on third party library?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.