我需要阅读Java包中包含的类。这些类在类路径中。我需要直接从Java程序执行此任务。您知道简单的方法吗?
List<Class> classes = readClassesFrom("my.package")
我需要阅读Java包中包含的类。这些类在类路径中。我需要直接从Java程序执行此任务。您知道简单的方法吗?
List<Class> classes = readClassesFrom("my.package")
Answers:
如果您的类路径中包含Spring,则可以执行以下操作。
在包中找到所有用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;
}
您可以使用此处描述的思考项目
它非常完整且易于使用。
上述网站的简要说明:
Reflections扫描您的类路径,为元数据建立索引,使您可以在运行时对其进行查询,并可以保存和收集项目中许多模块的信息。
例:
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);
我用这个,它可以处理文件或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;
}
Spring在中实现了出色的classpath搜索功能PathMatchingResourcePatternResolver
。如果使用classpath*
:前缀,则可以找到所有资源,包括给定层次结构中的类,甚至可以根据需要过滤它们。然后,您可以使用的子级AbstractTypeHierarchyTraversingFilter
,AnnotationTypeFilter
并AssignableTypeFilter
在类级别的注释或它们实现的接口上过滤这些资源。
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[]{});
}
该解决方案在EJB环境中进行了测试。
Scannotation和Reflections使用类路径扫描方法:
Reflections reflections = new Reflections("my.package");
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);
另一种方法是使用Java Pluggable Annotation Processing API编写注释处理器,该处理器将在编译时收集所有带注释的类并构建索引文件以供运行时使用。该机制在ClassIndex库中实现:
Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");
据我所知,Java反射API仍可疑地缺少该功能。您可以通过执行以下操作获取包对象:
Package packageObj = Package.getPackage("my.package");
但是,您可能已经注意到,这不会让您列出该软件包中的类。到目前为止,您必须采取一种更加面向文件系统的方法。
我在这篇文章中 找到了一些示例实现
我不是100%确信当您的类埋在JAR文件中时,这些方法是否会起作用,但是我希望其中一种能为您做到。
我同意@skaffman ...如果您还有另一种解决方法,建议您改用该方法。
当前列出给定包中所有类的最健壮的机制是ClassGraph,因为它可以处理最广泛的类路径规范机制,包括新的JPMS模块系统。(我是作者。)
List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
.enableClassInfo().scan()) {
classNames = scanResult.getAllClasses().getNames();
}
eXtcos看起来很有希望。假设您要查找所有符合以下条件的类:
使用eXtcos,这就像
ClasspathScanner scanner = new ClasspathScanner();
final Set<Class> classStore = new ArraySet<Class>();
Set<Class> classes = scanner.getClasses(new ClassQuery() {
protected void query() {
select().
from(“common”).
andStore(thoseExtending(Component.class).into(classStore)).
returning(allAnnotatedWith(MyComponent.class));
}
});
Bill Burke写了一篇(有关类扫描的不错的文章),然后他写了Scannotation。
Hibernate已经编写了以下代码:
CDI可以解决这个问题,但不知道-尚未进行全面调查
。
@Inject Instance< MyClass> x;
...
x.iterator()
也用于注释:
abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
我恰好实现了它,并且在大多数情况下都可以使用。由于很长,我把它放在这里的文件中。
这个想法是找到在大多数情况下都可用的类源文件的位置(据我所测试,JVM类文件是一个已知的例外)。如果代码在目录中,请扫描所有文件,仅扫描类文件。如果代码在JAR文件中,请扫描所有条目。
此方法只能在以下情况下使用:
您有一个与要发现的包相同的类,该类称为SeedClass。例如,如果要列出“ java.io”中的所有类,则种子类可能是java.io.File
。
您的类位于目录中或JAR文件中,它具有源文件信息(不是源代码文件,而只是源文件)。据我所试,除JVM类(那些类随JVM一起提供)外,它几乎可以100%工作。
您的程序必须具有访问这些类的ProtectionDomain的权限。如果您的程序是本地加载的,那应该没有问题。
我仅对该程序进行了常规使用测试,因此它可能仍然有问题。
我希望这有帮助。
使用依赖Maven:
groupId: net.sf.extcos
artifactId: extcos
version: 0.4b
然后使用此代码:
ComponentScanner scanner = new ComponentScanner();
Set classes = scanner.getClasses(new ComponentQuery() {
@Override
protected void query() {
select().from("com.leyton").returning(allExtending(DynamicForm.class));
}
});
Brent-关联是一种方式的原因与CLASSPATH的任何组件上的任何类都可以在任何程序包中声明自己有关(Java / javax除外)。因此,给定的“包”中没有所有类的映射,因为没人知道也不知道。您明天可以更新jar文件并删除或添加类。这就像试图获取世界上所有国家/地区的所有名叫John / Jon / Johan的人的名单一样-我们每个人都不是无所不知的,因此我们每个人都找不到正确的答案。