Skip to content

Commit f489ebd

Browse files
committed
Add Muzzle reference creation for interfaces
This will allow muzzle to fail if an implemented interface is missing.
1 parent ff239d7 commit f489ebd

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/Reference.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
import java.util.LinkedHashSet;
1010
import java.util.List;
1111
import java.util.Set;
12+
import lombok.ToString;
1213
import net.bytebuddy.jar.asm.Opcodes;
1314
import net.bytebuddy.jar.asm.Type;
1415

1516
/** An immutable reference to a jvm class. */
17+
@ToString
1618
public class Reference {
1719
private final Set<Source> sources;
1820
private final String className;
@@ -129,11 +131,6 @@ private static Set<Flag> mergeFlags(final Set<Flag> flags1, final Set<Flag> flag
129131
return merged;
130132
}
131133

132-
@Override
133-
public String toString() {
134-
return "Reference<" + className + ">";
135-
}
136-
137134
public static class Source {
138135
private final String name;
139136
private final int line;

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceCreator.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,16 @@ public void visit(
180180
refSourceClassName = Utils.getClassName(name);
181181
refSourceType = Type.getType("L" + name + ";");
182182
refSourceTypeInternalName = refSourceType.getInternalName();
183-
// Additional references we could check
184-
// - supertype of class and visible from this package
185-
// - interfaces of class and visible from this package
183+
184+
// Add references to each of the interfaces.
185+
for (String iface : interfaces) {
186+
addReference(
187+
new Reference.Builder(iface)
188+
.withSource(refSourceClassName, 0) // We don't have a specific line number to use.
189+
.withFlag(Reference.Flag.PUBLIC)
190+
.build());
191+
}
192+
// the super type is handled by the method visitor to the constructor.
186193
super.visit(version, access, name, signature, superName, interfaces);
187194
}
188195

dd-java-agent/testing/src/test/groovy/muzzle/ReferenceCreatorTest.groovy

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ class ReferenceCreatorTest extends AgentTestRunner {
4949
aFieldRefs.size() == 2
5050
}
5151

52+
def "ref test"() {
53+
setup:
54+
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.A.getName(), this.getClass().getClassLoader())
55+
def a = references.get('muzzle.TestClasses$MethodBodyAdvice$A')
56+
def b = references.get('muzzle.TestClasses$MethodBodyAdvice$B')
57+
58+
expect:
59+
references.keySet() == ['muzzle.TestClasses$MethodBodyAdvice$A', 'muzzle.TestClasses$MethodBodyAdvice$B'].toSet()
60+
61+
and: "doesn't need to reference self"
62+
!(a.getSources().any { it.name == 'muzzle.TestClasses$MethodBodyAdvice$A' })
63+
}
64+
5265
def "protected ref test"() {
5366
setup:
5467
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.B2.getName(), this.getClass().getClassLoader())
@@ -67,6 +80,24 @@ class ReferenceCreatorTest extends AgentTestRunner {
6780
references.get('muzzle.TestClasses$MethodBodyAdvice$A') != null
6881
}
6982

83+
def "interface impl creates references"() {
84+
setup:
85+
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.SomeImplementation.getName(), this.getClass().getClassLoader())
86+
87+
expect:
88+
references.get('muzzle.TestClasses$MethodBodyAdvice$SomeInterface') != null
89+
references.size() == 1
90+
}
91+
92+
def "child class creates references"() {
93+
setup:
94+
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.A2.getName(), this.getClass().getClassLoader())
95+
96+
expect:
97+
references.get('muzzle.TestClasses$MethodBodyAdvice$A') != null
98+
references.size() == 1
99+
}
100+
70101
def "instanceof creates references"() {
71102
setup:
72103
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(InstanceofAdvice.getName(), this.getClass().getClassLoader())
@@ -82,7 +113,7 @@ class ReferenceCreatorTest extends AgentTestRunner {
82113
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(TestClasses.InDyAdvice.getName(), this.getClass().getClassLoader())
83114

84115
expect:
85-
references.get('muzzle.TestClasses$MethodBodyAdvice$SomeImplementation') != null
116+
references.get('muzzle.TestClasses$MethodBodyAdvice$HasMethod') != null
86117
references.get('muzzle.TestClasses$MethodBodyAdvice$B') != null
87118
}
88119

dd-java-agent/testing/src/test/java/muzzle/TestClasses.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,9 @@ public static boolean instanceofMethod(final Object a) {
9595

9696
// Can't test this until java 7 is dropped.
9797
public static class InDyAdvice {
98-
// public static MethodBodyAdvice.SomeInterface indyMethod(
99-
// final MethodBodyAdvice.SomeImplementation a) {
98+
// public static MethodBodyAdvice.HasMethod indyMethod(final MethodBodyAdvice.HasMethod a) {
10099
// Runnable aStaticMethod = MethodBodyAdvice.B::aStaticMethod;
101-
// return a::someMethod;
100+
// return a::requiredMethod;
102101
// }
103102
}
104103
}

0 commit comments

Comments
 (0)