Skip to content

Commit

Permalink
Add Muzzle reference creation for interfaces
Browse files Browse the repository at this point in the history
This will allow muzzle to fail if an implemented interface is missing.
  • Loading branch information
tylerbenson committed Dec 2, 2020
1 parent cb2cca9 commit bf7f42b
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import lombok.ToString;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.jar.asm.Type;

/** An immutable reference to a jvm class. */
@ToString
public class Reference {
private final Set<Source> sources;
private final String className;
Expand Down Expand Up @@ -129,11 +131,6 @@ private static Set<Flag> mergeFlags(final Set<Flag> flags1, final Set<Flag> flag
return merged;
}

@Override
public String toString() {
return "Reference<" + className + ">";
}

public static class Source {
private final String name;
private final int line;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,16 @@ public void visit(
refSourceClassName = Utils.getClassName(name);
refSourceType = Type.getType("L" + name + ";");
refSourceTypeInternalName = refSourceType.getInternalName();
// Additional references we could check
// - supertype of class and visible from this package
// - interfaces of class and visible from this package

// Add references to each of the interfaces.
for (String iface : interfaces) {
addReference(
new Reference.Builder(iface)
.withSource(refSourceClassName, 0) // We don't have a specific line number to use.
.withFlag(Reference.Flag.PUBLIC)
.build());
}
// the super type is handled by the method visitor to the constructor.
super.visit(version, access, name, signature, superName, interfaces);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ class ReferenceCreatorTest extends AgentTestRunner {
aFieldRefs.size() == 2
}

def "ref test"() {
setup:
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.A.getName(), this.getClass().getClassLoader())
def a = references.get('muzzle.TestClasses$MethodBodyAdvice$A')
def b = references.get('muzzle.TestClasses$MethodBodyAdvice$B')

expect:
references.keySet() == ['muzzle.TestClasses$MethodBodyAdvice$A', 'muzzle.TestClasses$MethodBodyAdvice$B'].toSet()

and: "doesn't need to reference self"
!(a.getSources().any { it.name == 'muzzle.TestClasses$MethodBodyAdvice$A' })
}

def "protected ref test"() {
setup:
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.B2.getName(), this.getClass().getClassLoader())
Expand All @@ -67,6 +80,24 @@ class ReferenceCreatorTest extends AgentTestRunner {
references.get('muzzle.TestClasses$MethodBodyAdvice$A') != null
}

def "interface impl creates references"() {
setup:
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.SomeImplementation.getName(), this.getClass().getClassLoader())

expect:
references.get('muzzle.TestClasses$MethodBodyAdvice$SomeInterface') != null
references.size() == 1
}

def "child class creates references"() {
setup:
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(MethodBodyAdvice.A2.getName(), this.getClass().getClassLoader())

expect:
references.get('muzzle.TestClasses$MethodBodyAdvice$A') != null
references.size() == 1
}

def "instanceof creates references"() {
setup:
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(InstanceofAdvice.getName(), this.getClass().getClassLoader())
Expand All @@ -82,7 +113,7 @@ class ReferenceCreatorTest extends AgentTestRunner {
Map<String, Reference> references = ReferenceCreator.createReferencesFrom(TestClasses.InDyAdvice.getName(), this.getClass().getClassLoader())

expect:
references.get('muzzle.TestClasses$MethodBodyAdvice$SomeImplementation') != null
references.get('muzzle.TestClasses$MethodBodyAdvice$HasMethod') != null
references.get('muzzle.TestClasses$MethodBodyAdvice$B') != null
}

Expand Down
5 changes: 2 additions & 3 deletions dd-java-agent/testing/src/test/java/muzzle/TestClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,9 @@ public static boolean instanceofMethod(final Object a) {

// Can't test this until java 7 is dropped.
public static class InDyAdvice {
// public static MethodBodyAdvice.SomeInterface indyMethod(
// final MethodBodyAdvice.SomeImplementation a) {
// public static MethodBodyAdvice.HasMethod indyMethod(final MethodBodyAdvice.HasMethod a) {
// Runnable aStaticMethod = MethodBodyAdvice.B::aStaticMethod;
// return a::someMethod;
// return a::requiredMethod;
// }
}
}

0 comments on commit bf7f42b

Please sign in to comment.