NoClassDefFoundError - Generated classes


(Simone Vratogna) #1

Hello I have a gradle project that used to work correctly in eclipse (neon 3) with an older version of buildship, recently I updated to version 2.2.1 and cannot run my unit tests anymore.
The problem lies in the fact that, using querydsl, there are a bunch of generated classes (that are correctly added to the project classpath) that now are not found anymore when trying to run the tests.
Running the tests just using gradlew is ok.
I have read something concerning the fact that the now the classpath used by eclipse and that used by buildship have totally diverged so I see the classes in eclipse’s classpath but are not available for buildship’s. The problem is that I have no idea on how to solve this… :slight_smile:


(Donát Csikós) #2

Buildship 2.2 introduced runtime classpath separation which probably causes your problem. The works the following way: it checks what Gradle source sets the executed main() method or test class belong to and filters the unrelated entries from the runtime classpath. It’s a bit tricky to debug, so I’d suggest you create minimal example exhibiting the problem and we’ll have a look.


(Donát Csikós) #3

Another idea would be to disable the classpath separation. You can do that by removing the gradle_scope and the gradle_used_by_scope attributes from the classpath entries. You can customize the classpath entries in the eclipse.classpath.file.whenMerged block:

apply plugin: 'java'
apply plugin: 'eclipse'

eclipse {
    classpath {
        file {
            whenMerged {
                entries.each { entry ->
                    if (entry instanceof org.gradle.plugins.ide.eclipse.model.AbstractClasspathEntry) {
                        entry.entryAttributes.remove('gradle_scopes')
                        entry.entryAttributes.remove('gradle_used_by_scope')
                    }
                }
            }
        }
    }
}

(Simone Vratogna) #4

I’ll try to create an example project asap. In the meanwhile, the solution of disabling class separation works, thank you!


(Jochen Meierhofer) #5

Hello,
I experienced the same problem with Buildship 2.2.1 and Eclipse 2018-09.
I was able to create a sample project, which reproduces the bug: Generated sources from Query DSL plugin can not be accessed if buildship classpath separation is active.

Steps:

  • import project into eclipse
  • run “./gradlew queryDsl” or “./gradlew install” in library folder
  • Run “Refresh Gradle Project” in eclipse
  • execute test QMyEntityTest in subproject library-server

If you comment in lines 37-46 in library-server build.gradle, then it works.

Git Repo: https://github.com/jmeierhofer/buildship-bug-querydsl

Regards & many thanks in advance
Jochen


(Donát Csikós) #6

It seems that the com.ewerk.gradle.plugins.querydsl plugin defines a new source set that is independent from the main and test source sets. Would it make sense to make the generated types part of the main source set?


(Jochen Meierhofer) #7

Hi donat,

thanks for your reply. Ok, good to know that the ewerk querydsl plugin causes the problem. I will try to find another solution. Perhaps it works with another plugin.

I will write another post if I managed to get it running.


(Jochen Meierhofer) #8

I managed to get queryDsl running with eclipse 2018-09, buildship 2.2.1 and gradle 4.10.2. I attached my gradle build file if anybody finds this thread in the future.

Eclipse detects changed entities automatically and runs the JPA annotation processor in the background.

  • Import the project with buildship
  • Run the following gradle commands in a bash or commandline: ./gradlew eclipseJdtApt eclipseFactoryPath eclipseJdt
  • Refresh the gradle project in eclipse (right click - gradle - refresh gradle project)
build.gradle

buildscript {
repositories {
mavenCentral()
}
}

plugins {
id ‘java’
id “net.ltgt.apt” version “0.20”
id ‘net.ltgt.apt-eclipse’ version ‘0.19’
}

repositories {
mavenCentral()
}

// query DSL annotation processor config
dependencies {
def queryDslVersion = ‘4.2.1’

compile("com.querydsl:querydsl-core:${queryDslVersion}")
compile("com.querydsl:querydsl-jpa:${queryDslVersion}")

annotationProcessor (
    "com.querydsl:querydsl-apt:${queryDslVersion}:jpa",
    "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final",
    "javax.annotation:javax.annotation-api:1.3.2",
)

}

dependencies {
compile(“org.hibernate:hibernate-java8:5.2.12.Final”)

testCompile "junit:junit:4.12"
testCompile "org.hamcrest:hamcrest-all:1.3"
testCompile "org.mockito:mockito-core:1.10.19" 

}

// eclipse annotation processor config for query DSL - see https://github.com/tbroyer/gradle-apt-plugin
eclipse {
jdt {
apt {
aptEnabled = compileJava.aptOptions.annotationProcessing
reconcileEnabled = true
processorOptions = compileJava.aptOptions.processorArgs
// where eclipse will output the generated sources
genSrcDir = file(‘bin/.apt_generated’)
}
}

factorypath {
    plusConfigurations = [ configurations.annotationProcessor, configurations.testAnnotationProcessor ]
    minusConfigurations = []
}

}


(Daniel Platz) #9

The approach from Jochen is the one I am taking right now as well.
And it works fine. The issue is just the manual steps needed to run the tasks “eclipseJdtApt eclipseFactoryPath eclipseJdt” and the manual refresh of the project.
Is there any way to somehow automate this so buildship just does this when I import the project in Eclipse or do a “Gradle Refresh” at least?

I was wondering if Buildship of Eclipse is executing any actual gradle task? like the eclipse task? It does not seem to be the case. At least when i try something along this lines, it dont see this beeing executed when i run “Gradle Refresh”…

tasks["eclipse"].dependsOn("testit")

task testit {
    doLast {
        def file1 = new File('c:/junk/log.txt')
        file1.write 'Executed from Eclipse.\n'
    }
}

(Jochen Meierhofer) #10

That’s because buildship does not execute the eclipse task as far as I know.
I am also interested in an automatic approach. I was postponing this manual issue for now…