升级至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

