byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

The example in "Working with unloaded classes" is wrong.

Open diguage opened this issue 3 years ago • 8 comments

The example in "Working with unloaded classes" is wrong.

class MyApplication {
  public static void main(String[] args) {
    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());
    assertThat(bar.getDeclaredField("qux"), notNullValue());
  }
}

diguage avatar Jul 31 '22 12:07 diguage

How so? What is wrong with it?

raphw avatar Jul 31 '22 19:07 raphw

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()); // It returns net.bytebuddy.dynamic.DynamicType.Loaded, not Class.

If invoke getLoaded() method, then return the Class. But it throws an exception:

Class<?> loadedClass = new ByteBuddy()
        .redefine(typePool.describe("foo.Bar").resolve(), // do not use 'Bar.class'
                ClassFileLocator.ForClassLoader.ofSystemLoader())
        .defineField("qux", String.class)
        .make()
        .load(ClassLoader.getSystemClassLoader())
        .getLoaded(); // invoke the method to return Class. But the code throws Exception in thread "main" java.lang.IllegalStateException: Class already loaded: class foo.Bar

The log:

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 com.diguage.cafe.jiadao.Test6.main(Test6.java:26)
$ java -version
openjdk version "1.8.0_332"
OpenJDK Runtime Environment Corretto-8.332.08.1 (build 1.8.0_332-b08)
OpenJDK 64-Bit Server VM Corretto-8.332.08.1 (build 25.332-b08, mixed mode)

byte-buddy.version: 1.12.12

diguage avatar Aug 01 '22 02:08 diguage

I assume that you loaded the class somewhere in com.diguage.cafe.jiadao.Test6.main. There's a unit test to check that this works in Byte Buddy.

raphw avatar Aug 01 '22 11:08 raphw

@raphw OK, let me research it.

diguage avatar Aug 02 '22 06:08 diguage

I found the test example: https://github.com/raphw/byte-buddy/blob/master/byte-buddy-dep/src/test/java/net/bytebuddy/ByteBuddyTutorialExamplesTest.java#L155

The test example invokes .getLoaded():

image

diguage avatar Aug 02 '22 16:08 diguage

There is one more difference:

image

image

diguage avatar Aug 02 '22 16:08 diguage

I commented on your PR also. The test is different to keep it repeatable on the same VM. That's probably why this glitched through. Try the system loader with the INJECT strategy, then I think this would work.

raphw avatar Aug 02 '22 20:08 raphw

That being the case, whether the tutorial can correspond to a specific version of byteBuddy, I think this is a good thing, if the sentence does not go smoothly, please forgive me for using google translate.

Jason-purse avatar Aug 10 '22 07:08 Jason-purse