从包中获取所有类
假设我有一个java包commands
,其中包含所有inheritance自ICommand
类,我能以某种方式获得所有这些类吗? 我正在锁定以下内容:
Package p = Package.getPackage("commands"); Class[] c = p.getAllPackagedClasses(); //not real
有可能吗?
这是一个基本的例子,假设类不是JAR打包的:
// Prepare. String packageName = "com.example.commands"; List> commands = new ArrayList>(); URL root = Thread.currentThread().getContextClassLoader().getResource(packageName.replace(".", "/")); // Filter .class files. File[] files = new File(root.getFile()).listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".class"); } }); // Find classes implementing ICommand. for (File file : files) { String className = file.getName().replaceAll(".class$", ""); Class> cls = Class.forName(packageName + "." + className); if (ICommand.class.isAssignableFrom(cls)) { commands.add((Class ) cls); } }
下面是使用JSR-199 API的实现,即来自javax.tools.*
类javax.tools.*
:
List commands = new ArrayList (); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null); Location location = StandardLocation.CLASS_PATH; String packageName = "commands"; Set kinds = new HashSet(); kinds.add(JavaFileObject.Kind.CLASS); boolean recurse = false; Iterable list = fileManager.list(location, packageName, kinds, recurse); for (JavaFileObject javaFileObject : list) { commands.add(javaFileObject.getClass()); }
这是一个使用Spring的实用方法。
有关模式的详细信息,请参见此处
public static List listMatchingClasses(String matchPattern) throws IOException { List classes = new LinkedList (); PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver(); Resource[] resources = scanner.getResources(matchPattern); for (Resource resource : resources) { Class> clazz = getClassFromResource(resource); classes.add(clazz); } return classes; } public static Class getClassFromResource(Resource resource) { try { String resourceUri = resource.getURI().toString(); resourceUri = resourceUri.replace(esourceUri.indexOf(".class"), "").replace("/", "."); // try printing the resourceUri before calling forName, to see if it is OK. return Class.forName(resourceUri); } catch (Exception ex) { ex.printStackTrace(); } return null; }
从公共Classloader.getResources(String name)开始。 向类加载器询问与您感兴趣的包中的每个名称对应的类。 重复所有相关的类加载器。
是的,但这不是最简单的事情。 这有很多问题。 并非所有课程都很容易找到。 有些类可以在:Jar,作为类文件,通过网络等。
看看这个post。
要确保它们是ICommand类型,那么您必须使用reflection来检查inheritance类。
这将是我们需要的非常有用的工具,JDK应该提供一些支持。
但是在构建期间可能会做得更好。 您知道所有类文件的位置,您可以静态检查它们并构建图形。 在运行时,您可以查询此图以获取所有子类型。 这需要更多的工作,但我相信它确实属于构建过程。
使用Johannes Link的ClasspathSuite ,我能够这样做:
import org.junit.extensions.cpsuite.ClassTester; import org.junit.extensions.cpsuite.ClasspathClassesFinder; public static List> getClasses(final Package pkg, final boolean includeChildPackages) { return new ClasspathClassesFinder(new ClassTester() { @Override public boolean searchInJars() { return true; } @Override public boolean acceptInnerClass() { return false; } @Override public boolean acceptClassName(String name) { return name.startsWith(pkg.getName()) && (includeChildPackages || name.indexOf(".", pkg.getName().length()) != -1); } @Override public boolean acceptClass(Class> c) { return true; } }, System.getProperty("java.class.path")).find(); }
ClasspathClassesFinder在系统类路径中查找类文件和jar。
在您的特定情况下,您可以像这样修改acceptClass:
@Override public boolean acceptClass(Class> c) { return ICommand.class.isAssignableFrom(c); }
有一点需要注意:小心你在acceptClassName中返回的内容,因为ClasspathClassesFinder的下一步是加载类并调用acceptClass。 如果acceptClassName总是返回true,那么最终将加载类路径中的每个类,这可能会导致OutOfMemoryError。
您可以使用OpenPojo并执行此操作:
final List pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);
然后,您可以查看列表并执行所需的任何function。
- kafka KStream – 采用n秒计数的拓扑
- 方法iterator()在java.util.Collection和java.lang.Iterable中声明,它的超级接口?
- 启动服务时出现Jpa-hibernate错误
- 是否可以使用带有JPA的Spring MVC仅更新实体上的属性子集?
- 运行hbase MR作业时,我的cdh5.2集群会出现FileNotFoundException
- 是否可以在同一帧中打开一个新的fxml文件
- 为Julia集生成自定义调色板
- 当手动分配ID时,Spring Data MongoDB Annotation @CreatedDate不起作用
- 如何使用LDAP,应用程序,第三方应用程序等进行身份validation