【问题标题】:Adding an annotation to a runtime generated class using Javassist使用 Javassist 向运行时生成的类添加注释
【发布时间】:2014-04-28 08:32:03
【问题描述】:

我正在使用 Javassist(Java 1.7) 向 ClassA 类添加注释,但出现异常。我究竟做错了什么?我试过的代码是这样的:

ClassA.java

public class ClassA
{

}

添加方法

public static <T> Class<T> addXmlRootAnnotationDynamicly(Class<T> declaredTyp) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException
{
    //pool creation 
    ClassPool pool = ClassPool.getDefault();
    //extracting the class
    CtClass cc = pool.getCtClass(declaredTyp.getCanonicalName());

    // create the annotation
    ClassFile ccFile = cc.getClassFile();
    ConstPool constpool = ccFile.getConstPool();
    AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
    Annotation annot = new Annotation("javax.xml.bind.annotation.XmlRootElement", constpool);
    attr.addAnnotation(annot);

    // add the annotation to the class
    cc.getClassFile().addAttribute(attr);

    // transform the ctClass to java class
    Class<T> dynamiqueBeanClass = cc.toClass();

    //instanciating the updated class 
    //      T sayHelloBean = dynamiqueBeanClass.newInstance();

    return dynamiqueBeanClass;

}

打电话

Class<ClassA> addXmlRootAnnotationDynamicly = addXmlRootAnnotationDynamicly(ClassA.class);

例外

javassist.CannotCompileException:由 java.lang.LinkageError:加载程序(sun/misc/Launcher$AppClassLoader 的实例):尝试重复名称的类定义:“de/it_p/pvlight/share/util/ClassA” 在 javassist.ClassPool.toClass(ClassPool.java:1099) 在 javassist.ClassPool.toClass(ClassPool.java:1042) 在 javassist.ClassPool.toClass(ClassPool.java:1000) 在 javassist.CtClass.toClass(CtClass.java:1224) 在 de.it_p.pvlight.share.util.JAXBUtil.addXmlRootAnnotationDynamicly(JAXBUtil.java:107) 在 de.it_p.pvlight.share.util.JAXBUtilTest.addXmlRootAnnotationDynamicly(JAXBUtilTest.java:60) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 引起:java.lang.LinkageError:加载程序(sun/misc/Launcher$AppClassLoader 的实例):尝试重复名称的类定义:“de/it_p/pvlight/share/util/ClassA” 在 java.lang.ClassLoader.defineClass1(本机方法) 在 java.lang.ClassLoader.defineClass(ClassLoader.java:800) 在 java.lang.ClassLoader.defineClass(ClassLoader.java:643) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 javassist.ClassPool.toClass2(ClassPool.java:1112) 在 javassist.ClassPool.toClass(ClassPool.java:1093) ... 15 更多

【问题讨论】:

    标签: java annotations javassist


    【解决方案1】:

    可以在堆栈跟踪中找到问题的根源:

    尝试对名称进行重复的类定义:“de/it_p/pvlight/share/util/ClassA”

    您的addXmlRootAnnotationDynamicly 方法采用已加载 类并重新定义该类,而无需更改其名称。重新定义后,您尝试再次加载更改后的类。然而,这在 Java 中是不可能的,因为任何ClassLoader 都可以only load a class of a given name one single time

    出于这个原因,pool.getCtClass 方法采用String 而不是加载的Class,并与用于描述卸载 Classes 的CtClasses 一起使用。为了克服您的问题,您有不同的选择:

    • 将方法的签名更改为addXmlRootAnnotationDynamicly(String),并将de.it_p.pvlight.share.util.ClassA 作为参数传递。确保在转换它之前,在代码中的任何地方都没有加载这个类。因此,您应该在应用程序启动时运行转换,以确保在转换之前不会意外加载该类。然后将您更改的Class 加载到cc.toClass()
    • 创建使用随机名称的参数类(或使用接口)的子类。然后,子类的类型与您的参数类兼容,但永远不会加载。
    • 使用Instrumentation API 在运行时重新定义加载的类。
    • 确保输入类和输出类加载了不同的ClassLoaders。 (不推荐)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      • 2012-07-31
      • 2011-12-21
      • 1970-01-01
      相关资源
      最近更新 更多