如何在给定的包中find注释的方法?
我对方法有一个简单的标记注释(类似于Effective Java (第二版)第35项中的第一个例子):
/** * Marker annotation for methods that are called from installer's * validation scripts etc. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface InstallerMethod { }
然后,在一个给定的包(比如说com.acme.installer
)里面有几个包含大约20个类的子包,我想find所有注解的方法。 (因为我想对unit testing中的所有注释方法进行一些检查。)
什么(如果有的话)是最简单的方法呢? 最好不添加新的第三方库或框架。
编辑 :澄清,显然method.isAnnotationPresent(InstallerMethod.class)
将是方法来检查一个方法是否有注释 – 但这个问题包括find所有的方法。
如果你想自己实现它,这些方法将find给定包中的所有类:
/** * Scans all classes accessible from the context class loader which belong * to the given package and subpackages. * * @param packageName * The base package * @return The classes * @throws ClassNotFoundException * @throws IOException */ private Iterable<Class> getClasses(String packageName) throws ClassNotFoundException, IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); String path = packageName.replace('.', '/'); Enumeration<URL> resources = classLoader.getResources(path); List<File> dirs = new ArrayList<File>(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); URI uri = new URI(resource.toString()); dirs.add(new File(uri.getPath())); } List<Class> classes = new ArrayList<Class>(); for (File directory : dirs) { classes.addAll(findClasses(directory, packageName)); } return classes; } /** * Recursive method used to find all classes in a given directory and * subdirs. * * @param directory * The base directory * @param packageName * The package name for classes found inside the base directory * @return The classes * @throws ClassNotFoundException */ private List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException { List<Class> classes = new ArrayList<Class>(); if (!directory.exists()) { return classes; } File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) { classes.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); } } return classes; }
然后你可以用给定的注解过滤这些类:
for (Method method : testClass.getMethods()) { if (method.isAnnotationPresent(InstallerMethod.class)) { // do something } }
你应该看看开源的reflection库 。 有了它,你可以很容易地实现你想要的几行代码:
Reflections reflections = new Reflections( new ConfigurationBuilder().setUrls( ClasspathHelper.forPackage( "com.acme.installer" ) ).setScanners( new MethodAnnotationsScanner() ) ); Set<Method> methods = reflections.getMethodsAnnotatedWith(InstallerMethod.class);
如果你很乐意使用Spring,那么就使用它的上下文来做一些事情:组件扫描function,其中Spring扫描给定包中的注释类。 在封面之下,这是非常可怕的,并涉及在文件系统和JAR文件寻找包中的类的grubbing。
即使你不能直接使用Spring,仔细查看它的源代码也许会给你一些想法。
当然,JavareflectionAPi在这里没有用,它没有提供获取包中所有类的方法。