Fix `SpockRunner` BootstrapJar creation under Java9+
package datadog.trace.agent.test;
+import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
+import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;
import static datadog.trace.agent.tooling.Utils.BOOTSTRAP_PACKAGE_PREFIXES;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
import com.google.common.reflect.ClassPath;
import datadog.trace.agent.tooling.Utils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
@@ -105,20 +110,8 @@ public class SpockRunner extends Sputnik {
ClassLoader loader = AgentTestRunner.class.getClassLoader();
if (!(loader instanceof URLClassLoader)) {
// java9's system loader does not extend URLClassLoader
- // which breaks google ClassPath lookup
- Field f = null;
- try {
- f = loader.getClass().getDeclaredField("ucp");
- f.setAccessible(true);
- Object ucp = f.get(loader);
- loader = new URLClassLoader((URL[]) ucp.getClass().getMethod("getURLs").invoke(ucp), null);
- } catch (Exception e) {
- throw new RuntimeException(e);
- } finally {
- if (null != f) {
- f.setAccessible(false);
- }
- }
+ // which breaks Guava ClassPath lookup
+ loader = buildJavaClassPathClassLoader();
}
final ClassPath testCP = ClassPath.from(loader);
Set<String> bootstrapClasses = new HashSet<String>();
@@ -135,6 +128,30 @@ public class SpockRunner extends Sputnik {
TestUtils.createJarWithClasses(loader, bootstrapClasses.toArray(new String[0])).getFile());
}
+ /**
+ * Parse JVM classpath and return ClassLoader containing all classpath entries. Inspired by Guava.
+ *
+ * <p>TODO: use we cannot use Guava version when we can update Guava to version that has this
+ * logic, i.e. when we drop Java7 support.
+ */
+ private static ClassLoader buildJavaClassPathClassLoader() {
+ ImmutableList.Builder<URL> urls = ImmutableList.builder();
+ for (String entry : Splitter.on(PATH_SEPARATOR.value()).split(JAVA_CLASS_PATH.value())) {
+ try {
+ try {
+ urls.add(new File(entry).toURI().toURL());
+ } catch (SecurityException e) { // File.toURI checks to see if the file is a directory
+ urls.add(new URL("file", null, new File(entry).getAbsolutePath()));
+ }
+ } catch (MalformedURLException e) {
+ System.err.println(
+ String.format(
+ "Error injecting bootstrap jar: Malformed classpath entry: %s. %s", entry, e));
+ }
+ }
+ return new URLClassLoader(urls.build().toArray(new URL[0]), null);
+ }
+
/** Run test classes in a classloader which loads test classes before delegating. */
private static class InstrumentationClassLoader extends java.lang.ClassLoader {
final ClassLoader parent;
