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.