spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.22k stars 40.47k forks source link

After 3.2.0 update, the querydsl embedded column type comparison operation is not possible. #38527

Closed phjppo0918 closed 9 months ago

phjppo0918 commented 9 months ago

After 3.2.0 update, the querydsl embedded column type comparison operation is not possible.

In version 3.1.4, it worked without any problems, but the equals operation for embedded columns does not work properly after the 3.2.0 update.

Currently operating based on kotlin - JVM17.

The error code is as follows.

java.lang.IllegalArgumentException: org.hibernate.query.SemanticException: Cannot compare tuples of different lengths

    at org.hibernate.internal.ExceptionConverterImpl.convert(exceptionconverterimpl.java:143)
    at org.hibernate.internal.ExceptionConverterImpl.convert(exceptionconverterimpl.java:167)
    at org.hibernate.internal.ExceptionConverterImpl.convert(exceptionconverterimpl.java:173)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(abstractsharedsessioncontract.java:802)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(abstractsharedsessioncontract.java:707)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(abstractsharedsessioncontract.java:132)
    at java.base/java.lang.reflect.Method.invoke(method.java:568)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(sharedentitymanagercreator.java:311)
    at jdk.proxy2/jdk.proxy2.$Proxy233.createQuery(Unknown Source)
    at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(abstractjpaquery.java:132)
    at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(abstractjpaquery.java:125)
    at com.querydsl.jpa.impl.AbstractJPAQuery.fetch(abstractjpaquery.java:242)
    at site.qbox.qboxserver.domain.question.query.QuestionDao.findAllBy(QuestionDao.kt:26)
    at java.base/java.lang.reflect.Method.invoke(method.java:568)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(aoputils.java:352)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(reflectivemethodinvocation.java:196)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(reflectivemethodinvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(cglibaopproxy.java:765)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(transactioninterceptor.java:123)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(transactionaspectsupport.java:385)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(transactioninterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(reflectivemethodinvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(cglibaopproxy.java:765)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(cglibaopproxy.java:717)
    at site.qbox.qboxserver.domain.question.query.QuestionDao$$SpringCGLIB$$0.findAllBy(<generated>)
    at site.qbox.qboxserver.domain.question.query.QuestionDaoTest$1$2.invokeSuspend(QuestionDaoTest.kt:58)
    at site.qbox.qboxserver.domain.question.query.QuestionDaoTest$1$2.invoke(QuestionDaoTest.kt)
    at site.qbox.qboxserver.domain.question.query.QuestionDaoTest$1$2.invoke(QuestionDaoTest.kt)
    at io.kotest.core.spec.style.scopes.DescribeSpecContainerScope$it$3.invokeSuspend(DescribeSpecContainerScope.kt:113)
    at io.kotest.core.spec.style.scopes.DescribeSpecContainerScope$it$3.invoke(DescribeSpecContainerScope.kt)
    at io.kotest.core.spec.style.scopes.DescribeSpecContainerScope$it$3.invoke(DescribeSpecContainerScope.kt)
    at io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invokeSuspend(TestCaseExecutor.kt:88)
    at io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invoke(TestCaseExecutor.kt)
    at io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invoke(TestCaseExecutor.kt)
    at io.kotest.engine.test.interceptors.CoroutineDebugProbeInterceptor.intercept(CoroutineDebugProbeInterceptor.kt:29)
    at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:97)
    at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
    at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
    ....mores

Build.gradle.kts is as follows.


plugins {
    id("org.springframework.boot") version "3.2.0"
    id("io.spring.dependency-management") version "1.1.4"
    id("org.jetbrains.kotlinx.kover") version "0.7.3"
    id("org.asciidoctor.jvm.convert") version "3.3.2"
    kotlin("jvm") version "1.9.20"
    kotlin("plugin.spring") version "1.9.20"
    kotlin("plugin.jpa") version "1.9.20"
    kotlin("kapt") version "1.9.20"
}

group = "site.q-box"
version = "0.0.1-SNAPSHOT"

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}
extra["snippetsDir"] = file("build/generated-snippets")

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-validation")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-mail")
    implementation("com.github.maricn:logback-slack-appender:1.6.1")
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
    implementation("org.springframework.boot:spring-boot-starter-data-redis")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    developmentOnly("org.springframework.boot:spring-boot-docker-compose")

    //kotlin
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")

    //database
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    runtimeOnly("com.mysql:mysql-connector-j")
    testRuntimeOnly("com.h2database:h2")

    //querydsl
    implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta")
    kapt("com.querydsl:querydsl-apt:5.0.0:jakarta")

    //security
    implementation("org.springframework.boot:spring-boot-starter-security")
    testImplementation("org.springframework.security:spring-security-test")

    //test container
    testImplementation("org.springframework.boot:spring-boot-testcontainers")
    testImplementation("org.testcontainers:junit-jupiter")
    testImplementation("com.redis.testcontainers:testcontainers-redis-junit:1.6.4")

    //monitoring
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    runtimeOnly("io.micrometer:micrometer-registry-prometheus")

    // rest docs
    testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
    testImplementation("org.springframework.restdocs:spring-restdocs-asciidoctor")

    //kotest
    testImplementation("io.kotest:kotest-runner-junit5:5.6.2")
    testImplementation("io.kotest:kotest-assertions-core:5.6.2")
    testImplementation("io.kotest.extensions:kotest-extensions-spring:1.1.3")

    //mockkk
    testImplementation("io.mockk:mockk:1.13.8")
    testImplementation("com.ninja-squad:springmockk:4.0.2")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs += "-Xjsr305=strict"
        jvmTarget = "17"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

//docs setting
tasks {
    val snippetsDir = file("$buildDir/generated-snippets")

    clean {
        delete("src/main/resources/static/docs")
    }

    test {
        useJUnitPlatform()
        systemProperty("org.springframework.restdocs.outputDir", snippetsDir)
        outputs.dir(snippetsDir)
    }

    asciidoctor {
        dependsOn(test)

        attributes(
            mapOf("snippets" to snippetsDir)
        )
        inputs.dir(snippetsDir)

        doFirst {
            delete("src/main/resources/static/docs")
        }
    }

    register<Copy>("copyDocument") {
        dependsOn(asciidoctor)

        destinationDir = file(".")
        from(asciidoctor.get().outputDir) {
            into("src/main/resources/static/docs")
        }
    }

    bootJar {
        dependsOn(asciidoctor)

        from(asciidoctor.get().outputDir) {
            into("BOOT-INF/classes/static/docs")
        }
    }
}

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath("org.jetbrains.kotlinx:kover-gradle-plugin:0.7.3")
    }
}

kover {
    excludeJavaCode()
}

The example entity code is as follows.

@Entity
class Question(
    @Column(nullable = false) var title: String,
    @Lob @Column(nullable = false) var body: String,
    @Embedded val lecture: LectureId,
    @Column(nullable = false) val writerId: String,
    @Id @GeneratedValue val id: Long = 0L,
) : BaseEntity() {
    fun changeContents(title: String, body: String) {
        this.title = title
        this.body = body
    }
}

@Embeddable
data class LectureId(
    val code: String,
    val departId: Long
) : Serializable
wilkinsona commented 9 months ago

This is almost certainly a Hibernate issue. Please try Spring Boot 3.1.x upgraded to Hibernate 6.3.2.Final to see if the problem occurs. You may also want to try Spring Boot 3.2.0 with Hibernate 6.4.0.Final to see if they've already fixed the problem (there is some similarity with HHH-17454).