超类层次结构正常时的ClassCircularityError

ClassCircularityError when the superclass hierarchy is normal

我正在为我的个人项目开发 java 代理,遇到了一个非常奇怪的错误。当我 运行 我的 IDE 中的方法 "register" 工作正常。无圆度误差。但是当我导出代理并将其与启动参数 javaagent:"agent.jar" 一起使用时,它会崩溃并给出 ClassCircularityError (Looping superclass hierarchy).

public class Refactorer implements ClassFileTransformer {
    private static final Set<AbstractMatcher<String>> matchers = new HashSet<AbstractMatcher<String>>();

    public static void register(AbstractMatcher<String> matcher) {
        matchers.add(matcher);
    }

    public byte[] transform(ClassLoader loader, String name, Class<?> clazz, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {}
}

堆栈跟踪

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
    at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
Caused by: java.lang.ClassCircularityError: java/util/Set
    at me.vader.Refactorer.register(Refactorer.java:42)
    at me.vader.Setup.registerModders(Setup.java:30)
    at me.vader.Agent.setAndAddTransformer(Agent.java:37)
    at me.vader.Agent.premain(Agent.java:18)

真正让我感到困惑的是,当我检查编译代理中的超类层次结构时,它打印得很好。

测试:

Class c = matchers.getClass();
int i = 0;
while (c != null){
    System.out.println("Class (Sup x" + i+ "): " + c.getName());
    c = c.getSuperclass();
    i++;
}

i = 0;
c = matcher.getClass();
while (c != null){
    System.out.println("Class (Sup x" + i+ "): " + c.getName());
    c = c.getSuperclass();
    i++;
}

输出:

// The "matchers"
Class (Sup x0): java.util.HashSet
Class (Sup x1): java.util.AbstractSet
Class (Sup x2): java.util.AbstractCollection
Class (Sup x3): java.lang.Object

// The matcher being added to "matchers"
Class (Sup x0): me.vader.match.ClassMatcher
Class (Sup x1): me.vader.match.AbstractMatcher
Class (Sup x2): java.lang.Object

似乎 classes 没有按正确的顺序加载。我不确定为什么,但似乎就是这样。

我的修复是在 Refactorer 中添加以下内容 class:

static {
    Serializable.class.getName();
    Cloneable.class.getName();
    Iterable .class.getName();
    Collection.class.getName();
    AbstractCollection.class.getName();
    Set.class.getName();
    AbstractSet.class.getName();
    HashSet.class.getName();
}

强制以正确的顺序加载它们。它很丑,但它有效。