bytebuddy rebase 与 OSGi 中的子类和错误 name/NoClassDefFoundError
bytebuddy rebase versus subclass and wrong name/NoClassDefFoundError in OSGi
我正在尝试开发一个包装实际调用方法的建议。这就是我声明拦截器的方式:
public class SecurityInterceptor() {
@RuntimeType
public Object intercept(
@SuperCall Callable<Object> supercall,
@This Object target,
@Origin Method method,
@AllArguments Object[] args) {
// Check args and annotations ...
Object obj = supercall.call();
// use Spring SPEL to post-process obj content ...
}
}
拦截器注册如下:
byte[] woven = new ByteBuddy().subclass(type)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(new SecurityInterceptor()))
.make().getBytes();
编织字节数组通过 WeavingHook/WovenClass OSGi 机制进行管理。
一旦加载编织的class,我就会得到以下异常:
java.lang.NoClassDefFoundError: com/contoso/users/service/provider/UsersServiceImpl (wrong name: com/contoso/users/service/provider/UsersServiceImpl$ByteBuddy$q3pXZ5KY)
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:?]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2410) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2194) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1607) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl.access0(BundleWiringImpl.java:80) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2053) ~[?:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:?]
at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1927) ~[?:?]
at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:978) ~[?:?]
如果我使用 rebase
方法而不是 subclass
方法并删除 @SuperCall Callable<Object> supercall
参数,则会调用拦截器。
只有当我在 OSGi 中应用拦截器时才会出现此错误:相同的过程在 vanilla java junit 测试中运行良好,我按如下方式修改 classes:
<T> T loadTestClass(Class<T> clazz) throws Exception {
return new ByteBuddy()
.subclass(clazz)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(securityInterceptor))
.make()
.load(getClass().getClassLoader())
.getLoaded()
.newInstance();
}
关于如何处理此 NoClassDefFoundError
/ 错误名称 错误的任何想法?
OSGi class 加载器实现通常使用 ClassLoader.defineClass
方法,该方法将预期的 class 名称作为参数:例如https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/ClassLoader.html#defineClass(java.lang.String,byte%5B%5D,int,int)。当提供预期的 class 名称时,class 加载程序要求定义的 class 的名称与预期的 class 名称相匹配。这是一个很好的完整性检查。
因此,如果 class 加载程序正在定义 class Foo,则您不能为 class 提供具有不同名称的字节数组,例如 subclass .
我正在尝试开发一个包装实际调用方法的建议。这就是我声明拦截器的方式:
public class SecurityInterceptor() {
@RuntimeType
public Object intercept(
@SuperCall Callable<Object> supercall,
@This Object target,
@Origin Method method,
@AllArguments Object[] args) {
// Check args and annotations ...
Object obj = supercall.call();
// use Spring SPEL to post-process obj content ...
}
}
拦截器注册如下:
byte[] woven = new ByteBuddy().subclass(type)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(new SecurityInterceptor()))
.make().getBytes();
编织字节数组通过 WeavingHook/WovenClass OSGi 机制进行管理。
一旦加载编织的class,我就会得到以下异常:
java.lang.NoClassDefFoundError: com/contoso/users/service/provider/UsersServiceImpl (wrong name: com/contoso/users/service/provider/UsersServiceImpl$ByteBuddy$q3pXZ5KY)
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:?]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2410) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2194) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1607) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl.access0(BundleWiringImpl.java:80) ~[?:?]
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2053) ~[?:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:?]
at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1927) ~[?:?]
at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:978) ~[?:?]
如果我使用 rebase
方法而不是 subclass
方法并删除 @SuperCall Callable<Object> supercall
参数,则会调用拦截器。
只有当我在 OSGi 中应用拦截器时才会出现此错误:相同的过程在 vanilla java junit 测试中运行良好,我按如下方式修改 classes:
<T> T loadTestClass(Class<T> clazz) throws Exception {
return new ByteBuddy()
.subclass(clazz)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(securityInterceptor))
.make()
.load(getClass().getClassLoader())
.getLoaded()
.newInstance();
}
关于如何处理此 NoClassDefFoundError
/ 错误名称 错误的任何想法?
OSGi class 加载器实现通常使用 ClassLoader.defineClass
方法,该方法将预期的 class 名称作为参数:例如https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/ClassLoader.html#defineClass(java.lang.String,byte%5B%5D,int,int)。当提供预期的 class 名称时,class 加载程序要求定义的 class 的名称与预期的 class 名称相匹配。这是一个很好的完整性检查。
因此,如果 class 加载程序正在定义 class Foo,则您不能为 class 提供具有不同名称的字节数组,例如 subclass .