Java:循环类路径中的所有类

有没有办法迭代类路径中的所有类?

我想对实现某个接口的一些类进行一些反思性检查,但是我想完全动态地完成它,而不需要检查哪些类,只需浏览类路径。

Reflections库有助于解决这个问题。 正如其他人所说,在所有类加载情况下都不是完全可能的,但如果你拥有的只是jar子和文件,那么这将是可靠的。

你不能优雅地做到这一点。

基本上可以要求类加载器加载特定的类名,但不能要求它加载所有类。 (对于在Web上加载类的情况,这样做可能不可行 – 您无法可靠地要求Web服务器告诉您特定目录下的所有文件。)

如果你的类路径处理文件系统,你可能会痛苦地找到扩展目录中的所有jar文件,递归正常的类路径目录,并查看所有明确指定的jar文件 – 但它会很棘手,也可能很脆弱。

我已经为单个类加载器解决了这个问题。 我需要reflection来编写代码来检查JUnit测试并报告被忽略的测试。

/** * Attempts to list all the classes in the specified package as determined * by the context class loader * * @param pckgname * the package name to search * @return a list of classes that exist within that package * @throws ClassNotFoundException * if something went wrong */ private static List getClassesForPackage(String pckgname) throws ClassNotFoundException { // This will hold a list of directories matching the pckgname. There may be more than one if a package is split over multiple jars/paths ArrayList directories = new ArrayList(); try { ClassLoader cld = Thread.currentThread().getContextClassLoader(); if (cld == null) { throw new ClassNotFoundException("Can't get class loader."); } String path = pckgname.replace('.', '/'); // Ask for all resources for the path Enumeration resources = cld.getResources(path); while (resources.hasMoreElements()) { directories.add(new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8"))); } } catch (NullPointerException x) { throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Null pointer exception)"); } catch (UnsupportedEncodingException encex) { throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Unsupported encoding)"); } catch (IOException ioex) { throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + pckgname); } ArrayList classes = new ArrayList(); // For every directory identified capture all the .class files for (File directory : directories) { if (directory.exists()) { // Get the list of the files contained in the package String[] files = directory.list(); for (String file : files) { // we are only interested in .class files if (file.endsWith(".class")) { // removes the .class extension try { classes.add(Class.forName(pckgname + '.' + file.substring(0, file.length() - 6))); } catch (NoClassDefFoundError e) { // do nothing. this class hasn't been found by the loader, and we don't care. } } } } else { throw new ClassNotFoundException(pckgname + " (" + directory.getPath() + ") does not appear to be a valid package"); } } return classes; } 

我的解决方案基于此线程中的代码 :

我想你必须手动检查它:

 String classpath = System.getProperty("java.class.path"); String[] locations = classpath.split(System.getProperty("path.separator")); // inspect all jar's and class files in these locations, which is a pain in the b%tt 

或者使用一些第三方库(我不知道)。

我不知道有这样做的库,但有些开源项目是出于自己的目的而这样做的。 例如, Spring可以迭代类路径中的类来查找具有特定注释的类。 你可以看看他们是如何做到的,以获得一些想法。 我将从org.springframework.context.annotation包中的类开始,例如ClassPathScanningCandidateComponentProviderCommonAnnotationBeanPostProcessor

如果在项目中使用spring-context:这是一个使用所需注释枚举所有类型的工作示例:

 /** * Lists all types in the given package (recursive) which are annotated by the given annotation. * 

* All types which match the criteria are returned, no further checks (interface, abstract, embedded, etc. * are performed. *

* * @param aAnnotation * the desired annotation type * @param aRoot * the package name where to start the search. * @return a list of found types */ private Collection> findCandidatesByAnnotation( Class aAnnotation, String aRoot ) { List> result = new ArrayList>(); ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider( false ) { @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return true; } }; scanner.addIncludeFilter( new AnnotationTypeFilter( aAnnotation ) ); Set canditates = scanner.findCandidateComponents( aRoot ); for ( BeanDefinition beanDefinition : canditates ) { try { String classname = beanDefinition.getBeanClassName(); Class clazz = Class.forName( classname ); result.add( clazz ); } catch ( ClassNotFoundException t ) { myLog.error( "Springs type scanner returns a class name whose class cannot be evaluated!!!", t ); } } return result; }

此代码在java 8下针对spring-context-4.1.1.RELEASE进行了测试。

你不能没有自定义类加载器。

例如,考虑从甚至不提供目录列表的远程服务器加载类的情况。 你怎么可能迭代那里的所有课程?

classloader接口不提供这样的function。 但是如果您使用自己的类加载器(或扩展现有的类加载器),您可以添加此function。 无论如何,它并不漂亮。