外部jarの標準出力を取得できる方法

このQ&Aのポイント
  • ClassLoaderを使用して外部jarのクラスをロードし、標準出力を取得する方法について教えてください。
  • SimpleOutputというクラスは、渡された引数を標準出力に表示するだけのものです。GUI上に表示するためには、この標準出力の値を取得する必要があります。
  • 外部jarのクラスをロードし、そのクラスのmainメソッドを実行することで、SimpleOutputの標準出力の値を取得することができます。
回答を見る
  • ベストアンサー

外部jarの標準出力を取得できますか?

ClassLoaderで外部jarのクラスをロードし、実行するプログラムを作りました。 SimpleOutputは、単に渡された引数を標準出力に出すだけのものです。 この値を取得してGUI上に表示させたいのですが、取得する方法をご教授ください。 System.out.println("Load class"); URL[] urls = { file.toURI().toURL() }; ClassLoader loader = URLClassLoader.newInstance(urls); Class<?> cls = loader.loadClass("SimpleOutput"); System.out.println(cls); Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"test"}; method.invoke(obj, new Object[]{av});

  • Java
  • 回答数4
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
noname#247307
noname#247307
回答No.4

これ以上は、読み込むJarライブラリで引っかかっている可能性もありますのでなんともいえません。 ライブラリが自作のものであれば、まずはJarにせず、直接クラスをロードして動かすところからやってみて、問題がロードしたあとの処理か、ロードする時点で発生しているのか切り分けてはどうでしょう。 あと、ちょっと気になったんですが、読み込むクラスはデフォルトパッケージなんですか? 普通はあり得ないと思いますが。またmainは実装されているのですよね。

yurie1130
質問者

お礼

eclipse上で実行すると、コンソールに外部jarの標準出力が出るので、外部jarの読込は問題ないと思っていましたが、たまたま動いていただけかもしれないですね。 今はテスト的に自作のjarをロードしていますが、 本当にやりたいのは自作のものではありません。 焦らず1つ1つ確認していってみます。 mainはもちろん実装されています。 最近javaを始めたばかりで、気にしていなかったのですが、 デフォルトパッケージはあり得ないのですね。 そこら辺も勉強してみます。 詳しく説明していただき、ありがとうございました。

その他の回答 (3)

noname#247307
noname#247307
回答No.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("--------------------------------");

yurie1130
質問者

お礼

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("--------------------------------");

noname#247307
noname#247307
回答No.2

実際にやってないんですが……。method.invoke(obj, new Object[]{av}); を実行した後で、as.toString()でByteArrayOutputStreamからStringを取り出せないでしょうか。

yurie1130
質問者

お礼

遅くなって申し訳ありません。 そのようにして、取り出せなかったのですが、 どこかで例外がはかれているような動きだったので、 どこが問題かデバッグしようと試みたのですが、 ブレークポイントにすら止まらず、どうしていいか分からない状態です。 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("--------------------------------"); ---のプリント文も出力されません。

yurie1130
質問者

補足

System.out.println(as.toString()); でも何も出力されません。

noname#247307
noname#247307
回答No.1

System.setOut(PrintStream s); でSystem.outのPrintStreamを変更できます。ですので、あらかじめsetOutでPrintStreamを変更しておき、それからロードしたクラスを実行すれば、変更されたPrintStreamで結果を受け取れると思います。 例えば、 System.setOut(new PrintStream(new FileOutputStream(...)))とすれば指定のファイルに書きだされますし、FileOutputStreamの代りにByteArrayOutputStreamにすれば、出力内容を書きだすbyte配列からStringを取り出せるでしょう。

yurie1130
質問者

お礼

ありがとうございます。 以下のようにしてみたのですが、うまく動きません。 宣言の仕方が悪いでしょうか。 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});

関連するQ&A

  • 指定されたクラスの継承元の確認方法

    Class cls = Class.forName("extendsClass"); Object obj = cls.newInstance(); if (obj instanceof AbstractClass) {   System.out.println("継承してた");   ((AbstractClass)obj).method(); } こんなことをして、objのクラスがAbstractClassを継承しているという ことは確認することが出来たのですが、これはやはり継承しているか どうかを確認する為にインスタンス化を行っています。 指定された名称のクラスが、特定のクラスを継承していた場合に限り、 その名称のクラスをインスタンス化する、 という流れは行えないのでしょうか?

    • ベストアンサー
    • Java
  • リフレクション

    リフレクションによって、Stringの値(strVal)を各クラスのオブジェクトに変換したいと思っております。 下のようなコードで、this.typeにセットしてあるオブジェクトのvalueOfメソッドを実行したいのですが、clazz.getMethod部分で次のようなExceptionが発生してしまいます。 staticメソッドはgetMethodでは取得・実行できないのでしょうか? ご存知の方いらっしゃいましたら、教えて頂けないでしょうか。 【Exception】 java.lang.NoSuchMethodException: java.lang.String.valueOf() 【コード】 Class clazz = Class.forName(this.type); Method method = clazz.getMethod("valueOf", new Class[0]); return method.invoke(clazz.newInstance(), new Object[]{strVal} ); 今回、this.typeには、"java.lang.String"が入っています。

    • ベストアンサー
    • Java
  • ClassLoaderを作成してみたいのですが

    クラスから別の場所のクラスを呼び出す構造を作りたくて、ClassLoaderを勉強しています。 まず、ClassLoaderを継承したLoaderを作成しなくてはいけないというのがわかり、その中で抽象メソッドloadClassと、関係するdefine,resolve,findSystemなどを記述してやるらしいというのまでは、あやふやながら理解できました。 それで、呼び出す側では、Loader.loadClassを呼んでクラスをロードし、newInstanceメソッドを呼べば、その実体ができる"らしい"まで解読して頭がパンクしてしまいました。 疑問は、以下の通りです。 ・「Loaderは自分で作らないといけない」とあったのですが、ClassLoaderを継承させたLoaderを自前で書かないといけないのでしょうか。単にオブジェクトを生成するだけでいいんでしょうか。簡単なサンプルがあれば嬉しいのですが・・・。 ・ ひとまず、簡単な計算を行うクラスを作って呼び出してみたいのですが、newInstanceを実行するとインスタンスが生成されて即中身が実行される、という説明文を読んだのですが、値の受け渡しはどうすればできるのでしょうか。 以上、よろしくご教示お願いいたします。

    • ベストアンサー
    • Java
  • Java リフレクションについて

    1.リフレクションを使い、値をセット(BeanのSetterメソッドにて) 2.1でセットした値を取得するために、下記コードで取得 Method Method = Class.getMethod("getLstData"); Object obj = Method.invoke(****); 上記の****の箇所には、メソッドのあるクラスのインスタンスを渡す、 というところまでは分かりますが、newInstance()してしまうと、新しいオブジェクトになってしまうので 値が取得できません。 error>>java.lang.IllegalArgumentException: object is not an instance of declaring class どのようにすれば、値の取得が可能でしょうか。 どなたかご教授いただければと思います。 ※Java 1.5を使用

    • ベストアンサー
    • Java
  • リフレクション

    Webアプリ上でリフレクションにてとあるクラスのメソッドを実行するサンプルを作成して 見たのですがうまく動きませんでした。最後のmethod.invoke()の処理にてExceptionが発生し、 java.lang.IllegalArgumentException: object is not an instance of declaring class と表示されてしまいます。 作成したサンプルは下記なのですがどこが原因かお分かりになりますでしょうか。 try { Class cls = Class.forName("dao.TestDao"); // 引数の型をセット Constructor constructor = cls.getDeclaredConstructor(HttpSession.class); constructor.setAccessible(true); // 引数を渡してオブジェクトを生成 Object obj = constructor.newInstance(session); Method method = cls.getDeclaredMethod("getDataDao", int.class); method.setAccessible(true); Object result = method.invoke(cls, new Integer(100)); } catch (Exception e) { e.printStackTrace(); } // このクラスのgetDataDao()をリフレクションにて実行 public class TestDao { HttpSession session = null; public TestDao(HttpSession session) { this.session = session; } public List<String> getDataDao(int iNo) { List<String> list = new ArrayList<String>(); list.add((String)session.getAttribute("1")); list.add((String)session.getAttribute("2")); list.add((String)session.getAttribute("3")); list.add((String)session.getAttribute("4")); list.add((String)session.getAttribute("5")); return list; } }

    • ベストアンサー
    • Java
  • メソッドのオーバーライド(java)

    class A3{ void hello(){ System.out.println("A3"); } void hello(int i){ System.out.println("A3"+i); } } class B3 extends A3{ void hello(){ System.out.println("B3"); } } class C3 extends B3{ void hello(String s){ System.out.println("C3"+s); } } class MethodOverriding3{ public static void main(String args[]){ A3 obj = new C3(); obj.hello(); } } 上のプログラムを実行すると"B3"と表示されまが、どうしてクラスBのメソッドが実行されるのでしょうか? クラスAのメソッドが無視される仕組みがわかりません。 また、クラスMethodOverriding3でobj.hello("abc")としてコンパイルすると mo.java:25: シンボルを見つけられません。 シンボル: メソッド hello(java.lang.String) 場所 : A3 の クラス obj.hello("abc");   ^ エラー 1 個 とエラーが出ます。 どうしてでしょうか? 誰か教えてください、お願いします。

    • ベストアンサー
    • Java
  • リフレクション 可変長引数メソッドの取得

    リフレクションで、(1)の方のメソッドインスタンスを得たいとき、どういった方法が考えられますか? //JDK 6.0 public Hoge { void method1(String str, Object ...objs){}//(1) void method1(String str, String str2){}//(2) } Hoge hoge = new Hoge(); Class c = hoge.getClass(); Method m12 = c.getMethod("method", String.class, String.class); Method m11 = c.getMethod("method", ?? );

    • ベストアンサー
    • Java
  • 外部ライブラリについて

    Java初心者です・・。 eclipse上で、以下のソースで実行したところ、エラーになりました。 外部のライブラリを使用しているからかと思い、ビルド・パスを設定しました。 しかし・・・まだエラーが表示されます・・・。 どなたかご存知の方・・・アドバイスをお願いします。 [ソース] import javax.swing.*; import java.awt.*; class FusenExec { static public void main(String[] args) { String msg =JOptionPane.showInputDialog ("メッセージを入力して下さい。"); Dodai fusen = new Dodai(); JLabel label = new JLabel(msg); label.setOpaque(true); label.setBackground( Color.YELLOW); fusen.add(label); fusen.setSize(300, 50); fusen.setVisible(true); } } [エラー内容] Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version number in .class file at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) at FusenExec.main(FusenExec.java:10)

    • ベストアンサー
    • Java
  • ”メンバ指定”で表示させる順がわかりません

    一番したにかいたプログラムなんですが、 System.out.println("**********基本的なメンバ操作***********"); の次の表示させるコードは System.out.println("+++++++++++クラスメンバをインスタンス名で操作+++++++++++"); となっているのに、実行結果が **********基本的なメンバ操作*********** インスタンスメソッド: インスタンス変数=100クラス変数=300 インスタンスメソッド: インスタンス変数=200クラス変数=300 クラスメソッド;クラス変数=300 +++++++++++クラスメンバをインスタンス名で操作+++++++++++ d1のクラス変数=400 d2のクラス変数=400 MyClsのクラス変数=400 でした。 どういう順で処理されているのでしょうか。 超初心者です。変なことをたぶん聞いていると思いますが教えてください。 class MyCls { int ins_hensu = 0; static int cls_hensu = 0; public void ins_method() { System.out.println("インスタンスメソッド: インスタンス変数=" + ins_hensu + "クラス変数=" + cls_hensu); } public static void cls_method(){ System.out.println("クラスメソッド;クラス変数=" + cls_hensu); } } public class JaCls08{ public static void main(String args[]) { MyCls d1 = new MyCls(),d2 = new MyCls(); System.out.println("**********基本的なメンバ操作***********"); d1.ins_hensu = 100; d2.ins_hensu = 200; MyCls.cls_hensu = 300; d1.ins_method(); d2.ins_method(); MyCls.cls_method(); System.out.println("+++++++++++クラスメンバをインスタンス名で操作+++++++++++"); d1.cls_hensu =400; System.out.println("d1のクラス変数=" + d1.cls_hensu); System.out.println("d2のクラス変数=" + d2.cls_hensu); System.out.println("MyClsのクラス変数=" + MyCls.cls_hensu); } }

    • ベストアンサー
    • Java
  • JavaとMySQLを接続できなくて困っています。

    MySQLで作成したデータベースをJavaを使って表示するというプログラムを作っているのですが、JDBCドライバがうまく機能せず、接続できません。初歩的な問題なのだとは思いますが、どなたか解決方法を教えてください。 import java.sql.*; public class Iwate1 { /** * @param args */ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ try{ String drv = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql:///iwate"; String usr = "----"; String pw = "-------"; Class.forName(drv).newInstance(); Connection cn = DriverManager.getConnection(url, usr, pw); Statement st = cn.createStatement(); String qry = "SELECT * FROM iwate_table"; ResultSet rs = st.executeQuery(qry); ResultSetMetaData rm = rs.getMetaData(); int cnum = rm.getColumnCount(); while(rs.next()){ for(int i=1; i<=cnum; i++){ System.out.print(rm.getColumnName(i)+":"+rs.getObject(i)+" "); } System.out.println(""); } rs.close(); st.close(); cn.close(); } catch(Exception e){ e.printStackTrace(); } } } 結果は java.lang.ClassNotFoundException: com.mysql.jdbc.Driver at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:169) at Iwate1.main(Iwate1.java:17)

専門家に質問してみよう