我目前正在开发一个自定义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的类加载器可以访问生成的代理使用的所有其他类。如果没有,您可能需要一个非常复杂的加载器委托结构才能使这两个类都可用。甚至可能是不可能的(这取决于您的代理实际应该做什么)。

09-16 06:12