4

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

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 环境中尝试这个。

4

3 回答 3

1

反射返回代理对象这一事实并不妨碍您收集有关注解及其值的信息。

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<Annotation> type = (Class<Annotation>) 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()) {
         //...
    }

}  

为了得到这个解决方案,我使用了以下帖子: How to get annotation class name, attribute values using reflection

于 2015-02-05T07:43:17.330 回答
1

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

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

于 2017-06-08T23:54:34.153 回答
0

在尝试基于使用注释的声明性方法创建用于代码生成的 ant 任务时,我遇到了同样的问题。我发现 Proxy - Object 的文档指出 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());
        }

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

于 2013-12-22T14:44:07.217 回答