ブログ

【SAP BTP Cloud Foundry】JavaをバージョンアップしたらRuntime指定にハマった話

この記事をSNSでシェア!

2026年10月15日

はじめに

過去に弊社で開発したSAP BTPアプリケーションでは、当時の標準的なバージョン指定として Java 17 を使用して開発が行われました。

その後、年月の経過に伴いJavaのサポート状況が更新され、この度 Java EOL(End of Life)に伴う対応が必要となりました。これを受け、利用するJavaバージョンを Java 17 から Java 25 へ引き上げる対応を行うこととなりました。

しかし、開発環境側で Java / Maven を Java 25 に変更してアプリケーションのビルドを行ったところ、デプロイ時に思わぬ問題が発生しました。

これを如何にして解消したか、SAP BTP Cloud Foundry 上で Java のバージョンアップを行う際の確認ポイントを通じて、次章より順を追って説明していきます。

問題発生までの経緯と原因の概要

現在、私たちのプロジェクトではローカル環境(VS Code)のほか、クラウド上の開発環境である BAS(SAP Business Application Studio) を使用しています。

今回は BAS 上に Java 25 環境をセットアップしていたため、ビルド(コンパイル)自体は Java 25 で問題なく成功し、成果物(jar)が生成されていました。そのため、そのまま Cloud Foundry(CF) にデプロイすれば正常に起動すると思っていました。

しかし、「ビルドを行う環境(BAS)」と「アプリを実行する環境(Cloud Foundry)」は別物です。実際に CF へデプロイしたところ、アプリケーションが起動せず crashed になりました。

今回の原因をひとことで言うと、以下の通りです。

Java 25 でビルドした成果物を、Cloud Foundry 上では Java 21 相当の Runtime で起動しようとしていた

ログを確認したところ UnsupportedClassVersionError が発生しており、class file version 69.0 と up to 65.0 の差分から、「ビルド時の Java バージョン」と「実行 Runtime」の不一致だと判断しました。

最終的には問題を解消できましたが、mta.yaml に Java 25 の指定を入れていても、実際に起動時に参照されている Runtime が想定通りとは限らず、切り分けに少しハマりました。

本記事では、Java のバージョンアップを行う際の確認ポイントとして、今回見たログや設定内容を備忘録としてまとめます。

発生したエラー

デプロイ後、アプリケーションは起動せず、cf app では以下のような状態になりました。

name:              <APP_NAME>
requested state:   started
buildpacks:        sap_java_buildpack_jakarta
instances:         0/2
state:             crashed

ログを確認すると、以下のエラーが出ていました。

java.lang.UnsupportedClassVersionError:
com/example/app/Main has been compiled by a more recent version of the Java Runtime
(class file version 69.0),
this version of the Java Runtime only recognizes class file versions up to 65.0

このエラーのポイントは、以下の2つです。

class file version 69.0
this version of the Java Runtime only recognizes class file versions up to 65.0

class file version 69.0 は Java 25 でコンパイルされた class を示します。
一方、up to 65.0 は Java 21 相当の Runtime までしか認識できない状態を示します。Oracle の JVM 仕様でも Java SE 25 が class file major version 69 までを扱うことが示されています。

つまり、今回の状態は以下でした。

ビルド成果物: Java 25 相当
CF上の実行Runtime: Java 21 相当

そのため、Java 25 で作られた jar を、Java 21 の Runtime で起動しようとして失敗していました。

なぜ今まで失敗しなかったのか

今回対応する前は、アプリケーションは Java 17 でビルドされていました。

そのため、仮に Cloud Foundry 上の Runtime が Java 21 相当だったとしても、Java 17 でコンパイルされた class は読み込めていたと考えられます。

整理すると、以下のようになります。

これまで:
ビルド成果物: Java 17 相当
CF上のRuntime: Java 21 相当
→ 起動できる(Java 21 Runtime は Java 17 の class を読み込めるため)

今回:
ビルド成果物: Java 25 相当
CF上のRuntime: Java 21 相当
→ Java 25 の class を読めず起動失敗(Java 21 Runtime は Java 25 の class を読み込めないため)

つまり、今回初めて ビルド成果物の Java バージョンが、CF上の実行Runtimeを上回った ことで問題が顕在化しました。

mta.yamlでJava 25を指定した

最初に、mta.yaml の Java モジュールに以下を指定しました。

JBP_CONFIG_SAP_MACHINE_JRE: '{ version: "25.+" }'

対象の Java モジュールは複数あったため、同じ指定が複数箇所に入っていました。

例です。

- name: <JAVA_APP_MODULE>
  type: java
  path: <JAVA_APP_PATH>
  properties:
    JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
    JBP_CONFIG_SAP_MACHINE_JRE: '{ version: "25.+" }'
    LOG_ROOT_LEVEL: "INFO"
  parameters:
    buildpack: sap_java_buildpack_jakarta
    stack: cflinuxfs4

デプロイ後、cf env でも設定自体は反映されていました。

cf env <APP_NAME> | grep -E "JBP_CONFIG|SAP_MACHINE|JRE|JAVA"

結果として、以下のように 25.+ が確認できました。

JBP_CONFIG_SAP_MACHINE_JRE: { version: "25.+" }

それでもRuntimeが切り替わらなかった

しかし、cf restage 後も同じ UnsupportedClassVersionError が発生しました。

cf restage <APP_NAME>

再度ログを確認しても、以下の状態は変わりませんでした。

class file version 69.0
this version of the Java Runtime only recognizes class file versions up to 65.0

つまり、JBP_CONFIG_SAP_MACHINE_JRE は環境変数として反映されているものの、実際の起動Runtimeは Java 25 になっていないように見えました。

ここで cf env をもう少し見ると、AppMain に以下のような指定がありました。

JRE_HOME="META-INF/.sap_java_buildpack/sap_machine_jdk"
JAVA_HOME="META-INF/.sap_java_buildpack/sap_machine_jdk"

また、mta.yaml では以下のように SAPMachineJDK を指定していました。

JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"

このため、JRE側の指定だけではなく、JDK側の指定も必要なのではないか、という仮説を立てました。

SAP Help でも、SapMachine を使う場合の設定として JBP_CONFIG_SAP_MACHINE_[JRE|JDK] という指定に触れられています。

追加で確認した設定

今回の構成では SAPMachineJDK を使っているように見えたため、以下の指定を追加する方針にしました。

JBP_CONFIG_SAP_MACHINE_JDK: '{ version: "25.+" }'

既存の JBP_CONFIG_SAP_MACHINE_JRE は消さず、同じ箇所に追加します。

JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
JBP_CONFIG_SAP_MACHINE_JRE: '{ version: "25.+" }'
JBP_CONFIG_SAP_MACHINE_JDK: '{ version: "25.+" }'
LOG_ROOT_LEVEL: "INFO"

複数の Java モジュールがある場合は、同じように各モジュールへ追加します。

- name: <JAVA_APP_MODULE>
  type: java
    properties:
        JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"
        JBP_CONFIG_SAP_MACHINE_JRE: '{ version: "25.+" }'
        JBP_CONFIG_SAP_MACHINE_JDK: '{ version: "25.+" }'

変更後は、再デプロイまたは環境変数反映後に restage します。

cf restage <APP_NAME>

その後、ログで実際にどの Runtime が使われているか確認します。

cf logs <APP_NAME> --recent | grep -Ei "SAPMachine|JDK|JRE|Java|version|UnsupportedClassVersionError|class file"

今回のポイント

今回のポイントは、mta.yaml に Java 25 を指定したつもりでも、実際に Cloud Foundry 上でどの Runtime が使われているかはログで確認する必要がある という点です。

UnsupportedClassVersionError 自体は SAP BTP 固有ではなく、Java 全体で起こりうるエラーです。今回の記事では、その Java 一般のエラーを、SAP BTP Cloud Foundry 上で Buildpack が選択する Runtime や mta.yaml の指定内容を確認しながら、どのように切り分けたかをまとめています。

特に以下のような構成では注意が必要でした。

JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jdk.SAPMachineJDK']"

このように JDK コンポーネントを明示している場合、JBP_CONFIG_SAP_MACHINE_JRE だけでは期待通りに効かない可能性があります。

また、cf env で設定値が見えていることと、実際にアプリ起動時にその Runtime が使われていることは別です。

確認すべきポイントは以下です。

cf env <APP_NAME>
cf app <APP_NAME>
cf restage <APP_NAME>
cf logs <APP_NAME> --recent

まとめ

Java のバージョンアップでは、ローカルや BAS 側の Java バージョンだけでなく、Cloud Foundry 上で Buildpack が選択する Runtime も揃える必要があります。

今回の事象は、以下の流れで発生しました。

項目内容
ビルド環境BAS 側を Java 25 に変更
成果物Java 25 でビルドされた jar を作成
CF 側の指定JBP_CONFIG_SAP_MACHINE_JRE で Java 25 を指定
実際の起動 RuntimeJava 21 相当のまま
発生したエラーJava 25 の class を Java 21 Runtime で読めず、UnsupportedClassVersionError が発生
追加で確認した点JDK コンポーネントを使用している構成だったため、JDK 側の Runtime 指定も確認対象になった

つまり、BAS 側では Java 25 の成果物を作成できていましたが、Cloud Foundry 上では Java 21 相当の Runtime で起動しようとしていたため、アプリケーションが起動できませんでした。

UnsupportedClassVersionError が出た場合は、まず以下の2点を見ると原因を切り分けやすいです。

class file version xx.x
this version of the Java Runtime only recognizes class file versions up to yy.y

この2つを見ることで、ビルド成果物のJavaバージョン と 実行RuntimeのJavaバージョン のズレを判断できます。

SAP BTP Cloud Foundryのような環境はデプロイが簡単な反面、裏で動いているBuildpackの仕様(今回はJDKとJREの指定の違い)を正しく理解していないと、思わぬ落とし穴にハマることを痛感しました。
ただ、今回のトラブルシューティングを通して、cf envやcf restageなどのCLIコマンドを使った原因切り分けの引き出しが増えたのは大きな収穫です。今後は設定ファイル(mta.yaml)を書き換えただけで満足せず、「実際の稼働環境で何が動いているか」をcf logs等で最後まで疑って確認する習慣を付けるきっかけになったと感じています。
今回の備忘録が、同じようにJavaのバージョンアップで頭を抱えている方の助けになれば嬉しいです!

投稿者プロフィール

野口 唯
野口 唯
Javaバックエンドエンジニアを経てSAP BTP関連の修行中。失敗から学ぶ記事を書きます。
この記事をSNSでシェア!