普段からSpringなどのDIフレームワークを使っているのですが、
Springでは、xmlファイルでパッケージ名を指定すると、そのパッケージ内のクラスをインスタンス化して注入してくれます。
便利な機能なのでよく使うのですが、どのようにしてパッケージ名からクラス一覧を取得しているかを知りませんでした。
実装を知るには、ソースを読めば手っ取り早いですが、今回はソースは読まずに、実装方法はこんな感じだろうかと考えてみます。
- パッケージ名から、そのパッケージ内のクラス一覧を取得する
-
import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardLocation; import javax.tools.ToolProvider; /** * 指定パッケージ内のクラス情報のコレクションを返す。 * * @param x_packageName パッケージ名 * @return クラス情報のコレクション */ public static Collection<Class<? extends Object>> getClasses(String x_packageName) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaFileManager fm = compiler.getStandardFileManager(new DiagnosticCollector<JavaFileObject>(), null, null); // 一覧に含めるオブジェクト種別。(クラスのみを含める) Set<JavaFileObject.Kind> kind = new HashSet<JavaFileObject.Kind>(); kind.add(JavaFileObject.Kind.CLASS); Collection<Class<? extends Object>> results = new ArrayList<Class<? extends Object>>(); Iterable<JavaFileObject> jfos = null; try { jfos = fm.list(StandardLocation.CLASS_PATH, x_packageName, kind, false); } catch (IOException e) { e.printStackTrace(); } if (jfos != null) { for (JavaFileObject fos : jfos) { try { Class<? extends Object> clazz = Class.forName(x_packageName + "." + fos.getName().replaceAll("\\.class$", "")); if (clazz.isEnum() || clazz.isInterface() || clazz.isAnonymousClass() || clazz.isLocalClass()) { continue; } results.add(clazz); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } return results; }
-
使用するのはjava.lang.reflectパッケージのクラスかと思っていましたが、実際はjavax.toolsパッケージのクラスです。
これらのクラスがあるのは、javaのバージョン1.6以降のようです。
バージョン1.5以前ではもうちょっと面倒なやり方になると思います。
フレームワークの実装を知ることで、フレームワークの使い方を知ります。
今回は、実装を想像しただけですが...
0 件のコメント:
コメントを投稿