告诉 bytebuddy 到 "not care" 通用信息

Tell bytebuddy to "not care" about generic information

所以我运行进入

Exception in thread "Thread-0" java.lang.IllegalArgumentException: Unknown type: null
    at net.bytebuddy.description.type.TypeDefinition$Sort.describe(TypeDefinition.java:213)
    at net.bytebuddy.description.type.TypeDescription$Generic$OfParameterizedType$ForLoadedType$ParameterArgumentTypeList.get(TypeDescription.java:4595)
    at net.bytebuddy.description.type.TypeDescription$Generic$OfParameterizedType$ForLoadedType$ParameterArgumentTypeList.get(TypeDescription.java:4569)
    at java.util.AbstractList$Itr.next(AbstractList.java:358)
    at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor.onParameterizedType(TypeDescription.java:1556)
    at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor$ForDetachment.onParameterizedType(TypeDescription.java:1709)
    at net.bytebuddy.description.type.TypeDescription$Generic$OfParameterizedType.accept(TypeDescription.java:4407)
    at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor.onParameterizedType(TypeDescription.java:1557)
    at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor$ForDetachment.onParameterizedType(TypeDescription.java:1709)
    at net.bytebuddy.description.type.TypeDescription$Generic$OfParameterizedType.accept(TypeDescription.java:4407)
    at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection.accept(TypeDescription.java:5308)
    at net.bytebuddy.description.field.FieldDescription$AbstractBase.asToken(FieldDescription.java:143)
    at net.bytebuddy.description.field.FieldDescription$AbstractBase.asToken(FieldDescription.java:87)
    at net.bytebuddy.description.field.FieldList$AbstractBase.asTokenList(FieldList.java:47)
    at net.bytebuddy.dynamic.scaffold.InstrumentedType$Factory$Default.represent(InstrumentedType.java:222)
    at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:698)
    at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:676)
    at parc.Foo.redefineClass(Foo.java:137)

当试图重新定义一个已经加载了 JVM 加载的字节码的 class 时。

代码处于初步阶段,已经 运行 由 soot-framework 形成,我们怀疑某些签名属性可能已经过时或在该过程中丢失,而 ByteBuddy 只是坚持它没有的信息的正确性。

严格来说,ByteBuddy 也不需要这些信息。 (显然,看看 signature 属性是如何可选的,以及 JVM 如何加载 class 和 运行 就好了。) 因此,一种快速检查的方法是告诉 byteBuddy 根本不在乎,看看是否有任何改变。

有没有办法以这种方式配置 ByteBuddy?

(ByteBuddy 版本为1.7.9

(项目需要Java 7)

(class 重新加载完成

private void redefineClass(String classname, byte[] bytecode) {
    ClassFileLocator cfl = ClassFileLocator.Simple.of(classname,bytecode);

    Class clazz;
    try{
        clazz = Class.forName(classname);
    }catch(ClassNotFoundException e){
        throw new RuntimeException(e);
    }

    Debug._print("REDEFINING %s",clazz.getName());

    new ByteBuddy()
            .redefine(clazz,cfl)
            .make()
            .load(clazz.getClassLoader(),ByteBuddyConfig.reloadingStrategy)
            ;
}

public class ByteBuddyConfig {

    static final ClassReloadingStrategy reloadingStrategy;
    static {
        try {
            reloadingStrategy = new ClassReloadingStrategy(
                    (Instrumentation) ClassLoader.getSystemClassLoader()
                            .loadClass("net.bytebuddy.agent.Installer")
                            .getMethod("getInstrumentation")
                            .invoke(null),
                    ClassReloadingStrategy.Strategy.RETRANSFORMATION);
        }catch(ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e){
            throw new RuntimeException(e);
        }
    }
}

感谢来自 的@kutschkern)

我想无论 ByteBuddy 前端在这里做什么,都是对您可以链接以执行另一个转换的所有其他操作的支持的一部分。如中所述,如果已经有字节码,可以跳过这些操作:

ClassReloadingStrategy s = ClassReloadingStrategy.fromInstalledAgent();
s.load(clazz.getClassLoader(),
    Collections.singletonMap(new TypeDescription.ForLoadedType(clazz), bytecode));

在 Java8 之前,您需要 Collections.<TypeDescription,byte[]>singletonMap(…)

当class加载策略基于ClassReloadingStrategy.Strategy.REDEFINITION时,您也可以使用

ClassReloadingStrategy s = ClassReloadingStrategy.fromInstalledAgent();
s.reset(ClassFileLocator.Simple.of(classname, bytecode), clazz);

因为它将使用通过 ClassFileLocator 检索到的字节码作为基础。

我建议继续使用获取 ClassReloadingStrategy 实现的标准方式,就像您在其他问题中所做的那样,我无法识别您希望通过这种更复杂的反射操作获得什么。

您可以将 net.bytebuddy.raw 属性 设置为 true 以强制 Byte Buddy 忽略任何通用类型信息。请注意,设置此 属性 可能会产生意想不到的结果,例如 Byte Buddy 不再能够正确解析桥接方法和其他内容。

当您编写仅转换现有方法的 Java 代理时,您通常可以设置此 属性,通常使用 Advice.

不过,这是一个奇怪的错误,这意味着 ParameterizedType 将其 getActualTypeArguments 之一定义为 null。此类错误通常会引发 JVM 通用签名解析器的错误。

关于反射操作,尚未发布的 Byte Buddy 1.7.11 将包含一个用于设置策略的便捷方法。