You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至Java 17后QueryDSL Q类无法生成的Gradle项目问题

问题

我正在将一个基于Spring Boot 2.7.5、QueryDSL 5.0、Gradle 7.5的项目从Java 8升级到Java 17。升级前项目运行正常,但升级后编译失败,执行CompileJava时所有Q类引用都提示"找不到符号"。我怀疑这些Q类要么生成路径不对,要么根本没生成。

我用VS Code做IDE,但所有Gradle命令都通过Windows命令行执行。已经查过相关问题但现有方案都不适用。

项目的主启动任务是MyAppRun,执行顺序是preCompile → generateJPA → generateQueryDSL → bootRun,失败发生在bootRun里的compileJava环节。我觉得generateQueryDSL任务需要调整,本人是Gradle和QueryDSL新手,求指导。

以下是原build.gradle文件:

plugins {
    id 'org.springframework.boot' version '2.7.5'
    // id 'net.ltgt.apt' version '0.18'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.mydomain'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

// sourceCompatibility = '17.0.6'

repositories {
    mavenLocal()
    mavenCentral()
    maven { url 'https://repo.spring.io/snapshot' }
    maven { url 'https://repo.spring.io/milestone' }
}

configurations {
    hibernatetool
    querydslapt
}

configurations.implementation.canBeResolved = true

sourceSets {
    main {
        java {
            srcDirs = ['src/main/java']
        }
    }

    generated {
        java {
            srcDir "$projectDir/generated/java"
        }
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
    implementation 'org.springframework.boot:spring-boot-starter-jersey'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.security:spring-security-config:5.6.8'
    implementation 'org.springframework.security:spring-security-core:5.6.8'
    implementation 'org.springframework.security:spring-security-oauth2-resource-server:5.6.8'
    implementation 'org.springframework.security:spring-security-oauth2-jose:5.6.8'
    runtimeOnly group: 'com.nimbusds', name: 'oauth2-oidc-sdk', version: '6.23'
    implementation 'org.hibernate:hibernate-core:5.6.12.Final'
    implementation 'org.hibernate:hibernate-tools:5.6.2.Final'
    implementation 'org.springframework.data:spring-data-rest-hal-explorer'
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.3.2'
    implementation group: 'org.json', name: 'json', version: '20200518'
    runtimeOnly 'org.postgresql:postgresql'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
        exclude group: 'junit', module: 'junit'
    }

    hibernatetool group:'org.hibernate', name:'hibernate-core', version:'5.6.12.Final'
    hibernatetool group:'org.hibernate', name:'hibernate-tools', version:'5.6.2.Final'
    hibernatetool group:'org.hibernate', name:'hibernate-entitymanager', version:'5.6.12.Final'
    hibernatetool group:'org.postgresql', name:'postgresql'

    implementation("com.querydsl:querydsl-core:5.0.0")
    implementation("com.querydsl:querydsl-jpa:5.0.0")
    implementation('com.google.guava:guava:31.1-jre')
    implementation('com.google.code.findbugs:jsr305:3.0.2')
    annotationProcessor("com.querydsl:querydsl-apt:5.0.0:jpa")
    annotationProcessor('org.springframework.boot:spring-boot-starter-data-jpa')
    annotationProcessor('org.springframework.boot:spring-boot-starter-data-rest')
    annotationProcessor('javax.persistence:javax.persistence-api:2.2')
    annotationProcessor('javax.annotation:javax.annotation-api:1.3.2')
    implementation fileTree(include: ['*.jar'], dir: './libs')

    /* annotationProcessor     'com.querydsl:querydsl-apt:4.2.1:jpa'
    annotationProcessor     'org.springframework.boot:spring-boot-starter-data-jpa' // needed because the query dsl annotation processor doesn't recognize javax.persistence.Entity
    compile                 'com.querydsl:querydsl-jpa:4.2.1'*/
    
}

springBoot {
    if (project.hasProperty('import')) {
        mainClass = 'com.mydomain.MyAppservices.ImportApplication'
    } else {
        mainClass = 'com.mydomain.MyAppservices.MyAppApplication'
    }
}

bootRun {
    if (project.hasProperty('import')) {
        args project.import
    }

    compileJava {
        options.compilerArgs << "-proc:none"
    }
}

task preCompile (type: JavaCompile) {
    source = sourceSets.main.java.srcDirs
    include 'com/mydomain/MyAppservices/config/MyAppReverseEngineeringStrategy.java'
    classpath = configurations.implementation
    destinationDirectory = file("build/classes/java/main")
}

task generateJPA  {
    group 'MyApp'
    description 'Generate JPA Entities'
    doLast{
        delete 'src/main/java/com/mydomain/MyAppservices/model', '*'
        delete fileTree('src/main/java/com/mydomain/MyAppservices/views') { include 'Q*' }
        ant {
            taskdef(name: 'hibernateTool',
                classname: 'org.hibernate.tool.ant.HibernateToolTask',
                classpath: configurations.hibernatetool.asPath)
            hibernateTool { 
                jdbcconfiguration(propertyFile: 'resources/hibernate.reveng.properties',
                                detectmanytomany: 'true',
                                reversestrategy: 'com.mydomain.MyAppservices.config.MyAppReverseEngineeringStrategy',
                                packagename: 'com.mydomain.MyAppservices.model',
                                revengfile: 'resources/hibernate.reveng.xml')
                hbm2java(destdir: 'src/main/java', ejb3: 'true', jdk5: 'true')
                classpath { 
                    pathElement(path: "build/classes/java/main")
                }   
            }
        }
    }
}

task generateQueryDSL (type: JavaCompile) {
    group 'MyApp'
    description "Generate QueryDSL classes"
    options.compilerArgs << "-s"
    options.compilerArgs << "src/main/java/"
    options.compilerArgs << "-proc:only"
    options.compilerArgs << '-processor'
    options.compilerArgs << 'com.querydsl.apt.jpa.JPAAnnotationProcessor'
    options.annotationProcessorPath = configurations.annotationProcessor
    source = sourceSets.main.java.srcDirs
    classpath = configurations.implementation + configurations.annotationProcessor
    destinationDirectory = file("build/classes/java/main")
}

generateJPA.dependsOn preCompile
generateQueryDSL.dependsOn generateJPA

task generate {
    group 'MyApp'
    description "Generate all JPAs and QueryDSL classes"
    dependsOn generateQueryDSL
}

task MyAppRun {
    dependsOn bootRun
    dependsOn generate
    tasks.findByName('bootRun').mustRunAfter 'generate'
}

task cleanGenerated {
    doLast{
        delete 'src/main/java/com/mydomain/MyAppservices/model', '*'
    }
}
解决方案

核心问题出在generateQueryDSL任务配置、Java 17下的注解处理器兼容,以及生成文件的路径识别上,以下是具体修改方案:

1. 修复generateQueryDSL任务的生成路径

当前把Q类生成到src/main/java/会和手动代码混在一起,且Gradle无法正确识别新生成文件。改用已定义的generated sourceSet路径,同时适配Java 17编译参数:

task generateQueryDSL (type: JavaCompile) {
    group 'MyApp'
    description "Generate QueryDSL classes"
    // 指定Q类生成到独立的generated/java目录
    options.compilerArgs << "-s" << "$projectDir/generated/java"
    options.compilerArgs << "-proc:only"
    options.compilerArgs << '-processor' << 'com.querydsl.apt.jpa.JPAAnnotationProcessor'
    // Java 17需显式添加JPA模块依赖
    options.compilerArgs << "--add-modules" << "java.persistence"
    options.annotationProcessorPath = configurations.annotationProcessor
    // 包含generateJPA生成的实体类路径
    source = sourceSets.main.java.srcDirs + files('src/main/java/com/mydomain/MyAppservices/model')
    classpath = configurations.implementation + configurations.annotationProcessor + sourceSets.main.output
    destinationDirectory = file("build/classes/java/generated")
}

2. 让主sourceSet识别生成的Q类

将generated sourceSet加入main的编译路径,确保compileJava能找到Q类:

sourceSets {
    main {
        java {
            srcDirs = ['src/main/java', sourceSets.generated.java.srcDirs]
        }
    }

    generated {
        java {
            srcDir "$projectDir/generated/java"
        }
    }
}

3. 修复bootRun中的compileJava配置

原配置在bootRun中全局禁用注解处理器,会影响Q类的编译识别。调整为仅在非生成任务时禁用:

compileJava {
    // 仅当不执行generateQueryDSL时,禁用注解处理避免重复生成
    if (!gradle.startParameter.taskNames.any { it.contains('generateQueryDSL') }) {
        options.compilerArgs << "-proc:none"
    }
    // Java 17编译参数适配
    options.compilerArgs << "--add-modules" << "java.persistence"
    options.release = 17
}

bootRun {
    if (project.hasProperty('import')) {
        args project.import
    }
    // 移除此处的compileJava配置
}

4. 调整依赖适配Java 17

Java 17移除了部分JEE模块,替换javax依赖为Jakarta版本(Spring Boot 2.7.x已支持过渡):

dependencies {
    // ... 其他依赖不变
    annotationProcessor("com.querydsl:querydsl-apt:5.0.0:jpa")
    annotationProcessor('org.springframework.boot:spring-boot-starter-data-jpa')
    annotationProcessor('org.springframework.boot:spring-boot-starter-data-rest')
    // 替换javax为jakarta兼容版本
    annotationProcessor('jakarta.persistence:jakarta.persistence-api:2.2.3')
    annotationProcessor('jakarta.annotation:jakarta.annotation-api:1.3.5')
    // ... 其他依赖不变
}

5. 明确任务执行顺序

避免并行执行导致的生成文件未就绪问题:

task MyAppRun {
    dependsOn generate, bootRun
    generate.mustRunAfter preCompile
    generateQueryDSL.mustRunAfter generateJPA
    bootRun.mustRunAfter generateQueryDSL
}

6. 扩展清理任务范围

清理生成的Q类文件,避免旧文件干扰:

task cleanGenerated {
    doLast{
        delete 'src/main/java/com/mydomain/MyAppservices/model', '*'
        delete 'generated/java', '*'
    }
}

最后执行任务前,先运行./gradlew cleanGenerated clean清理旧文件,再执行./gradlew MyAppRun启动项目。


内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 11:55:41