当我在某些情况下使用 ByteBuddy subclass a class 时,我得到 IllegalAccessErrors。为什么?

When I subclass a class using ByteBuddy in certain situations I get IllegalAccessErrors. Why?

(我是 ByteBuddy 的新用户。我使用的是 ByteBuddy 版本 1.10.8 和 JDK 11,没有模块路径或模块系统的任何其他部分。)

我有一个嵌套的 class 声明如下:

public static class Frob {
  protected Frob() {
    super();
  }
  public String sayHello() {
    return "Hello!";
  }  
}

(其包含class是foo.bar.TestExplorations。)

当我创建一个名为 foo.bar.CrapFrob 的动态子 class 时,如下所示,一切正常,如我所料:

final String className = "foo.bar.Crap";
final DynamicType.Unloaded<?> dynamicTypeUnloaded = new ByteBuddy()
  .subclass(Frob.class)
  .name(className)
  .make();
final Class<?> mySubclass = dynamicTypeUnloaded
  .load(this.getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
  .getLoaded();
assertNotNull(mySubclass);
assertEquals(className, mySubclass.getName());
final Object frobSubclass = mySubclass.newInstance();
assertTrue(frobSubclass instanceof Frob);

但是如果我更改 Frob 的构造函数使其成为包私有的,我会从最终断言中得到以下错误:

java.lang.IllegalAccessError: class foo.bar.Crap tried to access method 'void foo.bar.TestExplorations$Frob.<init>()' (foo.bar.Crap is in unnamed module of loader net.bytebuddy.dynamic.loading.ByteArrayClassLoader @5e3d57c7; foo.bar.TestExplorations$Frob is in unnamed module of loader 'app')

由于某些原因,Crap 的构造函数无法调用 super(),即使 CrapFrob 在同一个包中,并且 Frob()被定义为包私有。

我觉得 JDK 模块系统是罪魁祸首,即使我故意(非常非常故意)不使用它。我知道模块系统不喜欢拆分包,这在我看来就是在这里进行的。是否有构造函数策略或其他机制来解决此问题?

在Java中,如果一个包具有相同的名称并且由相同的class加载程序加载(与class相同),则该包仅等于另一个包es)。如果您使用 WRAPPER 策略,则无法访问任何超级 class 的包私有成员。 Byte Buddy 不禁止生成,因为在 javac 中这样做是合法的,但您需要使用 INJECTION 策略来执行您想要的操作,以确保 classes 由相同的 class装载机。请注意,它使用内部 API,因此,从 Java 9 开始,您宁愿使用 ForLookup class 加载策略。