告诉bytebuddy“不关心”通用信息

时间:2018-02-20 09:46:57

标签: java bytecode instrumentation byte-buddy

所以我遇到了

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$1.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的字节码的类。

代码处于已经由烟灰框架转换的初步步骤中,我们怀疑某些签名属性可能已经过时或在该过程中丢失,并且ByteBuddy只是坚持信息的正确性而不是'有。。

严格来说,ByteBuddy也不需要这些信息。 (显然,看看签名属性是如何可选的以及JVM如何加载和运行类就好了。) 因此,检查的一种快速方法是告诉byteBuddy根本不关心并查看是否会发生任何变化。

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

(ByteBuddy版本为1.7.9

(项目需要Java 7)

(课程重新加载

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);
        }
    }
}

感谢来自how to debug an internal error?)的@kutschkern

2 个答案:

答案 0 :(得分:3)

我认为无论ByteBuddy前端在这里做什么,都是对所有其他操作的支持的一部分,你可以链接到另一个转换。如the answer to your other question中所述,当已经有字节代码时,您可以跳过这些操作:

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

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

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

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

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

我建议继续采用ClassReloadingStrategy实施的标准方式,正如您在其他问题中所做的那样,我无法认识到您希望通过这种更复杂的反射操作获得什么。

答案 1 :(得分:1)

您可以将net.bytebuddy.raw属性设置为true,这会迫使Byte Buddy忽略任何泛型类型信息。知道设置此属性可能会产生意外结果,因为Byte Buddy不再能够正确解析桥接方法和其他事情。

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

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

至于反思操作,未发布的Byte Buddy 1.7.11将包含一种设定策略的便捷方法。