diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java index d54baf22c4..36c5ee75d0 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java +++ b/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.")) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java new file mode 100644 index 0000000000..15ef5d1c99 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java @@ -0,0 +1,27 @@ +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 locators = new ArrayList(); + 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])); + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy new file mode 100644 index 0000000000..fc2fa26337 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy @@ -0,0 +1,32 @@ +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" + } +}