我目前正在开发一个自定义ORM框架,并利用ASM在运行时动态生成子类。生成过程似乎已完成,但是当我尝试实例化结果类时,我收到了“ NoClassDefFoundError”。
该错误似乎与父类有关,而不是实际子类。这是子类生成方法的摘录:
private Class generateProxyClass(Class anEntitySuperClass,
List<Field> fieldsToIntercept) throws ClassNotFoundException{
String entitySuperClassName = this.convertToInternalName(anEntitySuperClass.getName());
//String entityProxySubClassName = "com/flux/dynamic/".concat(anEntitySuperClass.getSimpleName()).concat("Proxy");
String entityProxySubClassName = anEntitySuperClass.getSimpleName().concat("Proxy");
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(V1_6,ACC_PUBLIC+ACC_SUPER,entityProxySubClassName,null,entitySuperClassName,null);
cw.visitSource(entityProxySubClassName.concat(".java"),null);
//create constructor
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
mv.visitCode();
//have our consturctor initailise its super class.
mv.visitVarInsn(ALOAD,0);
mv.visitMethodInsn(INVOKESPECIAL,entitySuperClassName,"<init>","()V");
mv.visitInsn(RETURN);
mv.visitMaxs(0,0);
mv.visitEnd();
this.generateAndAppendProxyAccessorMethods(anEntitySuperClass,fieldsToIntercept, cw);
cw.visitEnd();
//at this point our class should be fully generated an include all required fields. next we
//convert the class to a byte array and pass it in to our helper method to load an
//actual class from the byte array.
return this.loadProxyClass(cw.toByteArray(),entityProxySubClassName);
}
上面调用的“ loadProxyClass”方法是基本上实例化的帮助器方法
并调用自定义ClassLoader来加载动态创建的类:
/**loads the generated proxy class from the provided bytes. */
private Class loadProxyClass(byte[] aGeneratedProxyClass,String proxyClassName) throws ClassNotFoundException{
return new ProxyClassLoader(Thread.currentThread().getContextClassLoader(),aGeneratedProxyClass)
.loadClass(this.convertToExternalName(proxyClassName));
}
ProxyClassLoader只是扩展了ClassLoader并覆盖了“ findClass”方法,以便加载动态生成的类字节:
public class ProxyClassLoader extends ClassLoader {
private byte[] rawClassBytes;
public ProxyClassLoader(ClassLoader parentClassLoader,byte[] classBytes){
super(parentClassLoader);
this.rawClassBytes = classBytes;
}
@Override
public Class findClass(String name) {
return defineClass(name,this.rawClassBytes, 0,this.rawClassBytes.length);
}
}
我得到的错误是:
Exception in thread "main" java.lang.NoClassDefFoundError: DummyEntity (wrong name: DummyEntityProxy)
其中
DummyEntity
是我传递给generateProxyClass
方法的超类,而DummyEntityProxy
是我尝试生成的类。我很沮丧,任何帮助将不胜感激。 最佳答案
通常,实现ClassLoader
尝试返回相同的类而不管要求的内容不是一个好主意。您得到的错误完全说明了这一点:NoClassDefFoundError: DummyEntity (wrong name: DummyEntityProxy)
。系统向您的ClassLoader
请求一个名为DummyEntity
的类,并且您返回了一个名为DummyEntityProxy
的类。
剩下的问题是,为什么像通常首先问到父加载器一样,要求您的加载器提供该类。看来父加载器没有找到超类,这表明您使用的父类加载器(Thread.currentThread().getContextClassLoader()
)无法访问您的超类。如果您将anEntitySuperClass.getClassLoader()
用作父加载器,那会更容易。
当然,您必须确保anEntitySuperClass
的类加载器可以访问生成的代理使用的所有其他类。如果没有,您可能需要一个非常复杂的加载器委托结构才能使这两个类都可用。甚至可能是不可能的(这取决于您的代理实际应该做什么)。