4

I'm using Gradle and Eclipse with the Buildship plugin.

Buildship creates the .classpath file for Eclipse to use. I need one classpath entry (com.gwtplugins.gwt.eclipse.core.GWT_CONTAINER) to appear after the org.eclipse.buildship.core.gradleclasspathcontainer entry, for class-loading reasons.

So the relevant part of my .classpath file should look like this (having the GWT_CONTAINER on the bottom).

<classpath>
 <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
 <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer" />
 <classpathentry kind="con" path="com.gwtplugins.gwt.eclipse.core.GWT_CONTAINER"/>
</classpath>

Buildship always has the gradleclasspathcontainer on the last position. So I tried to change the sorting like this in my build.gradle (excerpt):

eclipse {
    classpath { 
        file {
            beforeMerged { classpath ->
                def gwtClasspath = classpath.entries.find { entry -> entry.path == 'com.gwtplugins.gwt.eclipse.core.GWT_CONTAINER' }
                classpath.entries.remove gwtClasspath
                classpath.entries << gwtClasspath
            }
        }
    }

When using ./gradlew eclipseClasspath, the .classpath file is created correctly. But as soon as Buildship runs, the file is again overwritten with the wrong ordering.

I also tried using whenMerged instead of beforeMerged, but that doesn't change anything.

Here's the output of Gradle when started by Buildship (e.g. by clicking on Gradle -> Refresh on the Eclipse project's properties):

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
See https://docs.gradle.org/4.5/userguide/command_line_interface.html#sec:command_line_warnings

CONFIGURE SUCCESSFUL in 0s
:cleanEclipseWtpComponent
:cleanEclipseWtpFacet
:cleanEclipseWtp
:eclipseWtpComponent
:eclipseWtpFacet
:eclipseWtp

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
See https://docs.gradle.org/4.5/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 0s
4 actionable tasks: 4 executed

It seems Buildship doesn't even execute the eclipseClasspath task, but does create the .classpath file by some other means.

How can I get Buildship to honor my wish to have the classpath sorted my way?

Bob
  • 5,510
  • 9
  • 48
  • 80
  • Would the [_GWT Gradle Plugin_](https://github.com/steffenschaefer/gwt-gradle-plugin) be an option for you? – howlger Mar 02 '18 at 13:24
  • I'm already using this (that's where the classpath entry for GWT is coming from). – Bob Mar 02 '18 at 17:39

2 Answers2

3

I found the solution on Gradle forums:

Buildship doesn't use the eclipseClasspath task, but reads the configuration and creates .classpath by its own means. The Gradle classpath is appended to the end of the classpath, if it's not yet defined. This happens after executing the whenMerged section. So the solution is to add the Gradle classpath manually:

eclipse {
   classpath {
        containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
   }
}
Bob
  • 5,510
  • 9
  • 48
  • 80
0

Perhaps the withXml hook would work differently

eclipse.classpath.file {
    withXml { provider ->
        def entry = provider.asNode().classpath.classpathentry.find { it.path == 'com.gwtplugins.gwt.eclipse.core.GWT_CONTAINER' }
        println "Found $entry"
        def parent = entry.parent()
        parent.remove(entry)
        parent.append(entry)
    }
}
Bob
  • 5,510
  • 9
  • 48
  • 80
lance-java
  • 25,497
  • 4
  • 59
  • 101
  • Thanks for the suggestion, but this doesn't change the result :( – Bob Mar 02 '18 at 17:45
  • What did the println output? – lance-java Mar 02 '18 at 19:56
  • I just noticed Buildship doesn't execute the `eclipseClasspath` task. So there is no output from this task, but still the `.classpath` file is there after Buildship ran. So the problem is probably that Buildship uses other means to create this file. Buildship runs the following tasks: `eclipseWtpComponent`, `eclipseWtpFacet` and `eclipseWtp`. If I delete `.classpath` and run Gradle manually with those tasks, it does not create a new `.classpath` file. – Bob Mar 03 '18 at 08:39
  • Buildship should fire the `eclipseClasspath` task every time you right click on the project and choose "refresh gradle project" (there's also a refresh button in the buildship view). How did the `GWT_CONTAINER` get into your `.classpath`? Did you add it manually? Any additions should be done via `build.gradle` and not manually – lance-java Mar 03 '18 at 13:08
  • I'm using the GWT plugin (linked in the first comment below the question). According to its log, Buildship does not use the `eclipseClasspath` task. – Bob Mar 03 '18 at 17:12
  • You're right, it doesn't use the `eclipseClasspath` task, but it does use the `eclipse.classpath` model from `build.gradle`. If you are not adding `GWT_CONTAINER` in `build.gradle` then I'm pretty sure that's your problem. Everything needs to be in `build.gradle` and nothing can be added to `.classpath` by another external process/plugin (it's fine that GWT plugin reads the GWT_CONTAINER entry and acts accordingly). Perhaps you also need to add the GWT nature in build.gradle? – lance-java Mar 03 '18 at 17:29
  • According to the GWT Gradle Plugin documentation, it automatically adds the GWT nature. And the classpath includes the `GWT_CONTAINER`, but only at the wrong location. – Bob Mar 04 '18 at 16:52
  • Ok, if its gradle adding then that's fine. So, does the println in the `withXml` closure execute when you "refresh gradle project" in eclipse? Does it find the GWT entry? – lance-java Mar 04 '18 at 22:09
  • No, it doesn't even execute the `eclipseClasspath` task, so the `withXml` part is not executed, too. I'll add some log info to the question. – Bob Mar 06 '18 at 17:41
  • Agreed, but it should still use the eclipse model, which includes `withXml` – lance-java Mar 06 '18 at 18:33
  • Same goes for `beforeMerged` or `whenMerged`, but it doesn't. – Bob Mar 06 '18 at 19:42