eclipsegradlebuildship

Eclipse buildship not configuring classpath from gradle - worked and then broke


I have a gradle based eclipse workspace which has a parent project and multiple child projects. Eclipse suddenly has problems adding a project to the classpath of another though it works fine from gradle command line.

Eclipse is showing a typical error for a package it can't find:

PROJECTS

CmbProduct
+-- build.gradle
+-- settings.gradle
+--+ MangoCommon
   +-- build.gradle
   +-- src/main/java/org/mangogrove/common/util/StringTool.java
+--+ Model
   +-- build.gradle
+--+ Common
   +-- build.gradle
   +-- src/main/java/mypackage/AbstractExpander.java

View of Projects:

enter image description here

If I open AbstractExpander.java in eclipse it shows the import of StringTool as an error and underlins the "mango" package as the error. (See first pic).

WHAT I HAVE TRIED

Classes in Model that import classes from MangoCommon are fine.

Running "gradle compileJava" from command line works fine.

There are no errors in .metadata/.log

If I delete .metadata and rebuild/re-import the problem returns.

A similar setup on the same system for a different dev branch of the same product works fine.

I've done a restore of the dev tree from backups from last week when it worked fine. Problem returns as soon as I Gradle -> Sync in eclipse.

I removed .metadata and all .project .classpath .settings from each project (including parent) and imported via Gradle > Import Existing Gradle Project

EDIT 20221121

I tried eclipse 2021-12 before running I removed all .metadata .project .classpath .settings from each project (including parent) and imported via Gradle > Import Existing Gradle Project.

EDIT 20221122

Created a completely new workspace dir, git imported, then ran Eclipse and did Import > Gradle Existing Project. Same problem.

I restored the VM holding the broken workspace from a week before the VM rebooted. Eclipse fires up fine on the broken workspace. However after I run Gradle > Refresh Gradle Project it becomes broken in the same way.

I installed eclipse 2022-06 (4.20) and wiped my .metadata .settings .classpath .project files. After Gradle Import Existing Project the problem appears right away.

FINDINGS

In eclipse if I expand Common -> Project and External Dependencies the "MangoCommon" entry is greyed out but "Model" is normal.

enter image description here

My actual product has many other sub-projects most of which are like "Common" and are showing errors when importing classes from MangoCommon.

CmbProject build.gradle

buildscript {
    // Always load buildinfo so project.version is set as early as possible
    gradle.startParameter.taskNames = [":buildInfoLoad"] + gradle.startParameter.taskNames

    // Repos needed just for the dependencies section directly below
    repositories {
        flatDir {
            dirs 'MangoGroveGradle/repoflat'
        }
        maven { // aka "jcenter()"
            url "https://jcenter.bintray.com"
        }
    }

    dependencies {
        classpath("org.mangogrove.gradle:MangoGroveGradle:1.0.0")
    }
}

apply plugin: 'org.mangogrove.gradle'

import org.apache.tools.ant.filters.*;

allprojects {

    ext {
... snip ...
        generatedSrcDir = "src-gen
    }

wrapper {
    distributionType = Wrapper.DistributionType.BIN
}
subprojects {

    /*
     * Use "apply plugin" not "plugins" because the former allows each
     * sub-project to add their own without overriding what is set here.
     */
    apply plugin: 'java'
    /*
     * We use "testFixturesApi" and similar here so we must have this plugin
     */
    apply plugin: 'java-test-fixtures'
    // Every subproject should be configured for Eclipse
    apply plugin: 'eclipse'

    /*
     * Some files contain non-ASCII chars like Euro symbol.  We need to tell
     * Java to use UTF-8 always
     */
    compileJava {options.encoding = "UTF-8"}

    targetCompatibility = JavaVersion.VERSION_1_8
    sourceCompatibility = JavaVersion.VERSION_1_8
    javadoc.enabled = false

    sourceSets {
        main {
            java {
                // Define all source dirs - Purpose is to add "src-gen"
                srcDirs = ["src/main/java", "$rootProject.generatedSrcDir" ]
            }
        }
    }
    /*
     * Tell Gradle to treat src-gen like a resource so it will copy <model>.ecore files here
     * and set classpath properly at runtime.
     */
    sourceSets.main.resources.srcDir "$rootProject.generatedSrcDir"

    repositories {
        maven {
            // Local repo for annovention
            url uri("$rootDir/MangoCommon/repo")
        }
        maven {
            url uri("$rootDir/logbackwela/repo")
        }

        mavenCentral()
        maven { url "https://maven.java.net/content/groups/public" }
        // Texo/EMF
        maven { url "https://oss.sonatype.org/content/groups/public" }
        // Eclipse
        maven { url "https://oss.sonatype.org/content/repositories/public/eclipse" }
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
        maven { url 'https://mvnrepository.com/artifact' }
        
        maven { url "https://repository.jboss.org/nexus/content/groups/public-jboss" }
        maven { url "https://maven.vaadin.com/vaadin-addons"    }
        maven { url "https://oss.sonatype.org/content/repositories/vaadin-snapshots"    }
        
        maven { url "https://maven.clapper.org" }
        // Project Lombok
        maven { url "https://projectlombok.org/mavenrepo" }
    }

    def bouncycastleVersion = "1.69" // Was 1.68
    def lombokVersion = "1.18.20" // was 1.18.10
    .... snip ...

    ext {
        springFrameworkVersion = "5.3.6" // 5.3.4
        springDataVersion = "2.4.8" // 2.4.3
        ... snip ...
    }

    configurations.all {
        // We use logback now but some dependencies pull in slf4j-jdk14 so we exclude here
        exclude group:"org.slf4j", module: "slf4j-jdk14"
    }

    dependencies {
        /*
         * PRODUCT SPECIFIC
         */
        implementation "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
        implementation "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
        testFixturesApi "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
        testFixturesApi "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"

        /*
         * Common and product
         */
        implementation "org.simpleframework:simple-xml:$simpleXmlVersion"
        /*
         * We use logback for logging but need various slf4j packages to route other
         * logger frameworks to slf4j which is handled by logback
         */
        implementation "ch.qos.logback:logback-classic:$logbackVersion"
        implementation "org.slf4j:slf4j-api:$slf4jVersion"
        // Janino required by our logback configs
        implementation "org.codehaus.janino:janino:$janinoVersion"
        // Route JCL -> slf4j which forwards to logback
        implementation "org.slf4j:jcl-over-slf4j:$slf4jVersion"
        // Route JUL -> slf4j which forwards to logback
        // This is required for c3p0 to use slf4j -> logback
        implementation "org.slf4j:jul-to-slf4j:$slf4jVersion"
        // Route log4j -> slf4j which forwards to logback
        implementation "org.slf4j:log4j-over-slf4j:$slf4jVersion"
        // Send slf4j to log4j 1.2 for those JARs which use slf4j
        //implementation "org.slf4j:slf4j-log4j12:$slf4jVersion"
        // Log4j itself
        //implementation "log4j:log4j:$log4jVersion"

        // Texo (use changing: true to enable snapshots)
        implementation group: "org.eclipse.emf", name: "org.eclipse.emf.texo", version: "$texoVersion", changing: true
        implementation group: "org.eclipse.emf", name: "org.eclipse.emf.texo.server", version: "$texoVersion", changing: true
        implementation group: "org.eclipse.emf", name: "org.eclipse.emf.texo.xml", version: "$texoVersion", changing: true
        // Texo dependencies (not automaticly added by texo)
        implementation "org.eclipse.emf:org.eclipse.emf.common:$emfVersion"
        implementation "org.eclipse.emf:org.eclipse.emf.ecore:$emfVersion"
        implementation "org.eclipse.emf:org.eclipse.emf.ecore.xmi:$emfVersion"
        implementation "org.jsoup:jsoup:$jsoupVersion"

        // Apache HTTP client
        implementation("org.apache.httpcomponents:httpclient:$apacheHttpClientVersion") {
            // This is an older implementation deprecated by jcl-over-slf4j
            exclude group: "commons-logging"
        }
        // EventBus and more
        implementation "com.google.guava:guava:$googleGuavaVersion"
        testFixturesApi "com.google.guava:guava:$googleGuavaVersion"

        implementation("com.sun.mail:javax.mail:$javaxMailVersion") {   // Actual implementation
            // This dependency includes an older version
            exclude group: "javax.activation"
        }
        // Make sure we use the same version for everything
        implementation "jakarta.annotation:jakarta.annotation-api:1.3.5"

        implementation "net.java.dev.jna:jna:$jnaVersion"
        implementation "net.java.dev.jna:jna-platform:$jnaVersion"

        // This package provided by Tomcat or Servlet container
        compileOnly "javax.servlet:javax.servlet-api:$javaxServletVersion"
        testFixturesApi "javax.servlet:javax.servlet-api:$javaxServletVersion"

        annotationProcessor                 "org.projectlombok:lombok:$lombokVersion"
        compileOnly                         "org.projectlombok:lombok:$lombokVersion"
        testFixturesApi                     "org.projectlombok:lombok:$lombokVersion"
        testFixturesAnnotationProcessor     "org.projectlombok:lombok:$lombokVersion"
        testImplementation                  "org.projectlombok:lombok:$lombokVersion"
        testAnnotationProcessor             "org.projectlombok:lombok:$lombokVersion"

        testImplementation "org.testng:testng:$testngVersion"
    }
}

CmbProject settings.gradle

include 'CodeGen'
include 'MangoCommon'
include 'Model'
include 'Common'

Common build.gradle

plugins {
    id 'java-library'
}

// Enable deprecation messages in javac
compileJava {
    options.compilerArgs << '-Xlint:deprecation'
}
compileTestJava {
    options.compilerArgs << '-Xlint:deprecation'
}

dependencies {
    api project(":Model")

    // Version does not change
    api "javax.xml.soap:javax.xml.soap-api:1.4.0"

    testImplementation testFixtures(project(":MangoCommon"))
    testFixturesApi project(":MangoCommon")
    testFixturesApi testFixtures(project(":MangoCommon"))

    // Required for JAX-RS Client
    api "org.glassfish.jersey.core:jersey-client:$jerseyGlassfishVersion"
    // Required by client + servlet container 2.26 and later [RUNTIME REQUIREMENT]
    api "org.glassfish.jersey.inject:jersey-hk2:$jerseyGlassfishVersion"
    // Required by Client jersey 2.26 and later [RUNTIME REQUIREMENT]
    api "org.glassfish.jersey.media:jersey-media-jaxb:$jerseyGlassfishVersion"
}
... snip out tasks ....

Model build.gradle

plugins {
    id 'java-library'
}
compileJava.dependsOn copyEcore

// Enable deprecation messages in javac
compileJava {
    options.compilerArgs << '-Xlint:deprecation'
}

dependencies {
    api project(":MangoCommon")
//  testImplementation testFixtures(project(":MangoCommon"))

    api "org.flywaydb:flyway-core:$flywayVersion"
    // Provide javax.persistence classes
    api "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final"
    implementation "org.hibernate:hibernate-core:$hibernateVersion"
}

sourceSets.test.resources.srcDir "src/dev/resources" // for persistconfig.properties
... snip tasks ...

MangoCommon build.gradle

plugins {
    id 'java-library'
}

// Enable deprecation messages in javac
compileJava {
    options.compilerArgs << '-Xlint:deprecation,unchecked'
}
compileTestJava {
    options.compilerArgs << '-Xlint:deprecation,unchecked'
}
compileTestFixturesJava {
    options.compilerArgs << '-Xlint:deprecation'
}

dependencies {
    testImplementation "org.testng:testng:$testngVersion"

    api "com.impetus:annovention:$annoventionVersion"

    api("org.clapper:javautil:$clapperJavaUtilVersion") {
        // Exclude older asm to avoid implementation issue
        exclude group: "asm", module: "asm"
        exclude group: "asm", module: "asm-commons"
        exclude group: "asm", module: "asm-tree"
        // Exclude items provided elsewhere
        exclude group: "javax.mail", module: "mail"
        exclude group: "commons-logging", module: "commons-logging"
        exclude group: "javax.activation"
    }

    api("org.freemarker:freemarker:$freemarkerVersion") {
        exclude group: "freemarker", module: "freemarker" // Legacy org-less group
    }
    
    implementation "org.hibernate:hibernate-core:$hibernateVersion"
    testFixturesApi "org.hibernate:hibernate-core:$hibernateVersion"
    
    api "org.springframework:spring-core:$springFrameworkVersion"
    api "org.springframework:spring-context:$springFrameworkVersion"
    api "org.springframework:spring-context-support:$springFrameworkVersion"
    api "org.springframework:spring-orm:$springFrameworkVersion"
    api "org.springframework:spring-web:$springFrameworkVersion"
    api "org.springframework:spring-webmvc:$springFrameworkVersion"
    api "org.springframework.data:spring-data-jpa:$springDataVersion"
    api "com.zaxxer:HikariCP:$hikariCpVersion"
}
... snip tasks ...

Here is the Common/.classpath that Eclipse -> Gradle sync created:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
        <classpathentry kind="src" output="bin/main" path="src/main/java">
                <attributes>
                        <attribute name="gradle_scope" value="main"/>
                        <attribute name="gradle_used_by_scope" value="main"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="src" output="bin/main" path="src-gen">
                <attributes>
                        <attribute name="gradle_scope" value="main"/>
                        <attribute name="gradle_used_by_scope" value="main"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="src" output="bin/main" path="src/main/resources">
                <attributes>
                        <attribute name="gradle_scope" value="main"/>
                        <attribute name="gradle_used_by_scope" value="main"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="src" output="bin/test" path="src/test/java">
                <attributes>
                        <attribute name="gradle_scope" value="test"/>
                        <attribute name="gradle_used_by_scope" value="test"/>
                        <attribute name="test" value="true"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="src" output="bin/test" path="src/test/resources">
                <attributes>
                        <attribute name="gradle_scope" value="test"/>
                        <attribute name="gradle_used_by_scope" value="test"/>
                        <attribute name="test" value="true"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="src" output="bin/testFixtures" path="src/testFixtures/java">
                <attributes>
                        <attribute name="gradle_scope" value="testFixtures"/>
                        <attribute name="gradle_used_by_scope" value="testFixtures"/>
                        <attribute name="test" value="true"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
        <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
        <classpathentry kind="src" path="/Model">
                <attributes>
                        <attribute name="without_test_code" value="false"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="src" path="/MangoCommon">
                <attributes>
                        <attribute name="without_test_code" value="false"/>
                </attributes>
        </classpathentry>
        <classpathentry kind="output" path="bin/default"/>
</classpath>

Environment

eclipse.buildId=4.25.0.I20220831-1800
java.version=17.0.4.1
java.vendor=Eclipse Adoptium
Gradle: 7.5.1
Buildship: 3.1.6

Solution

  • Found the problem!

    Gradle 7.5.x + Buildship 3.1.6 seem to be broken. When I configured Eclipse (Preferences > Gradle > Specific version) to use 7.4.2 everything worked once again.

    I normally have Eclipse Gradle configured to use gradle wrapper. I had upgraded gradle wrapper from 7.4.2 to 7.5.1 from the command line a month ago. Gradle worked fine from the command line but once my dev system rebooted I ran Gradle > Refresh Gradle Project which used 7.5.1 for the first time in eclipse.