AppClassLoaderにApache Commonsのライブラリを追加します。
実際は以下のように、リフレクションで追加します。 CoreModで使用するのであればIFMLLoadingPluginの実装クラスのコンストラクタ内で実行するのが、 通常のmodであれば@Modのクラスのコンストラクタ内で実行するのがいいかと思われます。
val addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addURL.setAccessible(true);
addURL.invoke(Launch.classLoader.getClass().getClassLoader(), <URL to Library>);
また、にはmavenレポジトリ内のURLを指定できますが、modのjar内に含めて、
ClassInYourMod.class.getClassLoader().getResource("/path/to/library.jar")
とするのがいいかと思います。(オフラインでの起動の対応のためです。)
-
configurations
にconfigurationを追加し、compileにextendさせますconfigurations{ jarInJar compile.extendsFrom jarInJar }
-
dependencies
でapacheのライブラリをjarInJarに追加しますdependencies { // compile "org.apache.commons:commons-compress:1.9" // 削除 jarInJar "org.apache.commons:commons-compress:1.9" }
-
jar
タスクで追加しますjar { configurations.jarInJar.each {dep -> from(dep){ into "path/to" // 上の "/path/to/library.jar"のpath/toの部分。library.jarは"commons-compress-1.9.jar"のようになる。 } } }
ForgeにおけるClassLoaderは以下のようになっています。
// javaパッケージなどのローダ
Bootstrap ClassLoader
A | A |
| | Parent| |Child
| | | V
| | ExtClassLoader (これはOracle/OpenJDK固有, jdkパッケージの一部がここからロード)
| | A |
Parent| |Child Parent| |Child
| | | V
| | AppClassLoader // ここから↑はJDK内
| | A
| | | 必要なときに呼び出し
| V |
LaunchClassLoader // forge
LaunchClassLoaderは殆どのマインクラフトのクラスをロードするClassLoaderになります。 Classファイルの実行時編集もLaunchClassLoaderによって発生します。
一部のパッケージ(javaパッケージ)はLaunchClassLoaderのクラスパス内には存在しません。 そのためjavaパッケージなど一部のクラスのロードには上図のようにAppClassLoaderを呼び出しています。
この一部のクラスの中に"org.apache.commons."パッケージ内のクラスが含まれています。 マインクラフト自体が使っている前提ライブラリの一部がApache Commonsのためです。 そのためmodのjar内に"org.apache.commons."パッケージがあってもロードできません。
Java8までは(マインクラフトはjava8で動いてます)AppClassLoaderはURLClassLoaderなので、
URLClassLoader.addURL(URL)
でクラスパスに追加したいです。
しかしaddURL
はprotected
のため、リフレクションで呼び出します。
また、AppClassLoaderはLaunchClassLoaderをロードするClassLoaderなので、
Launch.classLoader.getClass().getClassLoader()
で取得します。よって最初のコードで追加できます。