代码之家  ›  专栏  ›  技术社区  ›  Ralph

按批注查找匿名类

  •  2
  • Ralph  · 技术社区  · 5 年前

    有没有一种方法可以通过使用java反射库(如( Reflections )?

    我有以下代码: 它使用声明内部类(扩展对象)并用 @DemoAnnotation

    public class DemoUsageService {
    
        public void doSomething() {
            this.test(new @DemoAnnotation(value="Test") Object() {
                String content = "myContent";
            });
        }
    }
    
    @Retention(RUNTIME)
    @Target({ElementType.TYPE_USE})
    public @interface DemoAnnotation {
       String value();
    }
    

    现在,我想在我的项目中找到所有(匿名)类,这些类都用 @演示注释 .


    我试过了 反思 库:但它不能找到匿名类(找到内部静态类)。

        @Test
        public void testFindAnnotatedClasses() throws Exception {
            
            Reflections reflections = new Reflections(
                    new ConfigurationBuilder()
                            .setUrls(ClasspathHelper.forPackage(DemoUsageService.class.getPackageName()))
                            .setScanners(
                                    new SubTypesScanner(false),
                                    new TypeAnnotationsScanner()));
            
            Set<Class<?>> result = reflections.getTypesAnnotatedWith(DemoAnnotation.class);
            assertEquals(1, result.size()); //fails, because result.size == 0
            //...
        }
    
    <dependency>
        <groupId>org.reflections</groupId>
        <artifactId>reflections</artifactId>
        <version>0.9.12</version>
    </dependency>
    

    @chrylis-cautiouslyoptimistic:的javap反编译器输出 DemoUsageService$1 看起来像是其中的批注。

    Classfile /C:/Users/engelmann/git/experiment-anonymousclass-annotationscanning/target/classes/DemoUsageService$1.class
      Last modified 21.09.2020; size 1016 bytes
      MD5 checksum 2dcb03fe361641b6e04fbb62bbb6c971
      Compiled from "DemoUsageService.java"
    class DemoUsageService$1
      minor version: 0
      major version: 55
      flags: (0x0020) ACC_SUPER
      this_class: #5                          // DemoUsageService$1
      super_class: #6                         // java/lang/Object
      interfaces: 0, fields: 2, methods: 1, attributes: 5
    Constant pool:
       #1 = Fieldref           #5.#30         // DemoUsageService$1.this$0:LDemoUsageService;
       #2 = Methodref          #6.#31         // java/lang/Object."<init>":()V
       #3 = String             #32            // myContent
       #4 = Fieldref           #6.#33         // java/lang/Object.content:Ljava/lang/String;
       #5 = Class              #34            // DemoUsageService$1
       #6 = Class              #35            // java/lang/Object
       #7 = Utf8               content
       #8 = Utf8               Ljava/lang/String;
       #9 = Utf8               this$0
      #10 = Utf8               LDemoUsageService;
      #11 = Utf8               <init>
      #12 = Utf8               (LDemoUsageService;)V
      #13 = Utf8               Code
      #14 = Utf8               LineNumberTable
      #15 = Utf8               LocalVariableTable
      #16 = Utf8               this
      #17 = Utf8               InnerClasses
      #18 = Utf8               LDemoUsageService$1;
      #19 = Utf8               MethodParameters
      #20 = Utf8               SourceFile
      #21 = Utf8               DemoUsageService.java
      #22 = Utf8               RuntimeVisibleTypeAnnotations
      #23 = Utf8               LDemoAnnotation;
      #24 = Utf8               value
      #25 = Utf8               Test
      #26 = Utf8               EnclosingMethod
      #27 = Class              #36            // DemoUsageService
      #28 = NameAndType        #37:#38        // doSomething:()V
      #29 = Utf8               NestHost
      #30 = NameAndType        #9:#10         // this$0:LDemoUsageService;
      #31 = NameAndType        #11:#38        // "<init>":()V
      #32 = Utf8               myContent
      #33 = NameAndType        #7:#8          // content:Ljava/lang/String;
      #34 = Utf8               DemoUsageService$1
      #35 = Utf8               java/lang/Object
      #36 = Utf8               DemoUsageService
      #37 = Utf8               doSomething
      #38 = Utf8               ()V
    {
      java.lang.String content;
        descriptor: Ljava/lang/String;
        flags: (0x0000)
    
      final DemoUsageService this$0;
        descriptor: LDemoUsageService;
        flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
    
      DemoUsageService$1(DemoUsageService);
        descriptor: (LDemoUsageService;)V
        flags: (0x0000)
        Code:
          stack=2, locals=2, args_size=2
             0: aload_0
             1: aload_1
             2: putfield      #1                  // Field this$0:LDemoUsageService;
             5: aload_0
             6: invokespecial #2                  // Method java/lang/Object."<init>":()V
             9: aload_0
            10: ldc           #3                  // String myContent
            12: putfield      #4                  // Field java/lang/Object.content:Ljava/lang/String;
            15: return
          LineNumberTable:
            line 7: 0
            line 8: 9
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      16     0  this   LDemoUsageService$1;
                0      16     1 this$0   LDemoUsageService;
        MethodParameters:
          Name                           Flags
          this$0                         final mandated
    }
    SourceFile: "DemoUsageService.java"
    RuntimeVisibleTypeAnnotations:
      0: #23(#24=s#25): CLASS_EXTENDS, type_index=65535
        DemoAnnotation(
          value="Test"
        )
    EnclosingMethod: #27.#28                // DemoUsageService.doSomething
    NestHost: class DemoUsageService
    InnerClasses:
      #5;                                     // class DemoUsageService$1
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Eugene    5 年前

    我以前从未使用过这个库,但在源代码中到处戳了戳,似乎我可以让它工作(它是以一种很好的方式编写的,所以我很幸运)。我不知道是否有更好的方法,但你可以这样做:

    static class TestScanner extends AbstractScanner {
    
        @Override
        public void scan(Object cls, Store store) {
    
            String className = getMetadataAdapter().getClassName(cls);
    
            try {
                Class<?> c = Class.forName(className);
                if (c.isAnonymousClass()) {
                    for (Annotation ann : c.getAnnotatedSuperclass().getAnnotations()) {
                        store.put(Utils.index(TypeAnnotationsScanner.class), ann.annotationType().getName(), className);
                    }
    
                }
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
    
        }
    
    }
    

    用法如下:

        Reflections reflections = new Reflections(
            new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(DemoUsageService.class.getPackageName()))
                                      .setScanners(new TestScanner(), new SubTypesScanner(false), new TypeAnnotationsScanner()));
    
        Set<Class<?>> result = reflections.getTypesAnnotatedWith(DemoAnnotation.class);
        result.forEach(x -> System.out.println(x.getName()));