Когда я делаю подкласс класса с помощью ByteBuddy в определенных ситуациях, я получаю IllegalAccessErrors. Почему? - PullRequest
1 голос
/ 10 марта 2020

(Я новый пользователь ByteBuddy. Я использую ByteBuddy версии 1.10.8 и JDK 11 без пути к модулю или какой-либо другой части системы модулей.)

У меня есть вложенный класс, объявленный как this:

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

(класс, содержащий его foo.bar.TestExplorations.)

Когда я создаю динамический подкласс c из Frob с именем foo.bar.Crap, как показано ниже, все работает ОК, как и следовало ожидать:

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(), даже если Crap и Frob находятся в одном пакете, а Frob() определен как private-package.

I Я чувствую, что в этом виновата система модулей JDK, хотя я сознательно (очень, очень сознательно) не использую ее. Я знаю, что модульная система не любит разделенные пакеты, что, как мне кажется, происходит здесь. Существует ли стратегия конструктора или другой механизм для решения этой проблемы?

1 Ответ

0 голосов
/ 10 марта 2020

В Java пакет равен другому пакету, только если он имеет то же имя и загружается тем же загрузчиком классов (так же, как и с классами). Если вы используете стратегию WRAPPER, вы не можете получить доступ к закрытым для пакета членам любого суперкласса. Byte Buddy не запрещает генерацию, как это было бы законно в javac, но вам нужно будет использовать стратегию INJECTION, чтобы сделать то, что вы хотите, чтобы убедиться, что классы загружаются одним и тем же загрузчиком классов. Имейте в виду, что он использует внутренний API, поэтому, начиная с Java 9, вы предпочитаете использовать стратегию загрузки классов ForLookup.

...