Search code examples
javaspring-bootgradleupgradequerydsl

QueryDSL Q Classes Not Generating after Java 17 Upgrade


I'm upgrading a Gradle 7.5 project that uses Spring Boot 2.7.5 and QueryDSL 5.0 from Java 8 to Java 17. The project was working before the upgrade, but afterword, it does not build because the final CompileJava execution logs a "cannot find symbol" error for all the Q class references in the code.

I think these classes are either being stored differently or are not being generated.

Also, in case this helps, I'm using VS Code as my IDE, but am running all my Gradle commands from a standard Windows command prompt.

I've looked at Stack Overflow and other sites for questions related to this. Unfortunately, though this question has been asked in various contexts, their answers did not work out for my context. Here are some places where I looked in case this helps others:

Here's my build.gradle. Please note that this was working when I had 'sourceCompatability = 1.8" and haden't started using the toolchain notation or even Java 17, yet. Also know that I did not create this file from scratch, but am editing one that someone else started.

Additionally, it's the "compileJava" command in the "bootRun" task that is failing (the main task to 'run' the app is "MyAppRun". It, in turn executes "preCompile", "generateJPA", "generateQueryDSL", and "bootRun" in that order). I expect something needs to change in the "generateQueryDSL" task.

I'm very new to Gradle and QueryDSL and would appreciate any advice.

Thanks in advance!

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', '*'
    }
}


Solution

  • To answer my own question, a coworker ended up changing a line at the end of the generateJPA task from

    hbm2java(destdir: 'src/main/java', ejb3: 'true', jdk5: 'true')
    

    to

    hbm2java(destdir: 'src/main/java', ejb3: 'true', jdk5: 'true', templatepath: 'resources/templates')
    

    and made sure we had a <Spring Boot project root>/resources/templates/pojo/Pojo.ftl file with this content:

    ${pojo.getPackageDeclaration()}
    
    <#assign classbody>
    <#include "PojoTypeDeclaration.ftl"/> {
    
    <#if !pojo.isInterface()>
    <#include "PojoFields.ftl"/>
    
    <#include "PojoConstructors.ftl"/>
       
    <#include "PojoPropertyAccessors.ftl"/>
    
    <#include "PojoToString.ftl"/>
    
    <#include "PojoEqualsHashcode.ftl"/>
    
    <#else>
    <#include "PojoInterfacePropertyAccessors.ftl"/>
    
    </#if>
    <#include "PojoExtraClassCode.ftl"/>
    
    }
    </#assign>
    
    ${pojo.generateImports()}
    ${classbody}
    

    This solved it for us.