【Mac M1環境】SpringbootアプリをNative Image化(IDEはIntelliJ)するのに、死ぬ程、苦労した話。

＜前回までの作業＞
さて、Springbootを使い、Webアプリケーションサーバを構築する事はできました。
「占いウェブアプリ」の構築手順はこちらです。
https://qiita.com/naiveprince0507/items/24a80b89c5e39ad9f6c7

＜今回のタスク＞
今回は、WebアプリケーションをNative Image化します。

＜作業概略と基本資料＞
これが本当に上手く行かずに、苦労しまくったので、何が問題なのか？ を記載します。

・本件全般に関する技術概要はこちら。
Springbootフレームワークと、そのアプリのNative　Image化手法
https://future-architect.github.io/articles/20210909a/

・ 作業の基本手順はこちら。
https://spring.pleiades.io/spring-boot/docs/current/reference/html/native-image.html

＜ちょっと説明＞
因みに、ネイティブイメージ化に関しては、上記サイトに詳述されております。
>GraalVM ネイティブイメージの導入
GraalVM ネイティブイメージは、Java アプリケーションをデプロイして実行する新しい方法を提供します。Java 仮想マシンと比較して、ネイティブイメージはより少ないメモリフットプリントで実行でき、はるかに高速な起動時間で実行できます。
これらは、コンテナー イメージを使用してデプロイされるアプリケーションに適しており、"Function as a service" (FaaS) プラットフォームと組み合わせると特に興味深いものになります。
JVM 用に作成された従来のアプリケーションとは異なり、GraalVM ネイティブイメージアプリケーションでは、実行可能ファイルを作成するために事前処理が必要です。この事前処理には、メインエントリポイントからアプリケーションコードを静的に分析することが含まれます。
GraalVM ネイティブイメージは、プラットフォーム固有の完全な実行可能ファイルです。ネイティブイメージを実行するために Java 仮想マシンを提供する必要はありません。
ビルド時に Spring が事前処理を実行し、GraalVM が使用できる追加のアセットを生成することが可能になります。

■ 問題点の整理
問題点1. Springbootプラグインの問題
SpringbootアプリをNative Image化する際に２つの方法があるのだが、実は、ここに罠がある。

>Spring Boot ネイティブイメージアプリケーションを構築するには、主に次の 2 つのメソッドがあります。
a) Cloud Native Buildpacks の Spring Boot サポートを使用して、ネイティブ実行可能ファイルを含む軽量コンテナーを生成します。
b) GraalVM ネイティブビルドツールを使用してネイティブ実行可能ファイルを生成します。

２つの方法の内、コンテナ化まで自動実行で作成してしまうのがa)の方法で、SpringbootアプリをJDKまで含めてネイティブイメージ化する（コンテナ化はしない）のが、b)の方法です。

当然、a)の方法の方が、ラクそうで良いのですが（NativeアプリをOS上で動かす事はあまり想定されず、最終的にはコンテナ上で動作させる事が大部分と思うので）、このCloud　Native Buildpacksは、Spring Initilizarのプラグインから、なぜか消えております。（2023年９月６日現在）。
尚、複数のネット情報からすると少し前には、Cloud Native Buildpacksのプラグインはあった筈なので、「なぜないんだ？」と探すのに、凄い時間が掛かった。

と言うわけで、現時点では、b)の方法しかありません。
尚、a)の方法では、ローカルPCにGraalVMがインストールされてなくても、Native Image化できます。（Dockerの機能でNative Image化を行う為。）　
しかし、b)の方法では、ローカルPC上にGraalVMがインストールされている必要があります。

GraalVMがインストールされている事をターミナル上確認します。
```
kanashimi_usr@kanashimi_usr-mac ~ % java -version
java version "17.0.6" 2023-01-17 LTS
Java(TM) SE Runtime Environment GraalVM CE 22.3.1 (build 17.0.6+9-LTS-jvmci-22.3-b11)
Java HotSpot(TM) 64-Bit Server VM GraalVM CE 22.3.1 (build 17.0.6+9-LTS-jvmci-22.3-b11, mixed mode, sharing)
kanashimi_usr@kanashimi_usr-mac ~ % 
```
無い場合は、ここから、無料でDLできます。（オープンソースです。）
https://www.graalvm.org/downloads/

問題点 2. IntelliJの問題
IDE(IntelliJ上での"GraalVM Native Support"のプラグインを入れるだけでOk。
これはとても簡単。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1665829/d8f82fd4-1c12-ad84-35ef-edbb288a57d7.png)

"GraalVM Native Support"プラグインをインストールしているので、"nativeCompile"コマンドの操作もIDE上に出てくる。よって、ここをRunすれば、Native Imageがビルドできる筈なのだが、IDE上で実行するとなぜかエラーが起きる。
![名称未設定3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1665829/9ccd6a05-b03a-be39-c783-36580996a896.png)
ビルド時に非常に多くのエラーが出て、Debuggingを一つずつ進めたのだが、これが本当に上手く行かない。
これで４日を潰した。そして、今も解決できていない。
ただ、非常に不思議なことに、IDE上ではなく、ターミナルを開いて、該当フォルダにて、"gradle nativeCompile"のコマンドを走らせると、ビルドできる。（これは、おそらくIntelliJの問題と思う。）
よって、Terminal上で、同コマンドを走らせます。

```
kanashimi_usr@kanashimi_usr-mac test0906 % gradle nativeCompile
```
![名称未設定4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1665829/795c76f0-5a8e-5bf5-e32d-0e2a7108a4bb.png)

ターミナル上で走らせたら、動いた！

問題点 3.　Webアプリ自体の問題。（私の技術力の問題）

冒頭で紹介した、「占いウェブアプリ」をNative Image化しようとするのですが、これは上手く、Native Image化できない。
Native　Image化に当たっては、アプリによって、微妙なチューニングが必要になることが多々あるので、今回も死ぬ程、「占いウェブアプリ」自体を書き直したりしたが、さまざまなパッチを当てたが、どうしてもNative　Image化できなかった。（これは、私自身の技術力の問題。）

■ 回避策
やりたい事は、Webアプリの開発ではなく、SpringbootアプリのNative Image化であるから、話を単純化して実行することにする。上記３つの問題点を回避する為に、結局、下記の設定ですることにした。
・　GraalVM　Native　Build　Toolsを使う。（Buildpackは使わない。無いから使えない。）
・ IDE(IntelliJ)の機能を使って、Nativeビルドしない。ターミナル上でビルドする。
・ 冒頭の「占いウェブアプリ」をNativeビルド化するのはとりあえず諦めて、超単純な、HelloWorld！をSpringbootで作り直して、それをビルドする。


■ 構築作業
と言うわけで実際の構築は下記。

１）まず、SpringIntializeで下記の様に設定。
Gradleを選び、PackagingはJar。
Dependencyは、SpringWebとGraalVM Native Supportのみ。
https://start.spring.io/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1665829/a5285ac4-5bcf-0f93-b6ed-b22c30673516.png)

2)HelloController.javaというクラスを作成し、下記の様に書く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1665829/09b19da0-f815-8ad3-5ad3-50ba762872ce.png)

コードはこれ。

```HelloController.java
package com.example.test0906;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/")
    public String index() {
        return "Greetings from Spring Boot!";
    }

}
```
3)IDE上ではなく、ターミナルを開いて、下記のコマンドを打ち込み、ビルドする。

```
kanashimi_usr@kanashimi_usr-mac test0906 % gradle nativeCompile
```
Buildが成功すると、build/native/nativeCompileのフォルダの下にNativeファイルが作成される。
![名称未設定5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1665829/c8285c3f-351b-bc4d-ffaa-25c7e9c2a425.jpeg)


４）　ターミナル上で、Runしてみる。
こんな感じ。

```
kanashimi_usr@kanashimi_usr-mac test0906 % build/native/nativeCompile/test0906
```

無事に表示されました！
```
kanashimi_usr@kanashimi_usr-mac ~ % curl -l localhost:8080
Greetings from Spring Boot!%  
```

苦節１週間の苦行でした！