2

Let's say I want to dynamically create class B <: A that I require to be visible everywhere where A is visible.

(Strictly speaking, I want to create class B <: A as an alternative to existing C <: A and require it to be visible everywhere, where C is visible. But that's a detail.)

And if I understood the classloader hierarchy thing correctly, getting B loaded from the same classloader that loaded A should do the trick.

ByteBuddy has this feature of specifying at which classloader to inject a new class

ByteBuddy byteBuddy = new ByteBuddy();

DynamicType.Builder builder = byteBuddy
        .subclass(A.class)
        .name("B")
        .andSoOn
        .blah
        ;

DynamicType.Unloaded<?> loadable = builder.make();


loadable.load(A.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION);

I can get the produced bytecode by means of

 byte[] bytecode = loadable.getBytes();

Which I can then modify and reload.

I've run into some issues with that, though: Why doesn't ASM call my ``visitCode``?

and even if I could get that to work, I don't know if that loading process would re-execute the static initialiser (which I want it to and what I was trying to test with the code in the other question) or not.

So the "safer" route would be to get finished bytecode from ASM before loading the class and then directly load that bytecode.

How do I do that, though?

The "obvious" approach would be to get a DynamicType.Unloaded from the byte[] and then use its load method like above.

I cannot seem to find a way to do that, though.

ClassLoaderByteArrayInjector has a very promising name. But it expects a TypeDescriptor, which -- again -- I cannot seem to get for an unloaded class.

How do I pull this off?

2 Answers 2

3

Note that for any ClassLoadingStrategy, only the name of a type matters, so you can simply use loadable.getTypeDescription(), e.g.

ClassLoadingStrategy.Default.INJECTION.load(A.class.getClassLoader(),
    Collections.singletonMap(loadable.getTypeDescription(), finalBytes));

as long as your subsequent transformations did not change the name. If you are going to use the resulting map, you have to be aware that the TypeDescription does not reflect your changes made after loadable.getBytes(), so you may recreate the type description from the resulting Class<?>, e.g. via new TypeDescription.ForLoadedType(resultClass).

Note that the class, you have linked to, has a method taking only a name and byte code, it’s just not static, so this documentation promises that

Class<?> resultClass
    = new ClassLoaderByteArrayInjector(A.class.getClassLoader())
    .inject("B", finishedClass);

should work (I couldn’t test it though).

Note that for a lot of cases, e.g. A never references B and B doesn’t access package-private elements of A, you can simply define a class with a derived class loader

Class<?> resultClass = new ClassLoader(A.class.getClassLoader()) {
    Class<?> get(String name, byte[] code) {
        return defineClass(name, code, 0, code.length);
    }
}.get("B", finishedClass);

instead of injecting it into A’s loader.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. Couldn't test the ClassLoaderByteArrayInjector either because it wouldn't let me import the class ... didn't pay attention to the version number in the url. Guess the class no longer exists. But your first way works. A may eventually reference B (as may all classes that have ever used A) so your third isn't an option for me. But nice addition for others who find it.
1

Note that the ClassLoaderByteArrayInjector is from an early beta version of Byte Buddy and does no longer exist. You are maybe looking for ClassInjector capabilities?

You can use these injectors but if you modify byte code with Byte Buddy to begin with you can just use the class loading strategies which are built on top of the class injector for the injection strategy.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.