URLClassLoader将Annotation加载为com.sun。$ Proxy $ 27

我正在尝试动态加载java类。 基本思想是,jar包含在运行时动态加载的模块。 我就是这样做的(我知道它很hacky,但没有其他方法可以动态地将jar添加到已经存在的类加载器中):

Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class }); method.setAccessible(true); method.invoke(moduleLoader, new Object[] { file.toURI().toURL() }); Class fooClass = moduleLoader.loadClass("com.coderunner.Foo"); Object foo = fooClass.newInstance(); 

每个模块都使用@Module注释进行注释。 因此,为了获得有关模块的更多信息,我尝试获取注释。 问题是foo上的注释是com.sun。$ Proxy $ 27而不是com.coderunner.Module,因此我得到了一个

 ClassCastException: Cannot cast com.sun.proxy.$Proxy42 (id=64) to com.coderunner.Module 

我不得不说我有点困惑这里发生的事情。 我想做什么? 怎么样?

编辑:我也许应该提一下我在spring / spring-mvc和tomcat环境中尝试这个。

reflection返回代理对象的事实不会阻止您收集有关注释及其值的信息。

getclass方法返回一个代理对象:

  log.info("annotation class:" + annotation.getClass()); 

输出:

  [INFO] annotation class:class com.sun.proxy.$Proxy16class 

输出与示例中的输出相同,但这没有问题。 拥有方法(或字段)就足够了。 另外一部分是调用注释方法

 public void analyseClass(Class myClass) { for (Method method: myClass.getMethods()) { System.out.println("aanotations :" + Arrays.toString(field.getAnnotations())); for (Annotation annotation : method.getAnnotations()) { log.info("annotation class:" + annotation.getClass()); log.info("annotation class type:" + annotation.annotationType()); Class type = (Class) annotation.annotationType(); /* extract info only for a certain annotation */ if(type.getName().equals(MyAnnotation.class.getName())) { String annotationValue = (String) type.getMethod("MY_ANNOTATION_CERTAIN_METHOD_NAME").invoke(annotation); log.info("annotationValue :" + annotationValue); break; } } } //do the same for the fields of the class for (Field field : myClass.getFields()) { //... } } 

为了得到这个解决方案,我使用了以下post: 如何使用reflection获取注释类名,属性值

您在注释类型前面获得代理的事实应该无关紧要。 它实际上可能误导你相信这是你遇到问题的原因。 如果像“isAnnotationPresent(..)”这样的东西失败,那不是因为那个代理,这是因为你使用多个类加载器多次加载了注释类。 例如,Jetty默认优先使用WebApp类加载器。 因此,如果您的Jetty服务器实例(或Tomcat或其他)已经加载了注释类,并且注释也在WebApp的类路径上,那么您可能会遇到像“getAnnotation()”这样的问题,而不会返回任何内容。 只需确保包含注释的库未加载两次。

Andreas提供的解决方案是一个非常脏的解决方法,只是掩盖了这样一个事实,即您可能没有控制/正确组织的类加载。

在尝试基于使用注释的声明性方法创建用于代码生成的ant任务时,我遇到了同样的问题。 我发现代理 – 对象的文档说明instanceof应该解决它,但这不起作用。 我终于找到了

Annotation[] annotations = classObj.getAnnotations();

  for(int i = 0;i < annotations.length;i++) { Class[] interfaces = annotations[i].getClass().getInterfaces(); for(int i2 = 0; i2 < interfaces.length;i2++) { System.out.println("interface:" + interfaces[i2].getName()); } 

给出我原始注释的名称,因此将此名称与注释类名进行比较将为您提供所需的结果。