Skip to content

Apache SparkとJava 17の問題:「cannot access class sun.nio.ch.DirectBuffer」の解決方法

問題の概要

Apache Spark 3.3.0をJava 17環境で実行すると、次のようなエラーが発生します:

java.lang.IllegalAccessError: class org.apache.spark.storage.StorageUtils$ (in unnamed module @0x59d016c9) 
cannot access class sun.nio.ch.DirectBuffer (in module java.base) because module java.base does not export 
sun.nio.ch to unnamed module @0x59d016c9

この問題は、Java 9で導入されたモジュールシステムに関連しています。Java 17では内部APIへのアクセス制限が強化され、Sparkが内部的に使用しているsun.nio.ch.DirectBufferクラスへのアクセスがデフォルトで禁止されているため発生します。

WARNING

公式ドキュメントではSparkがJava 17をサポートしていると記載されていますが、実際には追加のJVMオプション設定が必要です。

主要な解決方法

方法1: JVMオプションの追加(推奨)

Java 17でSparkを正常に動作させるには、必要なモジュールを開放するJVMオプションを追加する必要があります。

基本設定(最低限必要なオプション):

bash
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED

完全な設定(すべての互換性オプション):

bash
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
--add-opens=java.base/java.nio=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
--add-opens=java.base/sun.nio.cs=ALL-UNNAMED
--add-opens=java.base/sun.security.action=ALL-UNNAMED
--add-opens=java.base/sun.util.calendar=ALL-UNNAMED
--add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED

方法2: Sparkのバージョンアップ

Spark 3.3.2以降ではこの問題が部分的に改善されている場合があります:

xml
<!-- Maven設定 -->
<spark.version>3.5.0</spark.version>

INFO

Sparkの最新バージョンを使用することで、Java 17との互換性問題が解決している可能性があります。

環境別の設定方法

コマンドラインで実行する場合

bash
java \
    --add-opens=java.base/sun.nio.ch=ALL-UNNAMED \
    -jar your-spark-app.jar

Mavenプロジェクトの場合

pom.xmlに設定を追加:

xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>
            --add-opens=java.base/sun.nio.ch=ALL-UNNAMED
            <!-- その他の必要なオプション -->
        </argLine>
    </configuration>
</plugin>
xml
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED

Gradleプロジェクトの場合

build.gradleに設定を追加:

groovy
application {
    applicationDefaultJvmArgs = [
        "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
    ]
}
groovy
tasks.test {
    jvmArgs = [
        "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
    ]
}

IntelliJ IDEAで実行する場合

  1. 実行設定を開く
  2. 「VM options」フィールドに以下を追加:
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED

Docker環境の場合

Dockerfileに追加:

dockerfile
ENV JDK_JAVA_OPTIONS="--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"

VS Codeで実行する場合

launch.jsonに追加:

json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Main",
            "request": "launch",
            "mainClass": "com.spark.Main",
            "vmArgs": ["--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"]
        }
    ]
}

代替解決策

Java 11へのダウングレード

どうしても問題が解決できない場合は、Java 11を使用することを検討してください:

xml
<!-- ビルド設定例 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>

TIP

多くの運用環境では依然としてJava 11がサポートされているため、実用的な選択肢となりえます。

まとめ

Apache SparkをJava 17で実行する際の「cannot access class sun.nio.ch.DirectBuffer」エラーは、JVMのモジュールシステムに関する互換性問題です。以下のいずれかの方法で解決できます:

  1. JVMオプションの追加 - 最も一般的な解決方法
  2. Sparkのバージョンアップ - 長期的な解決策
  3. Java 11の使用 - 確実な代替案

環境に応じて適切な方法を選択し、Sparkアプリケーションを正常に実行してください。

DANGER

本番環境では、追加するJVMオプションがセキュリティポリシーと矛盾しないことを確認してください。特に金融機関や厳格なセキュリティ要件のある環境では、システム管理者と相談することが重要です。