Skip to content

Commit badff4f

Browse files
authored
[🍒 8187] Fix crash using Mule with JPMS (#8195)
* Mule: do not crash with JPMS (cherry picked from commit 0a7bf86) * muzzle (cherry picked from commit 4af59aa) * Applying suggestions and use ClassValue (cherry picked from commit 817c5ed)
1 parent 4f28172 commit badff4f

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

dd-java-agent/instrumentation/mule-4/build.gradle

+39-1
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,23 @@ muzzle {
3535
module = 'mule-core'
3636
versions = "[$muleVersion,)"
3737
javaVersion = "17"
38-
assertInverse true
3938
excludeDependency 'om.google.guava:guava'
4039
excludeDependency 'com.google.code.findbugs:jsr305'
4140
additionalDependencies +="org.mule.runtime:mule-tracer-customization-impl:$muleVersion"
4241
}
42+
43+
fail {
44+
name = 'before-4.5.0'
45+
group = 'org.mule.runtime'
46+
module = 'mule-core'
47+
versions = "[, $muleVersion)"
48+
excludeDependency 'om.google.guava:guava'
49+
excludeDependency 'com.google.code.findbugs:jsr305'
50+
}
4351
}
4452

4553
apply from: "$rootDir/gradle/java.gradle"
54+
apply plugin: "idea"
4655

4756
addTestSuiteForDir('mule46ForkedTest', 'test')
4857
addTestSuiteForDir('latestDepForkedTest', 'test')
@@ -81,6 +90,9 @@ configurations.all {
8190
}
8291

8392
sourceSets {
93+
main_java11 {
94+
java.srcDirs "${project.projectDir}/src/main/java11"
95+
}
8496
test {
8597
output.dir("$buildDir/generated-resources/test", builtBy: 'generateAppResources')
8698
}
@@ -92,6 +104,20 @@ sourceSets {
92104
}
93105
}
94106

107+
compileMain_java11Java.configure {
108+
setJavaVersion(it, 11)
109+
sourceCompatibility = JavaVersion.VERSION_1_8
110+
targetCompatibility = JavaVersion.VERSION_1_8
111+
}
112+
113+
jar {
114+
from sourceSets.main_java11.output
115+
}
116+
117+
forbiddenApisMain_java11 {
118+
failOnMissingClasses = false
119+
}
120+
95121
tasks.named("compileTestGroovy").configure {
96122
dependsOn 'mvnPackage', 'extractMuleServices'
97123
}
@@ -112,7 +138,13 @@ tasks.named("compileLatestDepForkedTestJava").configure {
112138
dependencies {
113139
compileOnly group: 'org.mule.runtime', name: 'mule-core', version: muleVersion
114140
compileOnly group: 'org.mule.runtime', name: 'mule-tracer-customization-impl', version: muleVersion
141+
compileOnly sourceSets.main_java11.output
115142

143+
main_java11CompileOnly project(':internal-api')
144+
main_java11CompileOnly project(':dd-java-agent:agent-tooling')
145+
main_java11CompileOnly project(':dd-java-agent:agent-bootstrap')
146+
147+
testImplementation sourceSets.main_java11.output
116148
testImplementation project(':dd-java-agent:instrumentation:aws-common')
117149
testImplementation project(':dd-java-agent:instrumentation:reactor-core-3.1')
118150
testImplementation project(':dd-java-agent:instrumentation:reactive-streams')
@@ -234,3 +266,9 @@ spotless {
234266
target "**/*.java"
235267
}
236268
}
269+
270+
idea {
271+
module {
272+
jdkName = '11'
273+
}
274+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package datadog.trace.instrumentation.mule4;
2+
3+
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
4+
5+
import com.google.auto.service.AutoService;
6+
import datadog.trace.agent.tooling.Instrumenter;
7+
import datadog.trace.agent.tooling.InstrumenterModule;
8+
import datadog.trace.agent.tooling.muzzle.Reference;
9+
import datadog.trace.api.Platform;
10+
11+
@AutoService(InstrumenterModule.class)
12+
public class JpmsMuleInstrumentation extends InstrumenterModule.Tracing
13+
implements Instrumenter.HasMethodAdvice, Instrumenter.ForKnownTypes {
14+
public JpmsMuleInstrumentation() {
15+
super("mule", "mule-jpms");
16+
}
17+
18+
@Override
19+
public boolean isEnabled() {
20+
return super.isEnabled() && Platform.isJavaVersionAtLeast(9);
21+
}
22+
23+
@Override
24+
public String[] knownMatchingTypes() {
25+
return new String[] {
26+
// same module but they can be initialized in any order
27+
"org.mule.runtime.tracer.customization.impl.info.ExecutionInitialSpanInfo",
28+
"org.mule.runtime.tracer.customization.impl.provider.LazyInitialSpanInfo",
29+
};
30+
}
31+
32+
@Override
33+
public String[] helperClassNames() {
34+
return new String[] {
35+
packageName + ".JpmsAdvisingHelper",
36+
};
37+
}
38+
39+
@Override
40+
public Reference[] additionalMuzzleReferences() {
41+
return new Reference[] {
42+
// added in 4.5.0
43+
new Reference.Builder("org.mule.runtime.tracer.api.EventTracer")
44+
.withMethod(
45+
new String[0],
46+
Reference.EXPECTS_NON_STATIC | Reference.EXPECTS_PUBLIC,
47+
"endCurrentSpan",
48+
"V",
49+
"Lorg/mule/runtime/api/event/Event;")
50+
.build(),
51+
};
52+
}
53+
54+
@Override
55+
public void methodAdvice(MethodTransformer transformer) {
56+
// it does not work with typeInitializer()
57+
transformer.applyAdvice(isConstructor(), packageName + ".JpmsClearanceAdvice");
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package datadog.trace.instrumentation.mule4;
2+
3+
import datadog.trace.api.GenericClassValue;
4+
import java.util.concurrent.atomic.AtomicBoolean;
5+
6+
public class JpmsAdvisingHelper {
7+
public static final ClassValue<AtomicBoolean> ALREADY_PROCESSED_CACHE =
8+
GenericClassValue.constructing(AtomicBoolean.class);
9+
10+
private JpmsAdvisingHelper() {}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package datadog.trace.instrumentation.mule4;
2+
3+
import static datadog.trace.instrumentation.mule4.JpmsAdvisingHelper.ALREADY_PROCESSED_CACHE;
4+
5+
import net.bytebuddy.asm.Advice;
6+
import net.bytebuddy.implementation.bytecode.assign.Assigner;
7+
8+
public class JpmsClearanceAdvice {
9+
@Advice.OnMethodExit(suppress = Throwable.class)
10+
public static void openOnReturn(@Advice.This(typing = Assigner.Typing.DYNAMIC) Object self) {
11+
final Class<?> cls = self.getClass();
12+
if (ALREADY_PROCESSED_CACHE.get(cls).compareAndSet(false, true)) {
13+
final Module module = cls.getModule();
14+
if (module != null) {
15+
try {
16+
// This call needs imperatively to be done from the same module we're adding exports
17+
// because the jdk is checking that the caller belongs to the same module.
18+
// The code of this advice is getting inlined into the constructor of the class belonging
19+
// to that package so it will work. Moving the same to a helper won't.
20+
module.addExports(cls.getPackageName(), module.getClassLoader().getUnnamedModule());
21+
} catch (Throwable ignored) {
22+
}
23+
}
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)