kelemen / netbeans-gradle-project

This project is a NetBeans plugin able to open Gradle based Java projects. The implementation is based on Geertjan Wielenga's plugin.
172 stars 57 forks source link

Clean and build root project failed because tests in its subprojects threw class definition not found error. #342

Closed HuckZou closed 7 years ago

HuckZou commented 7 years ago

I am using Gradle plugin in Netbeans for my project. I have following gradle build layout:

project A(root)/
    build.gradle
    settings.gradle
project B/
     build.gradle
     settings.gradle
project C/
     build.gradle
     settings.gradle

project B depends on project C, and root project A depends on project B. There are JUnit tests in project B and root project A. I was able to clean and build project B and project C successfully and all JUnit tests ran without errors. However, when I tried cleaning and building the root project A, JUnit tests in project B failed because it could not find its dependency classes from project C. I tried looking it up on StackOverflow but couldn't find a solution. It seems to me that the root project was able to compile all the source files successfully. However, during runtime, it was not able to find classes defined in project C.

Error message I got when clean and build the root project A:

java.lang.NoClassDefFoundError: projectC/Chipotle/LunchOrder
    at projectB.ChipotleOrdering.sendLunchOrder(ChipotleOrdering.java:95)
    at projectB.ChipotleOrderingTest.sendTestLunchOrders(ChipotleOrderingTest.java:109)

Gradle files for each project: projectA/build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")
    }
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
jar {
    baseName = 'projectA'
    version =  '0.1.0'
}
if (!hasProperty('mainClass')) {
    ext.mainClass = 'projectA.projectA'
}
repositories {
    mavenCentral()
    maven {
        url 'http://52north.org/maven/repo/releases/'
    }
}
dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.10'
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile 'mysql:mysql-connector-java'

    compile project(':projectC')
    compile project(':projectB')
}

projectA/settings.gradle:

rootProject.name = 'projectA'
include ':projectB'
project (':projectB').projectDir = new File(settingsDir, 'path/to/projectB')
include ':projectC'
project (':projectC').projectDir = new File(settingsDir, 'path/to/projectC')

projectB/build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")
    }
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'

sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
if (!hasProperty('mainClass')) {
    ext.mainClass = 'projectB.projectB'
}
repositories {
    mavenCentral()
    maven {
        url 'http://52north.org/maven/repo/releases/'
    }
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.10'
    compile project(':projectC')
}

projectB/settings.gradle:

rootProject.name = 'projectB'
include":projectC"
project(":projectC").projectDir = new File(settingsDir, "path/to/projectC")

projectC/build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'

sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

if (!hasProperty('mainClass')) {
    ext.mainClass = 'projectC.projectC'
}

repositories {
    mavenCentral()
    maven {
        url 'http://52north.org/maven/repo/releases/'
    }
}
dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.10'
    compile('org.springframework.boot:spring-boot-starter-web')
}

projectC/settings.gradle:

rootProject.name = 'projectC'
kelemen commented 7 years ago

I have tried to setup a build what you have described but I can't reproduce the issue. Though since this is not the first time I hear issues with a setup like yours, I would assume that there is a bug somewhere. What is the first 3 line of the output window, when you encounter this error. More specifically, is the settings.gradle there the appropriate one?

Anyway, I would recommend against this kind of setup. You should only have a settings.gradle in your root project (and none in the other projects). Also, you are less likely to encounter problems, if your root project is in a parent (possibly indirect) directory of every subproject.

HuckZou commented 7 years ago

Hi kelemen, thank you for helping me. In the output window, I got this message:

.......
projectB.ChipotleOrderingTest > testChipotleOrdering FAILED
    java.lang.NoClassDefFoundError at ChipotleOrderingTest.java:109
        Caused by: java.lang.ClassNotFoundException at ChipotleOrderingTest.java:109

63 tests completed, 5 failed
:projectB:test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':projectB:test'.
> There were failing tests. See the report at: file:///srv/git/sharedClasses/projectB/build/reports/tests/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

I think I'll try to create a root project directory that includes projectA,B and C as subprojects and see whether that could work.

kelemen commented 7 years ago

I need the first 3 lines of the output window which looks something like this:

Executing: gradle clean build
Arguments: [-x, test, -c, ....\settings.gradle]
JVM Arguments: [-Xmx512m]
HuckZou commented 7 years ago

Here is the output I get when I run clean and build the root project by .right click on the projectA and choose "Clean and Build" option. I would get the error mentioned above.

Build failure (see the Notifications window for stacktrace): gradle clean build
Executing: gradle clean build
Arguments: [-c, /srv/git/ProjectA/ProjectA/settings.gradle]

However, one strange thing I found was that, if I did right click projectA->Tasks->build->build, it would execute the following command with no error.

Executing: gradle :build
Arguments: [-c, /srv/git/ProjectA/ProjectA/settings.gradle]
kelemen commented 7 years ago

That is very strange, I will see what causes the difference. Anyway, which settings.gradle is the correct one in your opinion?

HuckZou commented 7 years ago

Thank you very much for helping me.. I believe that the settings.gradle file in ProjectA is the correct one to run. I looked into it a bit more. I found that second command ran successfully because it did not run the tests under the subproject (projectB). That was probably why it did not give me an error.

Executing: gradle :build
Arguments: [-c, /srv/git/ProjectA/ProjectA/settings.gradle]

:ProjectC:compileJava UP-TO-DATE
:ProjectC:processResources UP-TO-DATE
:ProjectC:classes UP-TO-DATE
:ProjectC:jar
:ProjectB:compileJava
:ProjectB:processResources UP-TO-DATE
:ProjectB:classes
:ProjectB:jar
:compileJava
:processResources UP-TO-DATE
:classes
:findMainClass
:jar
:bootRepackage
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

However, the first command actually ran the subprojects tests as well. Therefore, it failed because the root projectA couldn't find the dependencies needed for projectB.

Executing: gradle clean build
Arguments: [-c, /srv/git/ProjectA/ProjectA/settings.gradle]

:clean
:ProjectC:clean
:ProjectB:clean
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:ProjectC:compileJava
:ProjectC:processResources
:ProjectC:classes
:ProjectC:jar
:ProjectB:compileJava
:ProjectB:processResources UP-TO-DATE
:ProjectB:classes
:ProjectB:jar
:compileJava
:processResources UP-TO-DATE
:classes
:findMainClass
:jar
:bootRepackage
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build
:ProjectC:findMainClass
:ProjectC:bootRepackage
:ProjectC:assemble
:ProjectC:compileTestJava UP-TO-DATE
:ProjectC:processTestResources UP-TO-DATE
:ProjectC:testClasses UP-TO-DATE
:ProjectC:test UP-TO-DATE
:ProjectC:check UP-TO-DATE
:ProjectC:build
:ProjectB:findMainClass
:ProjectB:bootRepackage
:ProjectB:assemble
:ProjectB:compileTestJava
:ProjectB:processTestResources UP-TO-DATE
:ProjectB:testClasses
:ProjectB:test

projectB.ChipotleOrderingTest > testChipotleOrdering FAILED
    java.lang.NoClassDefFoundError at ChipotleOrderingTest.java:109
        Caused by: java.lang.ClassNotFoundException at ChipotleOrderingTest.java:109

63 tests completed, 5 failed
:projectB:test FAILED

FAILURE: Build failed with an exception.
kelemen commented 7 years ago

It is very strange, if the settings.gradle was specified correctly, I can't imagine that the plugin is doing something wrong. If you think, you have some time to spend on debugging this issue, you might try to debug this plugin because I can't reproduce this issue. The task execution is submitted to Gradle in AsyncGradleTask (in the awkwardly named doGradleTasksWithProgressIgnoreTaskDefCancel method). If you can notice some anomalies there, it might help finding the root cause.

Anyway, does this happen as well when you run the tasks from the command line as well?

HuckZou commented 7 years ago

Hi kelemen,

Thank you for helping me look into this. I think I found the possible cause for this issue. In my projectC build.gradle file, I used

apply plugin: 'org.springframework.boot'

I did not remember why I added it, because my projectC did not use the package. so I disabled the plugin by adding this to the end of the file

bootRepackage{
    enabled = false
}

After adding this, my root projectA was able to find its subprojectB's dependencies. Everything is building correctly now. Thank you again for taking the time to help me. 👍

kelemen commented 7 years ago

I'm glad the problem got solved. Though, it is a little strange that disabling bootRepackage solved the issue. Then again, I have seen stranger things with the boot plugin.