- PR -

独自クラスローダで外部 Jar に含まれるクラスを使用するには?

投稿者投稿内容
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-04-26 11:59
引用:

仰りたい事はわかります。
しかし、私の方法だと下記の問題が発生しません。


VMにおける「問題」ではなくVMの仕様ですので、
VMの仕様に合うように作成するべきだと思います。

質問者は外部jarのインスタンスが欲しいとの事ですので、
外部プロセスのインスタンスが欲しい場合、
VM間通信を行わなければいけません。
他にも今回の件には該当しないかもしれませんが、
トランザクションやリソースの衝突などの問題も解決しなければいけません。
ですので、今回の件では外部プロセスの起動は向かないと思います。

単純にmainメソッド経由で起動したいだけなら
外部プロセス化でもいいと思います。
まさ
ベテラン
会議室デビュー日: 2002/11/15
投稿数: 74
投稿日時: 2005-05-25 20:01
まさです。

先日での内容と多少異なってしまうのですが、
外部の LookAndFeel をプラグインのような形でアプリケーションに適用したいと思っています。
しかし、この場合も外部の Jar をうまく読めないようです。

コード:

UIManager.setLookAndFeel(lookAndFeel);



処理後、ComponentUI が無いとかで Error がトレースされます。

下記はサンプルコードですが、
(1)、(2) を設定ファイルに記述しておいてアプリケーションでそれを読み込んだら
外部 Jar 内の LookAndFeel を設定したいんです。

このサンプルなら、別プロセスじゃだめな理由が
ぽん様にもご理解いただけるのではと思います。

下記のサンプルコードのような手順で処理をしているのですが、
LookAndFeel を外部 Jar から取り込めるようにはできないんでしょうかね。

コード:

import java.awt.Container;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;

public class Sample {

    /** LookAndFeel の読み込みと設定    */
    private static void setLookAndFeel() {

        //  対象の LookAndFeel のクラス名 --- (1)
        String lafName;
//        lafName = "de.muntjak.tinylookandfeel.TinyLookAndFeel";
        lafName = "com.l2fprod.gui.plaf.skin.SkinLookAndFeel";

        //  対象の LookAndFeel のバイトコードが含まれるパス --- (2)
        String libraryPath;
//        libraryPath = "./lib/tinylaf-beta-1.2.1/tinylaf.jar";
        libraryPath = "./lib/skin/skinlf.jar";

        //  LookAndFeel 取り込み用クラスローダの作成
        URLClassLoader classLoader;
        {
            File jarFile;
            jarFile = new File(libraryPath);

            URL[] paths;
            try {
                paths = new URL[] {
                        jarFile.toURL(),
                    };

            } catch (MalformedURLException ex) {
                ex.printStackTrace(System.err);
                paths = new URL[0];
            }

            //  親とするクラスローダ
            ClassLoader parentLoader;
//            parentLoader = ClassLoader.getSystemClassLoader();
            parentLoader = Thread.currentThread().getContextClassLoader();

            //  LookAndFeel 取り込み用クラスローダ
            classLoader = URLClassLoader.newInstance(paths, parentLoader);
        }


        //  対象の LookAndFeel のインスタンス化と LookAndFeel の設定
        try {
            //  対象の LookAndFeel のインスタンス化
            Class lafClass;
            lafClass = Class.forName(lafName, true, classLoader);

            LookAndFeel lookAndFeel;
            lookAndFeel = (LookAndFeel) lafClass.newInstance();

            //  対象の LookAndFeel の適用
            UIManager.setLookAndFeel(lookAndFeel);

        } catch (Exception ex) {
            ex.printStackTrace(System.err);
        }
    }

    /** ウインドウの表示    */
    private static void openWindow() {

        JComboBox combo;
        {
            Object[] comboData;
            comboData = new Object[] {
                    "Item 1",
                    "Item 2",
                    "Item 3",
                };

            combo = new JComboBox(comboData);
        }


        JFrame frame;
        frame = new JFrame("Sample Frame");

        Container frameContainer;
        frameContainer = frame.getContentPane();
        frameContainer.add(combo);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    /** アプリケーション起動    */
    public static void main(final String[] args) {
        setLookAndFeel();
        openWindow();
    }

}


いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2005-05-26 14:42
classLoaderというクラスローダのインスタンスを作ってL&Fに設定しても、
JFrameなどそれぞれのインスタンス作成時もそのclassLoaderが見えてないと
指定したUIの部品はできません。
そうすると非常に面倒ですがUIの部品1つ1つをclassLoaderでインスタンス化
していくか、もしくは手っ取り早い方法はclassLoaderを作成後、
現在のスレッドのクラスローダをclassLoaderに置き換えてみればうまくいくかもしれませんね。
ThreadクラスのsetContextClassLoaderでできるんじゃないでしょうか?

がんばって見て下さい。
まさ
ベテラン
会議室デビュー日: 2002/11/15
投稿数: 74
投稿日時: 2005-05-27 10:21
お世話になります。まさです。

引用:

手っ取り早い方法はclassLoaderを作成後、
現在のスレッドのクラスローダをclassLoaderに置き換えてみればうまくいくかもしれませんね。
ThreadクラスのsetContextClassLoaderでできるんじゃないでしょうか?




できちゃいました。 (^^)v
setLookAndFeel 周りを次のようにしました。

コード:

            ClassLoader oldLoader;
            oldLoader = currentThread.getContextClassLoader();

            currentThread.setContextClassLoader(classLoader);

            //  対象の LookAndFeel の適用
            UIManager.setLookAndFeel(lookAndFeel);

//            currentThread.setContextClassLoader(oldLoader);




ひとつ心配事があります。
setLookAndFeel 後、上記のコメントの行で
基のクラスローダに戻そうとすると今まで通りエラーが出ます。

コード:

            //  LookAndFeel 取り込み用クラスローダ
            classLoader = URLClassLoader.newInstance(paths, parentLoader);



の部分で、基のコンテキストクラスローダを親クラスローダに指定しているので
基に戻す必要は無いのかなと考えていますが、どうなんでしょうか?
後々、基のクラスローダに戻した方がいいのでしょうか?

スキルアップ/キャリアアップ(JOB@IT)