User1291
User1291

Reputation: 8209

Tell bytebuddy to "not care" about generic information

So I ran into

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)

When trying to redefine a class that is already loaded with the bytecode the JVM loaded.

The code was in a preliminary step already transformed by a soot-framework and we suspect that some of the signature attributes might have become outdated or gone missing in that processs and that ByteBuddy simply insists on the correctness of the info it doesn't have.

Strictly speaking, ByteBuddy doesn't need that information, either. (Obviously, seeing how the signature attribute is optional and how the class is loaded and run by the JVM just fine.) So a quick way to check would be to tell byteBuddy to simply not care and see if that changes anything.

Is there a way to configure ByteBuddy in such a way?

(ByteBuddy version is 1.7.9)

(Project requires Java 7)

(class reloading is done

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

with

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

thanks to @kutschkern from how to debug an internal error? )

Upvotes: 4

Views: 471

Answers (2)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44042

You can set the net.bytebuddy.raw property to true what forces Byte Buddy into ignoring any generic type information. Know that setting this property might yield unexpected results as Byte Buddy is for example no longer able to properly resolve bridge methods and other things.

You can typically set this property when you are writing a Java agent that only transforms already existing methods, typically using Advice.

This is a strange error though, that implies a ParameterizedType that defines one of its getActualTypeArguments as null. Such errors do typically raise errors by the JVM generic signature parser.

As for the reflective operations, the yet unreleased Byte Buddy 1.7.11 will include a convenience method for setting the strategy.

Upvotes: 2

Holger
Holger

Reputation: 298529

I suppose that whatever the ByteBuddy frontend is doing here, is part of the support for all the other operations you could chain to perform another transformation. As said in the answer to your other question, you can skip these operations when have the byte code already:

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

Before Java 8, you’ll need Collections.<TypeDescription,byte[]>singletonMap(…).

when the class loading strategy is based on ClassReloadingStrategy.Strategy.REDEFINITION you can also use

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

as it will use the bytecode retrieved through the ClassFileLocator as base.

I suggest to stay with the standard way of acquiring the ClassReloadingStrategy implementation, as you did in your other question, I can’t recognize what you hope to gain with this more complicated reflective operation.

Upvotes: 3

Related Questions