Reputation: 11
I am trying to redefine an unloaded class and get java.lang.IllegalStateException: Class already loaded. The code is taken straight from the tutorial, only had to append "getLoaded()" for it to compile, see below. ByteBuddy version is the latest available 1.12.10, Java version 1.8.0_202. I tried a few other JVMs too getting same results.
I see that ByteArrayClassLoader is loading the class using Launcher$AppClassLoader instead of self. This causes the exception.
What do I need to make it work?
Thank you
class MyApplication {
public static void main(String[] args) throws Exception {
TypePool typePool = TypePool.Default.ofSystemLoader();
Class bar = new ByteBuddy()
.redefine(typePool.describe("foo.Bar").resolve(), // do not use 'Bar.class'
ClassFileLocator.ForClassLoader.ofSystemLoader())
.defineField("qux", String.class) // we learn more about defining fields later
.make()
.load(ClassLoader.getSystemClassLoader()) .getLoaded();
assertThat(bar.getDeclaredField("qux"), notNullValue());
}
}
Exception in thread "main" java.lang.IllegalStateException: Class already loaded: class foo.Bar
at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.load(ByteArrayClassLoader.java:362)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$WrappingDispatcher.load(ClassLoadingStrategy.java:367)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:148)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6166)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6154)
at MyApplication.main(UnloadedTest.java:17)
Upvotes: 1
Views: 866
Reputation: 44007
You are using a default class loading strategy which is one without use of Unsafe, but one that is creating a new class loader as a child of the supplied loader. This new loader will query its parent - the system class loader - first, which then loads Foo
. After Foo
is defined, it cannot be defined once again in the new child.
You can avoid this by injecting the class using an injection-based strategy like ClassLoadingStrategy.Default.INJECTION
or a lookup-based one (ClassLoadingStrategy.UsingLookup
). This way, no child loader is created but the altered class is injected into the system loader. Or you can disable querying the child loader by using ClassLoadingStrategy.Default.CHILD_FIRST
where any regular reference to Foo
in the reminder of the program will however load the original class in addition.
Upvotes: 1