gpt4 book ai didi

java - ASM 动态子类创建 - NoClassDefFoundError BeanInfo

转载 作者:行者123 更新时间:2023-11-30 02:46:26 24 4
gpt4 key购买 nike

我正在尝试使用 ASM Framework 动态创建一个子类。我能够创建该类并实例化它。但是当我尝试这样做时

org.apache.commons.beanutils.BeanUtils.copyProperties(processedEntity, entity); 

它抛出这个异常:

java.lang.NoClassDefFoundError: com/wheelsup/app/benefits/service/XpOWErhNBiBeanInfo (wrong name: com/wheelsup/app/benefits/service/XpOWErhNBi)

这是我用来创建子类的代码:

Class<? extends T> get() throws Exception {
String superClassInternalName = getInternalName(superClass);

String subClassSimpleName = RandomStringUtils.random(10, true, false);
String subClassInternalName = getClass().getPackage().getName().replaceAll("\\.", "/").concat("/").concat(subClassSimpleName);
String subClassName = getClass().getPackage().getName().concat(".").concat(subClassSimpleName);

ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
classWriter.visit(Opcodes.V1_6,
ACC_PUBLIC,
subClassInternalName,
null,
superClassInternalName,
null);

visitDefaultConstructor(classWriter, superClassInternalName);

classWriter.visitEnd();

return SubClassLoader.<T>init().load(classWriter.toByteArray(), subClassName);
}

private void visitDefaultConstructor(ClassWriter classWriter, String superClassInternalName) {
MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, superClassInternalName, "<init>", "()V");
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(0, 0);
methodVisitor.visitEnd();
}

private static class SubClassLoader<T> {
private final ClassLoader contextClassLoader;

private SubClassLoader(ClassLoader contextClassLoader) {
this.contextClassLoader = contextClassLoader;
}

static <U> SubClassLoader<U> init() {
return new SubClassLoader<>(Thread.currentThread().getContextClassLoader());
}

@SuppressWarnings("unchecked")
Class<? extends T> load(byte[] classBytes, String className) throws Exception {
return (Class<? extends T>) new SubClassLoader.DynamicClassLoader(contextClassLoader, classBytes).loadClass(className);
}

private static class DynamicClassLoader extends ClassLoader {
private byte[] rawClassBytes;

private DynamicClassLoader(ClassLoader contextClassLoader, byte[] classBytes) {
super(contextClassLoader);
this.rawClassBytes = classBytes;
}

@Override
public Class findClass(String name) {
return defineClass(name, this.rawClassBytes, 0, this.rawClassBytes.length);
}
}
}

我不明白BeanInfo的事情;它是什么?以及如何解决我的问题?

谢谢。

最佳答案

问题是您的 findClass 实现尝试返回一个生成的类,无论调用者请求哪个类。在某些情况下,未能加载类是使操作正常运行的正确做法。

BeanUtils 类依赖 Introspector它允许为被检查的类提供可选的显式 beaninfo 实现,因此如果被要求提供 FooBeanInfo,它将尝试加载类 FooBeanInfo > 首先,如果失败,它将为 Foo 构造一个通用 bean 信息。

但是,由于您的 findClass 实现尝试以错误的名称 XpOWErhNBiBeanInfo (重新)构造 XpOWErhNBi 类,而不是报告缺少 XpOWERhNBiBeanInfo,出现问题。

您必须更改您的SubClassLoader才能接收生成的类的预期名称。然后,您可以将 findClass 实现更改为

@Override
public Class findClass(String name) throws ClassNotFoundException {
if(!name.equals(expectedName))
throw new ClassNotFoundException(name);
return defineClass(name, this.rawClassBytes, 0, this.rawClassBytes.length);
}

一个更简单但hacky的解决方案是在第一个类构造之后将rawClassBytes清空,并为每个后续类抛出一个ClassNotFoundException类加载请求作为继承的标准 loadClass 实现保证仅对尚未加载的类调用 findClass,因此只要您的程序立即加载生成的类的逻辑不变,所有后续请求都涉及不同的、不受支持的类。

但是,由于关键点是程序逻辑不能改变,所以我不推荐这种hacky、脆弱的解决方案。将生成的类的名称传递给自定义加载器并验证它,一开始代码会多一些,但更简洁。

关于java - ASM 动态子类创建 - NoClassDefFoundError BeanInfo,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40076623/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com