普段から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 件のコメント:
コメントを投稿