关于 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 extends Annotation> 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 extends Field> allFields = ReflectionUtils.getAll(af1, withModifier(Modifier.PROTECTED));
assertEquals(1, allFields.size());
assertThat(allFields, names("f2"));
}
}