Adding a library to Eclipse classpath

I have installed Buildship 1.0.18 and I’m following the example at Buildship 1.0.18 is now available to add a library to my Eclipse project classpath.
In particular I’m using classpath.file.whenMerged to add a Library entry.
What I see is that the entry is not added to the .classpath file, but rather it’s in some way added to the “Project and External Dependencies” container. So, I can’t find the XML fragment shown in the corresponding “Configured entry in classpath container” anywhere in my workspace.

Anyway, my actual problem is that I would like to export the added library. Even though I do something like this in the whenMerged closure::

def lib = new org.gradle.plugins.ide.eclipse.model.Library(fileReference(file('path/to/my/jar)))
lib.exported = true
entries += lib

it doesn’t seem like the exported property is honoured. After all, the Eclipse UI allows to export only the whole classpath container, not just part of it… On the other hand, if I could add a classpathentry of type lib in my .classpath, I could get the result I want in that way. However I don’t know how to do it: I tried to manipulate the .classpath with eclipse.classpath.file.withXml, but it doesn’t seem to be honoured by Buildship (although it is if I invoke the “eclipse” task from the cli).

Any suggestion would be really appreciated.

The exported flag should work, though I’d be curious about the use case. It’s usually way better to work with dependencies. Gradle will automatically insert those into the classpath and propagate them to downstream projects.

dependencies {
  compile files("path/to/jar")
}

Yes, of course I know, but my use case is really specific.

This project is a webapp project made up of a servlet and a class which is meant to be deployed in the Tomcat lib directory, because it replaces the default TrustManager used by Tomcat. This class is defined in its own separate custom source set. First of all, to make Eclipse compile that class I must add that custom source set compile configuration with eclipse.classpath.plusConfigurations.

This is not enough, though. In the Tomcat launch configuration, I have to add my project to the Tomcat classpath. However, the project itself is not enough, because I’m missing the required libraries. In the Classpath tab entry of the launch configuration dialog, when I add the project to the “User Entries”, I can also specify to include the project exported entries. However, the “Project and External Dependencies” container is not exported by default. And, even if it were, I can’t export it as a whole because there are other libraries required to compile the servlet (from the standard runtime configuration). I would need to export only the dependencies declared in the custom source set runtime configuration. Do you know of any clean why to do this? What I thought till now is to cycle through that dependencies and add them as entries in the whenMerged closure, with exported=true. They will end up twice in the final Eclipse project build path, but I don’t care too much.

I know, it’s a mess because of Eclipse having an only classpath. I would need to create two separate projects for this to work cleanly, but having two projects with 1 class each seems overwhelming to me (especially in a Gradle multiprojects which already has 6 projects).

You say that the exported flag should be honoured… well, the UI does not give me any clue of this. Neither the “Order and Export” tab of the “Java Build Path” project property page nor the “Classpath” tab of the launch configuration (once I add the project to the classpath) show that the entry I add to the “Project and EXternal Dependencies” container is exported… I will try to do some experiments.

Why, though, eclipse.classpath.file.withXml is not honoured by Buildship?

The libraries should automatically be included when you add the project to the launch config. This should absolutely work with the dependencies declaration I showed you above. Instead of compile you should use runtime though, as you don’t intend to compile against that lib.

Maybe there is something special about that TomCat launch config, but a launch generally doesn’t just include the exported entries, but everything that the project needs. Could you share a screenshot or screencast of this configuration?

When you look inside the container, you can expand details of each entry and see their properties.

Because Buildship works on the classpath model, not with XML.

Hi Stefan.
The Tomcat case is a bit tricky. What I’m trying to do now is not to set up the webapp class path, but the classpath of Tomcat itself. That is, I’m simulating the case in which I’m putting some JARs in Tomcat’s own lib directory. These JARs should be put on the Tomcat own classpath and then be available for Tomcat to work.

This is accomplished in Ecilpse by changing the Tomcat classpath in the Classpath tab of the Tomcat launch configuration. Here is a screenshot:

Under “User Entries” I’m adding my project (the one that contains my X509TrustManager implementation I want Tomcat to use). As you can see, when you add a project to the Tomcat classpath, you can optionally tell Eclipse to also add the project exported entries and/or the projects required by that project (but NOT the libraries/JARs required by that project, if not exported - these are not added to the classpath in any case, unless they are exported AND the first flag is checked).

In my case I would like to add my project (that is: the compiled classes of my project) and the libraries I need to compile/run my X509TrustManager implementation. These are defined in my build script in the custom source set called “appServer”. So, in my buildscript I have:

eclipse.classpath.file.whenMerged {
    configurations.appServerRuntime.each { 
        def lib = new org.gradle.plugins.ide.eclipse.model.Library(fileReference(it))
        lib.exported = true
        entries += lib
    }
}

(by the way, I removed the “eclipse.classpath.plusCpmfogiratopms << appServerRuntime” to avoid duplicate addition to the Eclipse build path). What I see, however, is that even if these dependencies are then added to the “Project and External Dependencies” container, if I then add my project to the Tomcat classpath and run Tomcat, my required libraries are not indeed in the classpath and I receive a lot of NoClassDefFound, ClassNotFound etc. exceptions.
After all, I still can’t see anywhere that the “exported” flag is honoured in this case.

In the above screenshot, after “shop-sc-auth” (which is my project) you see a list of JARs. These where automatically added by the UI when I put those JARs as manual entries in my .classpath file, with kind=“lib” and exported=“true”. If I remove those entries, though, and I use the code above to let Buildship add my dependencies to the “Project and External Dependencies”, those JARs are not shown in the Classpath tab (only sho-sc-auth is added). And, in fact, I get the NoClassDefFound/ClassNotFound exceptions at runtime.

Where should I see that an element inside “Project and External Dependencies” is exported?
In the project “Java Build Path”, under “Order and Export”, I can only check the whole “Project and External Dependencies” container for export, not any single JAR inside it.

I hope I’ve explained it somehow. If I only had “withXml” supported, I may edit the .classpath programmatically to add entries with exported=true to that file directlry, but currently I can’t. This would solve my problem.

Any suggestion would be appreciated.

That is horrible. I feel truly sorry that you have to work with that :confused:

Instead of creating new lib instances, just search the classpath for the existing ones and set their exported flag.

I might have remembered incorrectly, sorry.

withXml should never be necessary, everything can be configured on the model since 3.0. We will deprecate and remove withXml in 4.0

I just tried it with a simple example project and setting the exported flag to true works. I created a second plain Java project and let it depend on this one and the Junit dependency was exported to it. When I removed the eclipse.classpath snippet, the Junit dependency disappeared again as expected. Here it is:

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

repositories {
    jcenter()
}

dependencies {
    testCompile 'junit:junit:4.12'
}

eclipse.classpath.file.whenMerged { 
    def lib = entries.find { it.path.contains 'junit' }
    lib.exported = true
}

So you can do the same with your project. Let a plain Java project (non-Gradle) depend on it and see if you can access the class you are trying to export. If that works, then the Tomcat plugin is broken.

Hi Stefan,
your help has been precious. First of all, by restore the “eclipse.classpath.plusCpmfogiratopms << appServerRuntime” and then changing the exported flags of the existing entires in whenMerged, I fixed the problem that if a dependency was already in the build path, adding it a second time to set exported = true was “failing” because Buildship prevents a second addition of the same library (and hence the “exported” flag was not honoured for that dependency).

Secondly, I tried with a plain Java project requiring my Gradle project to check whether the exported flag on the single libraries within the “Project and External dependencies” works and indeed it works (i.e.: those libraries are in the dependent project build path). This means that the Tomcat Classpath composition code is actually borken.

I will open a bug against WTP as soon as I have a simple example workspace. By now, I must give up on trying to run this project in the WTP-managed Tomcat instance :frowning:

1 Like

Thanks for verifying this, Mauro! I hope the WTP team can get this fixed :slight_smile:

My best guess for the root cause: They are probably only checking the rawClasspath instead of the resolvedClasspath, so anything inside containers is lost.