reflections:Java runtime metadata analysis

关于 reflections 及其版本

Reflections 通过扫描 classpath ,索引元数据,并且允许在运行时查询这些元数据。

使用 Reflections 可以很轻松的获取以下元数据信息:

  • 获取某个类型的全部子类;
  • 只要类型、构造器、方法,字段上带有特定注解,便能获取带有这个注解的全部信息( 类型、构造器、方法,字段 )
  • 获取所有能匹配某个正则表达式的资源;
  • 获取所有带有特定签名的方法,包括参数,参数注解,返回类型;
  • 获取所有方法的名字;
  • 获取代码里所有字段、方法名、构造器的使用。

官方 github

当前,reflections 有 3 个"特色鲜明"的版本:

  • 0.9.11 是最后一个依赖 guava 的版本;
  • 0.9.12 从这个版本开始移除了 guava 依赖;
  • 0.10.2 相较于 0.9.x 版本,0.10 版本采用了新的函数式的编程风格。学习曲线变陡峭了,对初级程序员来说不太友好。

综合考虑,对于初学者而言,推荐使用 0.9.12 版本。



    org.reflections
    reflections
    0.9.12

// 实例化Reflections,并指定要扫描的包名
Reflections reflections = new Reflections("my.project");
// 获取某个类的所有子类
Set> subTypes = reflections.getSubTypesOf(SomeType.class);
// 获取包含某个注解的所有类
Set> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);

基本使用

// scan urls that contain 'my.package', include inputs starting with 'my.package', use the default scanners
Reflections reflections = new Reflections("my.package");

//or using ConfigurationBuilder
new Reflections(new ConfigurationBuilder()
     .setUrls(ClasspathHelper.forPackage("my.project.prefix"))
     .setScanners(new SubTypesScanner(), 
                  new TypeAnnotationsScanner().filterResultsBy(optionalFilter), ...),
     .filterInputsBy(new FilterBuilder().includePackage("my.project.prefix"))
     ...);

扫描子类

Set> modules = 
    reflections.getSubTypesOf(com.google.inject.Module.class);

扫描注解

//TypeAnnotationsScanner 
Set> singletons = 
    reflections.getTypesAnnotatedWith(javax.inject.Singleton.class);

扫描资源

//ResourcesScanner
Set properties = 
    reflections.getResources(Pattern.compile(".*\\.properties"));

扫描方法注解

// MethodAnnotationsScanner
Set resources =
    reflections.getMethodsAnnotatedWith(javax.ws.rs.Path.class);
Set injectables = 
    reflections.getConstructorsAnnotatedWith(javax.inject.Inject.class);

扫描字段注解

// FieldAnnotationsScanner
Set ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

扫描字段注解

// FieldAnnotationsScanner
Set ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

扫描方法参数

// MethodParameterScanner
Set someMethods = reflections.getMethodsMatchParams(long.class, int.class);
Set voidMethods = reflections.getMethodsReturn(void.class);
Set pathParamMethods = reflections.getMethodsWithAnyParamAnnotated(PathParam.class);

扫描方法参数名

// MethodParameterNamesScanner
List parameterNames = reflections.getMethodParamNames(Method.class)

扫描方法调用情况

// MemberUsageScanner
Set usages = reflections.getMethodUsages(Method.class)

public class Store extends HashMap>> ;
import static org.reflections.ReflectionUtils.*;


// 查找 C3 的祖先,看谁的"脑袋"上有 AI1 注解。
getAllSuperTypes(TestModel.C3.class, withAnnotation(TestModel.AI1.class);

// 查找 C4 的方法,要求要是 public 的,且返回值为 void 。
getAllMethods(TestModel.C4.class, withModifier(Modifier.PUBLIC), withReturnType(void.class));
// 同上
getAllMethods(TestModel.C4.class, withPattern("public.*.void .*"));
            
// 查找 C4 的方法,要求方法中至少有个参数用到了 AM1 注解。
getAllMethods(TestModel.C4.class, withAnyParameterAnnotation(TestModel.AM1.class))
            
// 查找 C4 的域,要求被标注了 AF1 注解。 
getAllFields(TestModel.C4.class, withAnnotation(TestModel.AF1.class))
            
// 查找 C4 的域,要求被标准娱乐 AF1 注解,且注解的 value 属性值为 "2"
getAllFields(TestModel.C4.class, withAnnotation(new TestModel.AF1() {
        public String value() {return "2";}
        public Class annotationType() {return TestModel.AF1.class;}}))
               
// 查找 C4 的域,要求能够被 String 类型赋值的。
getAllFields(TestModel.C4.class, withTypeAssignableTo(String.class))

// 查找 C4 的构造器,无参的那个
getAllConstructors(TestModel.C4.class, withParametersCount(0))

// 查找 C3 脑袋上的注解,包括从祖先那里继承来的。
getAllAnnotations(TestModel.C3.class).size()

// 查找 C4 中叫 m4 的方法。
getMethods(TestModel.C4.class, withName("m4")).iterator().next();

/****************
* withParameter *
****************/
                 



assertTrue(getAnnotations(m4).isEmpty());

    @Test public void () throws Exception {
        Class target = Collections.class;
        Object arg1 = Arrays.asList(1, 2, 3);

        Set allMethods = new HashSet<>();
        for (Class type : getAllSuperTypes(arg1.getClass())) {
            allMethods.addAll(getAllMethods(target, withModifier(Modifier.STATIC), withParameters(type)));
        }

        Set allMethods1 = getAllMethods(target, withModifier(Modifier.STATIC), withParametersAssignableTo(arg1.getClass()));

        assertEquals(allMethods, allMethods1);

        for (Method method : allMethods) { //effectively invokable
            //noinspection UnusedDeclaration
            Object invoke = method.invoke(null, arg1);
        }
    }

    @Test
    public void withParametersAssignableFromTest() throws Exception {
        //Check for null safe
        getAllMethods(Collections.class, withModifier(Modifier.STATIC), withParametersAssignableFrom());

        Class target = Collections.class;
        Object arg1 = Arrays.asList(1, 2, 3);

        Set allMethods = new HashSet<>();
        for (Class type : getAllSuperTypes(arg1.getClass())) {
            allMethods.addAll(getAllMethods(target, withModifier(Modifier.STATIC), withParameters(type)));
        }

        Set allMethods1 = getAllMethods(target, withModifier(Modifier.STATIC), withParametersAssignableFrom(Iterable.class), withParametersAssignableTo(arg1.getClass()));

        assertEquals(allMethods, allMethods1);

        for (Method method : allMethods) { //effectively invokable
            //noinspection UnusedDeclaration
            Object invoke = method.invoke(null, arg1);
        }
    }

    @Test public void withReturn() {
        Set returnMember = getAllMethods(Class.class, withReturnTypeAssignableTo(Member.class));
        Set returnsAssignableToMember = getAllMethods(Class.class, withReturnType(Method.class));

        assertTrue(returnMember.containsAll(returnsAssignableToMember));
        assertFalse(returnsAssignableToMember.containsAll(returnMember));

        returnsAssignableToMember = getAllMethods(Class.class, withReturnType(Field.class));
        assertTrue(returnMember.containsAll(returnsAssignableToMember));
        assertFalse(returnsAssignableToMember.containsAll(returnMember));
    }

    @Test
    public void getAllAndReflections() {
        Reflections reflections = new Reflections(TestModel.class, new FieldAnnotationsScanner());

        Set af1 = reflections.getFieldsAnnotatedWith(TestModel.AF1.class);
        Set allFields = ReflectionUtils.getAll(af1, withModifier(Modifier.PROTECTED));
        assertEquals(1, allFields.size());
        assertThat(allFields, names("f2"));
    }

}

你可能感兴趣的:(reflections:Java runtime metadata analysis)