Javaパッケージに含まれるクラスを読み取る必要があります。これらのクラスはクラスパスにあります。このタスクをJavaプログラムから直接行う必要があります。簡単な方法を知っていますか?
List<Class> classes = readClassesFrom("my.package")
Javaパッケージに含まれるクラスを読み取る必要があります。これらのクラスはクラスパスにあります。このタスクをJavaプログラムから直接行う必要があります。簡単な方法を知っていますか?
List<Class> classes = readClassesFrom("my.package")
回答:
あなたが持っている場合は春をあなたにクラスパス、その後、次はそれを行います。
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は、優れたクラスパス検索機能をに実装してい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");
しかし、おそらくお気づきのように、そのパッケージ内のクラスを一覧表示することはできません。今のところ、あなたはファイルシステム指向のアプローチのようなものを取る必要があります。
この投稿 でいくつかのサンプル実装を見つけました
クラスがJARファイルに埋め込まれている場合にこれらのメソッドが機能するかどうかは100%わかりませんが、そのうちの1つが機能することを願っています。
@skaffmanに同意します...これについて別の方法がある場合は、代わりに行うことをお勧めします。
特定のパッケージ内のすべてのクラスを一覧表示するための最も堅牢なメカニズムは、新しいJPMSモジュールシステムを含むクラスパス指定メカニズムの可能な限り幅広い配列を処理するため、現在はClassGraphです。(私は著者です。)
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クラスを除いてほぼ100%機能します(これらのクラスにはJVMが付属しています)。
プログラムには、これらのクラスのProtectionDomainにアクセスする権限が必要です。プログラムがローカルに読み込まれている場合、問題はありません。
私は定期的に使用するためだけにプログラムをテストしたので、まだ問題があるかもしれません。
これがお役に立てば幸いです。
ここに別のオプションがあります、上/下の別の答えを少し変更します:
Reflections reflections = new Reflections("com.example.project.package",
new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);
依存関係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));
}
});
ブレント-関連付けが1つの方法である理由は、CLASSPATHの任意のコンポーネントの任意のクラスが任意のパッケージ(java / javaxを除く)で宣言できるという事実に関係しています。したがって、誰も知らず、知ることもできないため、特定の「パッケージ」内のすべてのクラスのマッピングはありません。明日、jarファイルを更新し、クラスを削除または追加できます。これは、世界のすべての国でJohn / Jon / Johanという名前のすべての人のリストを取得しようとするようなものです。誰も万能ではないため、正しい答えを得る人はいません。