如何从类路径中的 Java 包中读取所有类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1456930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I read all classes from a Java package in the classpath?
提问by
I need to read classes contained in a Java package. Those classes are in classpath. I need to do this task from a Java program directly. Do you know a simple way to do?
我需要读取 Java 包中包含的类。这些类在类路径中。我需要直接从 Java 程序执行此任务。你知道一个简单的方法吗?
List<Class> classes = readClassesFrom("my.package")
回答by Brent Writes Code
That functionality is still suspiciously missing from the Java reflection API as far as I know. You can get a package object by just doing this:
据我所知,Java 反射 API 中仍然可疑地缺少该功能。您只需执行以下操作即可获取包对象:
Package packageObj = Package.getPackage("my.package");
But as you probably noticed, that won't let you list the classes in that package. As of right now, you have to take sort of a more filesystem-oriented approach.
但是您可能已经注意到,这不会让您列出该包中的类。截至目前,您必须采取一种更面向文件系统的方法。
I found some sample implementations in thispost
我在这篇文章中 找到了一些示例实现
I'm not 100% sure these methods will work when your classes are buried in JAR files, but I hope one of those does it for you.
当您的类隐藏在 JAR 文件中时,我不能 100% 确定这些方法会起作用,但我希望其中一种方法对您有用。
I agree with @skaffman...if you have another way of going about this, I'd recommend doing that instead.
我同意@skaffman...如果你有另一种方式来解决这个问题,我建议你这样做。
回答by idarwin
Brent - the reason the association is one way has to do with the fact that any class on any component of your CLASSPATH can declare itself in any package (except for java/javax). Thus there just is no mapping of ALL the classes in a given "package" because nobody knows nor can know. You could update a jar file tomorrow and remove or add classes. It's like trying to get a list of all people named John/Jon/Johan in all the countries of the world - none of us is omniscient therefore none of us will ever have the correct answer.
Brent - 关联是一种方式的原因与这样一个事实有关,即 CLASSPATH 的任何组件上的任何类都可以在任何包中声明自己(java/javax 除外)。因此,给定“包”中的所有类都没有映射,因为没有人知道也不能知道。您可以明天更新 jar 文件并删除或添加类。这就像试图获得世界上所有国家/地区所有名为 John/Jon/Johan 的人的列表 - 我们没有人是无所不知的,因此我们永远不会有正确的答案。
回答by brianegge
Back when applets were common place, one might have a URL on the classpath. When the classloader required a class, it would search all the locations on the classpath, including http resources. Because you can have things like URLs and directories on the classpath, there is no easy way to get a definitive list of the classes.
当小程序很常见时,一个人可能在类路径上有一个 URL。当类加载器需要一个类时,它会搜索类路径上的所有位置,包括 http 资源。因为类路径上可以有 URL 和目录之类的东西,所以没有简单的方法来获得类的明确列表。
However, you can get pretty close. Some of the Spring libraries are doing this now. You can get all the jar's on the classpath, and open them up like files. You can then take this list of files, and create a data structure containing your classes.
但是,您可以非常接近。一些 Spring 库现在正在这样做。您可以在类路径上获取所有 jar,并像打开文件一样打开它们。然后,您可以获取此文件列表,并创建一个包含您的类的数据结构。
回答by NawaMan
I happen to have implemented it, and it works in most cases. Since it is long, I put it in a file here.
我碰巧实现了它,并且在大多数情况下都有效。因为很长,我把它放在一个文件里。
The idea is to find the location of the class source file which is available in most cases (a known exception are JVM class files -- as far as I've tested). If the code is in a directory, scan through all files and only spot class files. If the code is in a JAR file, scan all entries.
这个想法是找到在大多数情况下可用的类源文件的位置(一个已知的例外是 JVM 类文件——就我测试过的而言)。如果代码在一个目录中,则扫描所有文件并仅发现类文件。如果代码在 JAR 文件中,请扫描所有条目。
This method can only be used when:
此方法只能在以下情况下使用:
You have a class that is in the same package you want to discover, This class is called a SeedClass. For example, if you want to list all classes in 'java.io', the seed class may be
java.io.File
.Your classes are in a directory or in a JAR file it has source file information (not source code file, but just source file). As far as I've tried, it work almost 100% except the JVM class (those classes come with the JVM).
Your program must have permission to access ProtectionDomain of those classes. If your program is loaded locally, there should be no problem.
您有一个类在您要发现的同一个包中,这个类称为 SeedClass。例如,如果要列出“java.io”中的所有类,则种子类可能是
java.io.File
.您的类位于一个目录或 JAR 文件中,它具有源文件信息(不是源代码文件,而只是源文件)。据我尝试,除了 JVM 类(这些类与 JVM 一起提供)之外,它几乎可以 100% 工作。
您的程序必须有权访问这些类的 ProtectionDomain。如果你的程序是本地加载的,应该没有问题。
I've tested the program only for my regular usage, so it may still have problem.
我只针对我经常使用的情况测试了该程序,所以它可能仍然有问题。
I hope this helps.
我希望这有帮助。
回答by John Ellinwood
Spring has implemented an excellent classpath search function in the PathMatchingResourcePatternResolver
. If you use the classpath*
: prefix, you can find all the resources, including classes in a given hierarchy, and even filter them if you want. Then you can use the children of AbstractTypeHierarchyTraversingFilter
, AnnotationTypeFilter
and AssignableTypeFilter
to filter those resources either on class level annotations or on interfaces they implement.
Spring 在PathMatchingResourcePatternResolver
. 如果您使用classpath*
: 前缀,您可以找到所有资源,包括给定层次结构中的类,甚至可以根据需要过滤它们。然后,您可以使用AbstractTypeHierarchyTraversingFilter
,AnnotationTypeFilter
和的子AssignableTypeFilter
级在类级别注释或它们实现的接口上过滤这些资源。
回答by Shalom938
If you have Springin you classpath then the following will do it.
如果您的类路径中有Spring,那么以下将执行此操作。
Find all classes in a package that are annotated with XmlRootElement:
查找包中使用 XmlRootElement 注释的所有类:
private List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
List<Class> candidates = new ArrayList<Class>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + "**/*.class";
Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (isCandidate(metadataReader)) {
candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
}
}
}
return candidates;
}
private String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}
private boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
try {
Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
if (c.getAnnotation(XmlRootElement.class) != null) {
return true;
}
}
catch(Throwable e){
}
return false;
}
回答by Paul Kuit
Java 1.6.0_24:
Java 1.6.0_24:
public static File[] getPackageContent(String packageName) throws IOException{
ArrayList<File> list = new ArrayList<File>();
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader()
.getResources(packageName);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
File dir = new File(url.getFile());
for (File f : dir.listFiles()) {
list.add(f);
}
}
return list.toArray(new File[]{});
}
This solution was tested within the EJBenvironment.
此解决方案已在EJB环境中进行了测试。
回答by Ondra ?i?ka
Bill Burke has written a (nice articleabout class scanning] and then he wrote Scannotation.
Hibernatehas this already written:
- org.hibernate.ejb.packaging.Scanner
- org.hibernate.ejb.packaging.NativeScanner
CDImight solve this, but don't know - haven't investigated fully yet
Bill Burke 写了一篇(关于类扫描的好文章),然后他写了Scannotation。
Hibernate已经写了这个:
- org.hibernate.ejb.packaging.Scanner
- org.hibernate.ejb.packaging.NativeScanner
CDI可能会解决这个问题,但不知道 - 还没有完全调查
.
.
@Inject Instance< MyClass> x;
...
x.iterator()
Also for annotations:
也用于注释:
abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
回答by Edoardo Panfili
I use this one, it works with files or jar archives
我使用这个,它适用于文件或 jar 档案
public static ArrayList<String>getClassNamesFromPackage(String packageName) throws IOException{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL packageURL;
ArrayList<String> names = new ArrayList<String>();;
packageName = packageName.replace(".", "/");
packageURL = classLoader.getResource(packageName);
if(packageURL.getProtocol().equals("jar")){
String jarFileName;
JarFile jf ;
Enumeration<JarEntry> jarEntries;
String entryName;
// build jar file name, then loop through zipped entries
jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
jarFileName = jarFileName.substring(5,jarFileName.indexOf("!"));
System.out.println(">"+jarFileName);
jf = new JarFile(jarFileName);
jarEntries = jf.entries();
while(jarEntries.hasMoreElements()){
entryName = jarEntries.nextElement().getName();
if(entryName.startsWith(packageName) && entryName.length()>packageName.length()+5){
entryName = entryName.substring(packageName.length(),entryName.lastIndexOf('.'));
names.add(entryName);
}
}
// loop through files in classpath
}else{
URI uri = new URI(packageURL.toString());
File folder = new File(uri.getPath());
// won't work with path which contains blank (%20)
// File folder = new File(packageURL.getFile());
File[] contenuti = folder.listFiles();
String entryName;
for(File actual: contenuti){
entryName = actual.getName();
entryName = entryName.substring(0, entryName.lastIndexOf('.'));
names.add(entryName);
}
}
return names;
}
回答by Renato
You could use the Reflections Project described here
您可以使用此处描述的反射项目
It's quite complete and easy to use.
它非常完整且易于使用。
Brief description from the above website:
来自上述网站的简要说明:
Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project.
反射扫描你的类路径,索引元数据,允许你在运行时查询它,并可以保存和收集项目中许多模块的信息。
Example:
例子:
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);