- ベストアンサー
外部jarの標準出力を取得できる方法
- ClassLoaderを使用して外部jarのクラスをロードし、標準出力を取得する方法について教えてください。
- SimpleOutputというクラスは、渡された引数を標準出力に表示するだけのものです。GUI上に表示するためには、この標準出力の値を取得する必要があります。
- 外部jarのクラスをロードし、そのクラスのmainメソッドを実行することで、SimpleOutputの標準出力の値を取得することができます。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
これ以上は、読み込むJarライブラリで引っかかっている可能性もありますのでなんともいえません。 ライブラリが自作のものであれば、まずはJarにせず、直接クラスをロードして動かすところからやってみて、問題がロードしたあとの処理か、ロードする時点で発生しているのか切り分けてはどうでしょう。 あと、ちょっと気になったんですが、読み込むクラスはデフォルトパッケージなんですか? 普通はあり得ないと思いますが。またmainは実装されているのですよね。
その他の回答 (3)
メソッドを実行した後、元のPrintStreamにsetOutで戻さないと表示されませんよ。 ざっと、以下の様な感じで試してみましたが、一応動いてるようです。参考までに。 PrintStream oldps = System.out; ByteArrayOutputStream as = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(as); System.setOut(ps); ClassLoader loader = ClassLoader.getSystemClassLoader(); //とりあえずSystemClassLoaderでテスト try { Class<?> cls = loader.loadClass("jp.hoge.LibClass"); // ロードするクラス Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"this is test"}; method.invoke(obj, new Object[]{av}); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } System.setOut(oldps); System.out.println("--------------------------------"); System.out.println(as); System.out.println("--------------------------------");
お礼
ClassLoaderの使い方に問題があるのか、 上記ソース参考に以下のようにすると、実行しても無反応です。 そのまんまコピペすると、ClassNotFound例外が投げられて、 ---のプリント文も出ています。 File file = new File(System.getProperty("user.dir"), "SimpeOutput.jar"); PrintStream oldps = System.out; ByteArrayOutputStream as = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(as); System.setOut(ps); try { URL[] urls = { file.toURI().toURL() }; ClassLoader loader = URLClassLoader.newInstance(urls); Class<?> cls = loader.loadClass("SimpleOutput"); // ロードするクラス Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"this is test"}; method.invoke(obj, new Object[]{av}); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | MalformedURLException | InvocationTargetException e) { e.printStackTrace(); } System.setOut(oldps); System.out.println("--------------------------------"); System.out.println(as); System.out.println("--------------------------------");
実際にやってないんですが……。method.invoke(obj, new Object[]{av}); を実行した後で、as.toString()でByteArrayOutputStreamからStringを取り出せないでしょうか。
お礼
遅くなって申し訳ありません。 そのようにして、取り出せなかったのですが、 どこかで例外がはかれているような動きだったので、 どこが問題かデバッグしようと試みたのですが、 ブレークポイントにすら止まらず、どうしていいか分からない状態です。 ByteArrayOutputStream as = new ByteArrayOutputStream(); System.setOut(new PrintStream(as)); Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"test"}; method.invoke(obj, new Object[]{av}); System.out.println("--------------------------------"); System.out.println(as); System.out.println("--------------------------------"); ---のプリント文も出力されません。
補足
System.out.println(as.toString()); でも何も出力されません。
System.setOut(PrintStream s); でSystem.outのPrintStreamを変更できます。ですので、あらかじめsetOutでPrintStreamを変更しておき、それからロードしたクラスを実行すれば、変更されたPrintStreamで結果を受け取れると思います。 例えば、 System.setOut(new PrintStream(new FileOutputStream(...)))とすれば指定のファイルに書きだされますし、FileOutputStreamの代りにByteArrayOutputStreamにすれば、出力内容を書きだすbyte配列からStringを取り出せるでしょう。
お礼
ありがとうございます。 以下のようにしてみたのですが、うまく動きません。 宣言の仕方が悪いでしょうか。 ByteArrayOutputStream宣言後にデバッグ文を入れても、ブレークポイントを張っても反応しないので、どこでどうなっているか分かりません。 System.out.println("Load class"); URL[] urls = { file.toURI().toURL() }; ClassLoader loader = URLClassLoader.newInstance(urls); Class<?> cls = loader.loadClass("SimpleOutput"); System.out.println(cls); ByteArrayOutputStream as = new ByteArrayOutputStream(); System.setOut(new PrintStream(as)); Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"test"}; method.invoke(obj, new Object[]{av});
お礼
eclipse上で実行すると、コンソールに外部jarの標準出力が出るので、外部jarの読込は問題ないと思っていましたが、たまたま動いていただけかもしれないですね。 今はテスト的に自作のjarをロードしていますが、 本当にやりたいのは自作のものではありません。 焦らず1つ1つ確認していってみます。 mainはもちろん実装されています。 最近javaを始めたばかりで、気にしていなかったのですが、 デフォルトパッケージはあり得ないのですね。 そこら辺も勉強してみます。 詳しく説明していただき、ありがとうございました。