質問: コントロールパネルでシステム環境変数のCLASSPATHにclassファイルを置いてある場所を指定してあります。コンパイルや、コマンドでの実行はできますが、jarファイルを作ると一緒に入れてくれなくて、実行時にNoClassDefFoundErrorが出ます。 自動で入れてくれるように設定できますか? jar cvfm Sample.jar s.mf *.class でやってます。 追記: ダウンロードしたパッケージは使ってません(使ったことがありません)。 作ったclassファイルをフォルダにおいて、フォルダをクラスパスに設定してあります。 s.mfの中身は、 Main-Class: Sample の1行と改行1つだけです。 今までは、jarを作る度に一緒に入れるクラスファイルをプロジェクトのフォルダにコピーして、*.classでいっぺんに入れていましたが、今日org.apache.commons.lang3.math.NumberUtilsをダウンロードして使ってみたらその方法ではパッケージがなんとかってエラーが出て失敗しました。
回答: まず、自分が作ったjarと、外部提供jarを使用する場合について書きます。 おそらく、現在は次のようなコマンドで実行していると思います。 ``` > java -jar Sample.jar ``` しかし、`-jar`オプションをつけた場合、(環境変数や`-cp`,`-classpath`オプションで設定した)クラスパス設定は無視されます。 * Java: -jar と -classpath は併用できない - sardineの日記 オフィシャルのドキュメントでは、次の箇所が該当しますね。(該当Java8ドキュメントは日本語化されていないようですが) : > > When you use the -jar option, the specified JAR file is the source of all user classes, and other class path settings are ignored. > > > > > このオプションを使用すると、指定した JAR ファイルがすべてのユーザークラスのソースになり、ユーザークラスパスのほかの設定は無視されます。 > > > というわけで、`-jar`オプションを使わずに実行するようにすればクラスパス設定は効きます。 ``` > java -cp Sample.jar;commons-lang3-3.4.jar Sample ``` クラスパスに自分で作ったjarと外部製のjarを両方指定し、かつ、(マニフェストファイルのメインクラス記述を利用できないので)明示的に実行するクラスを指定してあげる方法です。 次に、上記の方法ではちょっとコマンドが煩雑なので、マニフェストファイルを利用して簡略化します。 マニフェストファイル(`s.mf`)の内容を以下のようにしてください。 ``` Main-Class: Sample Class-Path: commons-lang3-3.4.jar ``` そして、いつもどおり`jar`を作成します。 ``` > jar cvfm Sample.jar s.mf *.class ``` これで、カレントディレクトリに`Sample.jar`と`commons-lang3-3.4.jar`を置いておけば、従来通り次のコマンドで実行できるようになります。 ``` > java -jar Sample.jar ``` 勘違いされていると思うのでここで繰り返しておきますが、`-jar`オプションを指定した場合、環境変数`CLASSPATH`に設定した内容は無視されます。 今`org.apache.commons.lang3.math.NumberUtils`が参照できているのは、マニフェストファイルにクラスパス設定を行っているからです。 上記の方法だと、jarファイルが2つになって、やはりちょっと煩雑です。これをひとつにまとめたい...となると、一旦`commons-lang3-3.4.jar`を解凍し、自分の作成したクラスと統合した上でjarを作る必要が出てきます。 その作業を自動化してくれるツールがmaven assembly pluginなどです。 (1ファイル化されたjarのことを、Fat-Jarと呼んだりUber-Jarと呼んだりするようですので、興味があればこれらの単語で検索してみてください)。 (補足) 私は、jarで提供されているものはjarのまま使用したほうが良いと思います。 例えば、今回のNumberUtilsのソースはこちらになりますが、 ``` import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; ``` とある通り、このクラスは単独では動かず、別のクラスファイルも必要になります(そしてこれらのクラスもまた別のクラスを要求しているかもしれないわけです)。 これらをいちいち考えながら使用するのは面倒すぎます。