当我在某些情况下使用 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.Crap
的 Frob
的动态子 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()
,即使 Crap
和 Frob
在同一个包中,并且 Frob()
被定义为包私有。
我觉得 JDK 模块系统是罪魁祸首,即使我故意(非常非常故意)不使用它。我知道模块系统不喜欢拆分包,这在我看来就是在这里进行的。是否有构造函数策略或其他机制来解决此问题?
在Java中,如果一个包具有相同的名称并且由相同的class加载程序加载(与class相同),则该包仅等于另一个包es)。如果您使用 WRAPPER
策略,则无法访问任何超级 class 的包私有成员。 Byte Buddy 不禁止生成,因为在 javac 中这样做是合法的,但您需要使用 INJECTION
策略来执行您想要的操作,以确保 classes 由相同的 class装载机。请注意,它使用内部 API,因此,从 Java 9 开始,您宁愿使用 ForLookup
class 加载策略。
(我是 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.Crap
的 Frob
的动态子 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()
,即使 Crap
和 Frob
在同一个包中,并且 Frob()
被定义为包私有。
我觉得 JDK 模块系统是罪魁祸首,即使我故意(非常非常故意)不使用它。我知道模块系统不喜欢拆分包,这在我看来就是在这里进行的。是否有构造函数策略或其他机制来解决此问题?
在Java中,如果一个包具有相同的名称并且由相同的class加载程序加载(与class相同),则该包仅等于另一个包es)。如果您使用 WRAPPER
策略,则无法访问任何超级 class 的包私有成员。 Byte Buddy 不禁止生成,因为在 javac 中这样做是合法的,但您需要使用 INJECTION
策略来执行您想要的操作,以确保 classes 由相同的 class装载机。请注意,它使用内部 API,因此,从 Java 9 开始,您宁愿使用 ForLookup
class 加载策略。