Add support for extra classpath containers

I am new to Gradle and having some difficulty in adding a container classpath entry. My eclipse configuration has a container setup for a product library that I need to use in my java project. I am able to include the library to my project using the Configure build Path -> Add Library option, but when I am trying to set this up using gradle I am having some difficulty. I am defining the container as shown below.

eclipse {
   classpath {
    containers 'ilog.odms.ide.odm.enterprise.ODM_CONTAINER/ODM'
   }
}

If I add the library using build path -> add library option I can see the below in my .classpath file.

<classpathentry kind="con" path="ilog.odms.ide.odm.enterprise.ODM_CONTAINER/ODM"/>

You didn’t tell us what the difficulty is you are having.

The difficulty is there is no entry in the classpath for the container when defining it through the grade file. My understanding is we define the container in gradle and then refresh the project and it automatically adds an entry to classpath.

Thanks

I see, so you are using Buildship, which currently ignores extra containers (unfortunately). The fix is relatively simple, but with all the work for Gradle 3.0 going on, this will probably have to wait a little longer.

Thanks @st_oehme I will try it without using the eclipse plugin.

You can still use Buildship, you’ll just have to add the container manually and check in the .classpath file until we fix this.

@st_oehme I added the container to .classpath manually, however when I run the build task in Gradle, it fails and in the console I see java errors related to missing symbols from the container library I added manually. Below is my gradle build file and I have added the container library to my classpath using the eclipse configure build path option

apply plugin: ‘java’
apply plugin: ‘eclipse’

sourceSets {
main {
java {
srcDir ‘src’
}
resources {
srcDir ‘resources’
}
}
}

repositories {
jcenter()
}

// In this section you declare the dependencies for your production and test code
dependencies {
compile ‘com.google.guava:guava:17.0’, ‘org.eclipse.jdt:org.eclipse.jdt.annotation:1.1.0’
compile (
[group: ‘org.springframework’, name: ‘spring-core’, version: ‘3.1.0.RELEASE’],
[group: ‘org.springframework’, name: ‘spring-jdbc’, version: ‘3.1.0.RELEASE’]
)
}

We are facing the same “difficulty”. Our example is with GWT. When a project has a GWT nature it validates whether the GWT SDK (container) is on the classpath and does not find it (indirectly there is a binary/jar resolved via Gradle but is undetectable by the Google Plugin for Eclipse). Adding it via:

eclipse {
  classpath {
    containers 'com.google.gwt.eclipse.core.GWT_CONTAINER/NamedGWTContainer'
  }
}

… does not help, as it is ignored by Buildship.

Related - not sure if it stands, but GWT SDK also “liked” being the very first entry in the classpath and would error out otherwise long time ago. We dealt with it then by manually placing it at the top of the .classpath file. Gradle would only modify the file, not replace it, so this worked for us for years. With Buildship we are trying to eliminate all complexity and fully generate these files via Buildship.

The Gradle build does not use the eclipse classpath for compilation. It uses what is specified in the dependencies {} block.

This will work with Gradle 3.0 and Buildship 1.0.18 (the next release).

I wish Eclipse plugins would stop pretending that they are the source of truth, when in reality every real project has a build system that already knows all the dependencies. You’ll actually have to exclude the binary dependencies that are already on your classpath, but which should be provided by the container instead. Something like eclipse.classpath.minusConfigurations << configurations.gwt

Yes, I understand that. This is not about compilation failing but validation. Errors are shown in the console and validation is not complete. Depending on what Eclipse does, there is a risk of it not continuing the compilation of other projects because of this. Fortunately for us, that is not what is going on in this case.

I wish Eclipse plugins would stop pretending that they are the source of truth, when in reality every real project has a build system that already knows all the dependencies.

I agree 100%. Problem is that we are not in control of those.

You’ll actually have to exclude the binary dependencies that are already on your classpath, but which should be provided by the container instead. Something like eclipse.classpath.minusConfigurations << configurations.gwt

I am aware of this too. We are actually quite thorough on normalizing dependencies presently (that will go backwards with Buildship) as projects do export their dependencies and only add those that they did not import. We created a Gradle plugin that does this for us. This approach greatly helps with Eclipse performance and memory consumption, among other things. Duplicate classpath entries can cause failures - but, fortunately for us, in this GWT case, they do not matter. Furthermore, both the Gradle’s vision of the classpath and the container one are, actually, pointing to the exact same set of files (not just equal) as we auto-configure Eclipse container to point to them.

That part was not for you, see the quote above :slight_smile:

I don’t understand why that would get worse with Buildship. Buildship adds exactly the jars that each project needs to its classpath.

Can you elaborate? There were JDT bugs in older Eclipse versions that lead to the same jar being indexed several times, but these are no longer present in Mars and Neon.

An update first: by seeding .classpath files before importing the projects I was able to work around the errors. Yes, I presently effectively have duplicate entries in the classpath.

Re:

I don’t understand why that would get worse with Buildship. Buildship adds exactly the jars that each project needs to its classpath.

It isn’t about projects’ needs but about Eclipse memory consumption, performance and clarity. It may be different now, but past experience was that Eclipse gets bogged down by many libraries. I can’t be sure why but it feels like it may be indexing all duplicate occurrences of them (thus taking more memory and time) and performs slower when editing and looking them up (possibly due to inefficient indexing or lack of memory). Either way, Eclipse with less (duplicates of) dependency libraries performs a lot better. On a UX note, it helps to know exactly which project introduces the library as opposed to seeing it listed everywhere when searching for a class.

Re that update, copying a template file into a .classpath file before importing via Buildship works. The template file for the above case would look like:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER/NamedGWTContainer"/>
</classpath>

@st_oehme I have now upgraded the buildship to 1.0.20 and still seeing some issues withe using the eclipse classpath container. Maybe I don’t understand it much as I am new to gradle. I have defined the eclipse classpath container in the build.gradle file and when I refresh the project using option Gradle -> refresh project, I can see the container is showing up in eclipse build path. However, when I run the gradle build task from the task view, I see errors in the gradle console log which are related to unresolved symbols coming from the libraries specified in the container.
If gradle build will only recognize what is specified in the dependencies section, how could I make it also include the jars file specified in the eclipse classpath container?

Thanks,
Javid

Classpath containers are an Eclipse concept and only available inside the
ide. Gradle knows nothing about their content. You need to make your
dependencies available in a standalone form.

In general classpath containers are not very useful if you have a good build system like Gradle, because the build system already knows the dependencies. Classpath containers in Eclipse were invented back in the day when people used their IDE to build their jars :wink: