【问题标题】:URLClassLoader loads Annotation as com.sun.$Proxy$27URLClassLoader 将 Annotation 加载为 com.sun.$Proxy$27
【发布时间】:2013-08-19 09:25:27
【问题描述】:

我正在尝试动态加载一个 java 类。基本思想是,一个 jar 包含在运行时动态加载的模块。我就是这样做的(我知道这很 hacky,但是没有其他方法可以将 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 环境中尝试这个。

【问题讨论】:

    标签: java spring annotations classloader urlclassloader


    【解决方案1】:

    在尝试基于使用注释的声明性方法创建用于代码生成的 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());
            }
    

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

    【讨论】:

      【解决方案2】:

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

      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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 2017-10-09
          • 1970-01-01
          • 1970-01-01
          • 2015-12-22
          • 2011-06-07
          • 1970-01-01
          • 1970-01-01
          • 2019-02-08
          • 1970-01-01
          相关资源
          最近更新 更多