Check parent classloaders when resource location fails.
MODIFY
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java
@@ -41,6 +41,7 @@ public class AgentInstaller {
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(new LoggingListener())
+ .with(new DDLocationStrategy())
.ignore(nameStartsWith("datadog.trace."))
.or(nameStartsWith("datadog.opentracing."))
.or(nameStartsWith("datadog.slf4j."))

ADD
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java
+package datadog.trace.agent.tooling;
+
+import java.util.ArrayList;
+import java.util.List;
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.dynamic.ClassFileLocator;
+import net.bytebuddy.utility.JavaModule;
+
+/**
+ * Locate resources with the loading classloader. If the loading classloader cannot find the desired
+ * resource, check up the classloader hierarchy until a resource is found or the bootstrap loader is
+ * reached.
+ */
+public class DDLocationStrategy implements AgentBuilder.LocationStrategy {
+ private static final ClassLoader BOOTSTRAP_RESOURCE_LOCATOR = new ClassLoader(null) {};
+
+ @Override
+ public ClassFileLocator classFileLocator(ClassLoader classLoader, JavaModule javaModule) {
+ List<ClassFileLocator> locators = new ArrayList<ClassFileLocator>();
+ while (classLoader != null) {
+ locators.add(ClassFileLocator.ForClassLoader.of(classLoader));
+ classLoader = classLoader.getParent();
+ }
+ locators.add(ClassFileLocator.ForClassLoader.of(BOOTSTRAP_RESOURCE_LOCATOR));
+ return new ClassFileLocator.Compound(locators.toArray(new ClassFileLocator[0]));
+ }
+}

ADD
dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy
+package datadog.trace.agent.test
+
+import datadog.trace.agent.tooling.DDLocationStrategy
+import net.bytebuddy.agent.builder.AgentBuilder
+import net.bytebuddy.dynamic.ClassFileLocator
+import spock.lang.Specification
+
+class ResourceLocatingTest extends Specification {
+ def "finds resources from parent classloader"() {
+ setup:
+ final String[] lastLookup = new String[1]
+ ClassLoader childLoader = new ClassLoader(this.getClass().getClassLoader()) {
+ @Override
+ URL getResource(String name) {
+ lastLookup[0] = name
+ // do not delegate resource lookup
+ return findResource(name)
+ }
+ }
+ ClassFileLocator locator = new DDLocationStrategy().classFileLocator(childLoader, null)
+ ClassFileLocator defaultLocator = AgentBuilder.LocationStrategy.ForClassLoader.STRONG.classFileLocator(childLoader, null)
+
+ expect:
+ locator.locate("java/lang/Object").isResolved()
+ // lastLookup ensures childLoader was checked before parent for the resource
+ lastLookup[0] == "java/lang/Object.class"
+ (lastLookup[0] = null) == null
+
+ !defaultLocator.locate("java/lang/Object").isResolved()
+ lastLookup[0] == "java/lang/Object.class"
+ }
+}

Check parent classloaders when resource location fails.