mirror of https://github.com/sbt/sbt.git
enable ServiceLoader discovery across classloader layers
java.util.ServiceLoader uses findResources(), which was not overriden in ReverseLookupClassLoader, causing resources available in the descendant classloader not to be discovered when a service loader instance was using the top classloader.
This commit is contained in:
parent
f5eae27c69
commit
331ca6ec9b
|
|
@ -8,7 +8,9 @@
|
||||||
package sbt.internal;
|
package sbt.internal;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import sbt.util.Logger;
|
import sbt.util.Logger;
|
||||||
|
|
@ -64,6 +66,31 @@ final class ReverseLookupClassLoader extends ManagedClassLoader {
|
||||||
return url != null ? url : directDescendant.get().findResource(name);
|
return url != null ? url : directDescendant.get().findResource(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<URL> findResources(String name) throws IOException {
|
||||||
|
final Enumeration<URL> parentResources = super.findResources(name);
|
||||||
|
|
||||||
|
if (directDescendant.get() == null) {
|
||||||
|
return parentResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Enumeration<URL> directDescendantResources = directDescendant.get().findResources(name);
|
||||||
|
return new Enumeration<URL>() {
|
||||||
|
@Override
|
||||||
|
public boolean hasMoreElements() {
|
||||||
|
return parentResources.hasMoreElements() || directDescendantResources.hasMoreElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL nextElement() {
|
||||||
|
if (parentResources.hasMoreElements()) {
|
||||||
|
return parentResources.nextElement();
|
||||||
|
}
|
||||||
|
return directDescendantResources.nextElement();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void setup(final File tmpDir) {
|
void setup(final File tmpDir) {
|
||||||
setTempDir(tmpDir);
|
setTempDir(tmpDir);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
val dependency = project.settings(exportJars := true)
|
||||||
|
val descendant = project.dependsOn(dependency).settings(
|
||||||
|
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test"
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package dependency;
|
||||||
|
|
||||||
|
public class Runnable implements java.lang.Runnable {
|
||||||
|
public void run() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
dependency.Runnable
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
descendant.Runnable
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package descendant
|
||||||
|
|
||||||
|
class Runnable extends java.lang.Runnable {
|
||||||
|
override def run(): Unit = ()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import collection.JavaConverters._
|
||||||
|
import org.scalatest._
|
||||||
|
|
||||||
|
class ServiceLoaderTest extends FlatSpec {
|
||||||
|
val expected = Set(classOf[dependency.Runnable], classOf[descendant.Runnable])
|
||||||
|
|
||||||
|
val descendantClassLoader = classOf[descendant.Runnable].getClassLoader
|
||||||
|
val descendantRunnableLoader = java.util.ServiceLoader.load(classOf[java.lang.Runnable], descendantClassLoader)
|
||||||
|
val descendantLoadedClasses = descendantRunnableLoader.iterator().asScala.map(_.getClass).toSet
|
||||||
|
assert(descendantLoadedClasses == expected)
|
||||||
|
|
||||||
|
// this was the actual problem, when classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.AllLibraryJars
|
||||||
|
val dependencyClassLoader = classOf[dependency.Runnable].getClassLoader
|
||||||
|
val dependencyRunnableLoader = java.util.ServiceLoader.load(classOf[java.lang.Runnable], dependencyClassLoader)
|
||||||
|
val dependencyLoadedClasses = dependencyRunnableLoader.iterator().asScala.map(_.getClass).toSet
|
||||||
|
assert(dependencyLoadedClasses == expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
> set descendant / Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.AllLibraryJars
|
||||||
|
|
||||||
|
> test
|
||||||
|
|
||||||
|
> set descendant / Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.ScalaLibrary
|
||||||
|
|
||||||
|
> test
|
||||||
Loading…
Reference in New Issue