Adding libraries into Ant classpath only


(Eero Helenius) #1

I’m the maintainer of a Gradle plugin for a documentation tool called DITA Open Toolkit.

I originally wrote the plugin when I discovered that the Gradle daemon decreases DITA-OT build times dramatically because of its ability to reuse JVM instances, but Gradle has a whole bunch of features that are very well-suited for a tool like DITA-OT.

The way to run DITA-OT is to basically run to put its dependencies into the classpath and run Ant, so what I do in my plugin is to add the DITA-OT dependencies into the Ant class loader like this:

jars.each {
  org.apache.tools.ant.Project.class.getClassLoader().addURL(it.toURI().toURL())
}

This worked fine until DITA-OT added Guava into its list of dependencies. Ever since, builds that use my plugin keep failing with errors like this one:

Could not create service of type FileSnapshotter using TaskExecutionServices.createFileSnapshotter().
> com.google.common.cache.AbstractCache$SimpleStatsCounter cannot be cast to com.google.common.cache.AbstractCache$StatsCounter

(There’s a number of different Guava-related errors that can pop up.)

Presumably the reason is that Gradle depends on a different version of Guava than DITA-OT and the classloader picks the version at random and hands it to Gradle.

You can reproduce the issue with a Gradle buildfile like this (the Gradle daemon needs to be enabled):

defaultTasks 'x'

task x  {
    def url = 'http://central.maven.org/maven2/com/google/guava/guava/19.0/guava-19.0.jar'
    def file = new File('guava-19.0.jar')

    if (!file.exists()) {
        def stream = file.newOutputStream()
        stream << new URL(url).openStream()
        stream.close()
    }

    // Comment this line and the build will succeed.
    org.apache.tools.ant.Project.class.getClassLoader().addURL(file.toURI().toURL())
}

Is there any way around this issue? I could fork the JVM for DITA-OT, of course, but that’ll mean losing the performance benefit, which can be up to 170%, so I’d like to avoid that if possible.


(Lari Hotari) #2

I replied to this in the thread Guava classpath conflict and the Gradle daemon . Using the internal IsolatedAntBuilder seems to be the way to add libraries to Ant classpath only.