Google App Engine for Java21 の開発環境をEclipseで構築する

# はじめに

# 前提条件
Google App Engine for Java で既にプロジェクトの作成は終わっているとします。
プロジェクトの作成が終わってない人は以下のサイトを参考に作成しておいてください。
https://cloud.google.com/appengine/docs/standard/java-gen2/building-app/creating-project?hl=ja

以下の設定でプロジェクトを作成したと仮定します。
* project ID：sample
* service：default
* site URL：https://sample.appspot.com

# ハードウェア環境
* OS：Windows11 23H2
* CPU：Intel(R) Core(TM) i5-4260U CPU @ 1.40GHz   2.00 GHz
* メモリ：4.00GB
* SSD：【Ｃドライブ】431GB／【Ｄドライブ】33.5GB

※開発環境はＤドライブに構築します。
ちなみに[Macbook AirのSSDを換装してWindows11をインストールする](https://qiita.com/kazuki1600/items/c2fa6474d048a00847f7)で構築したMacbook Airです。

# やること
[1.Google Cloud CLI をインストールする](#1google-cloud-cli-をインストールする)
[2.Eclipse をダウンロードする](#2eclipse-をダウンロードする)
[3.JDK21 をダウンロードする](#3jdk21-をダウンロードする)
[4.フォルダを構成する](#4フォルダを構成する)
[5.Eclipse の起動](#5eclipse-の起動)
[6.Mavenプロジェクトの作成](#6mavenプロジェクトの作成)
[7.確認事項](#7確認事項)
[8.Google App Engine for Java へのデプロイ](#8google-app-engine-for-java-へのデプロイ)

# 1.Google Cloud CLI をインストールする
https://cloud.google.com/sdk/docs/install?hl=ja
Windows版の「Google Cloud CLI インストーラ」をダウンロードしてインストールします。
基本的には[次へ]で進めていけばいいですが、
![スクリーンショット 2024-10-16 191726.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/b94e7bba-4acc-966a-a615-2846fe0498d7.png)
私は「All users」でインストールしました。
「Single User」にすると失敗する訳では無いです。

インストールが完了すると自動で「gcloud init」が実行されますので、プロジェクトの管理者アカウントでログインして、「sample」プロジェクトを選択してください。

:::note alert
既に「gcloud CLI」がインストールされていて再インストールをする場合は、
アンインストーラでアンインストールした後に
C:\Users\[user name]\AppData\Local\ 配下にある
[ct4j-cloud-sdk]フォルダをフォルダごと手作業で削除してください。
これが残っているとDeployが失敗することがあります。
:::

# 2.Eclipse をダウンロードする
https://www.eclipse.org/downloads/packages/
上記サイトから Eclipse IDE 2024-09 R Packages をダウンロードします。
![スクリーンショット 2024-10-10 213934.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/8cdbf7f3-bd61-2476-0fc3-82032b74a3dd.png)
Windows版の Eclipse IDE for Java Developers を選択します。
zipファイルがダウンロードされるので展開してください。
※必要に応じて Eclipse IDE for Enterprise Java and Web Developers を選択しても問題ありません。

# 3.JDK21 をダウンロードする
https://www.oracle.com/jp/java/technologies/downloads/#java21
上記サイトから JDK21 をダウンロードします。
![スクリーンショット 2024-10-10 214108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/ee325542-35b4-ba1e-657d-014b20febeab.png)
Windows版の x64 Compressed Archive を選択します。 
zipファイルがダウンロードされるので展開してください。

# 4.フォルダを構成する
例としてＤドライブ直下に[eclipse2024-09]フォルダを作成し、その配下にダウンロードしたEclipseとJDKのフォルダを配置します
※相対パスで構築するのでどこに[eclipse2024-09]フォルダを構築しても問題ないです。
```text:Ｄドライブ
D:\
└─eclipse2024-09  <= 新規作成
  ├─eclipse\
  │  .eclipseproduct
  │  artifacts.xml
  │  eclipse.exe
  │  eclipse.ini   <= 編集します
  │  eclipsec.exe
  │  ├─configuration\
  │  ├─dropins\
  │  ├─features\
  │  ├─p2\
  │  ├─plugins\
  │  └─readme\
  │
  ├─jdk-21.0.4\    <= バージョンによって異なる
  │  ├─bin\
  │  ├─conf\
  │  ├─include\
  │  ├─jmods\
  │  ├─legal\
  │  └─lib\
  │
  └─workspace\     <= 新規作成
```
[eclipse]フォルダにある「eclipse.ini」に次の４行を追記します。
追記場所は最後行に追加すればよいです。
```eclipse.ini に追記
../jdk-21.0.4/bin

-Dswt.enable.autoScale=true
-Dswt.autoScale=100
-Dswt.autoScale.method=smooth
```
「../jdk-21.0.4/bin」はバージョンに合わせて変更してください。
```text:[eclipse2024-09]フォルダ
  ├─jdk-21.0.4\
  │  ├─bin\
```
への相対パスを記載しています。
「-Dswt.autoScale=100」はお使いのパソコンの解像度に合わせて設定してください。
高解像度のディスプレイの場合、eclipseのボタンが小さくて操作しにくい場合は、
「-Dswt.autoScale=150」のように設定すればよいです。

# 5.Eclipse の起動
「eclipse.exe」をダブルクリックしてEclipseを起動してください。
![スクリーンショット 2024-10-10 215433.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/81425e6e-ddfa-881a-0f0e-5c2beb164007.png)
workspaceは相対パスで指定します。
```
../workspace
```
[Launch]ボタンを押下すると次の警告が表示されることがあります。
![スクリーンショット 2024-10-10 215924.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/0b5e5fb6-662d-e81d-95e5-93b91ea0a99d.png)

:::note warn
Eclipseの起動時に、「Windows Defender 除外チェック」が表示された場合は、Eclipseの起動時に読み込むファイルがセキュリティソフトのWindows Defenderにウイルスチェックされている状態となっています。

このため、起動やプログラムの実行時にチェックの時間がかかってしまい、Eclipseの動作が重くなることが想定されますので、Eclipseと関連するファイルを対象外とすることができます。
利用されているコンピューターのスペックが低い場合などは、除外することをご検討ください。

但しこの場合、悪意のあるプログラムがあった場合も実行が可能となる場合がありますので、特にインターネットなど外部から取得したソースの実行には注意するようにしてください。
（設定は、Eclipseの設定画面であとから変更することも可能です）
:::

:::note info
相対パスで構築しているので [eclipse2024-09] フォルダをＤドライブ以外の場所に異動してもEclipseは起動するはずです。
:::

# 6.Mavenプロジェクトの作成
![スクリーンショット 2024-10-16 145612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/1d8f7630-8cf3-dba3-40b1-7700f887d972.png)
[File]-[New]-[Maven Project]を選択する

![スクリーンショット 2024-10-16 145657.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/bfe6c878-d641-d7a0-9ba6-cdfac8243c2a.png)
[Next >]ボタンを押下する

![スクリーンショット 2024-10-16 145812.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/987fc5c4-675d-6beb-b907-2cc40193df31.png)
* Catalog: Maven Central
* Filter: google
* Artifact Id: appengine-standard-archetype

[Next >]ボタンを押下する

![スクリーンショット 2024-10-21 201948.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/0c92aeda-d690-6db3-4169-221b34aa7805.png)
+ Group Id: com.appspot.sample
+ Artifact Id: default
+ Package: com.appspot.sample.controller
+ Properties available from archetype: 全て削除

準備ができたら[Finish]ボタンを押下すると構築が始まります。
途中EclipseのConsoleに以下の問い合わせが出ます。
```text
Define value for property 'appengine-version' ${appengine.sdk.version}:
```
とりえず「2.0.29」と入力して[Enter]キーを押下してください。次に
```text
groupId: com.appspot.sample
artifactId: default
version: 0.0.1-SNAPSHOT
package: com.appspot.sample.default
 Y:
```
と聞いていますので、「y」と入力して[Enter]キーを押下してください。
しばらく待つと次のような構成でMavenプロジェクトが構築されます。
```text
default
│  .classpath
│  .project
│  nbactions.xml
│  README.md
│  pom.xml   <= 編集する
│  
├─.settings
│      
├─src
│  ├─main
│  │  ├─appengine
│  │  │      app.yaml   <= 新規で作成（ダミーファイル）
│  │  │      
│  │  ├─java
│  │  │  └─com
│  │  │      └─appspot
│  │  │          └─sample
│  │  │              └─controller
│  │  │                  └─HelloAppEngine.java   <= ※1
│  │  ├─resources
│  │  └─webapp
│  │      │  
│  │      └─WEB-INF
│  │              appengine-web.xml   <= 編集する
│  │              web.xml             <= 編集する
│  │              logging.properties
│  │              
│  └─test
│      ├─java
│      │  └─com
│      │      └─appspot
│      │          └─sample
│      │              └─controller
│      │                  └─HelloAppEngineTest.java <= ※1
│      └─resources
└─target
```
※1：javax.servlet.* から jakarta.servlet.* に変更します。
参考：https://cloud.google.com/appengine/docs/standard/java-gen2/upgrade-java-runtime?hl=ja

続いて必要な設定を行っていきます。

## 6-1.pom.xml の編集

自動生成されたpom.xmlは一旦全部削除して、以下に置き換えます。
プロジェクトIDは、Google App Engineで構築したアプリケーションに合わせて編集してください。
デプロイバージョンは、ご自身の管理しやすい名前に編集してください。
AppEngine API 1.0 SDK のバージョンは、
https://mvnrepository.com/artifact/com.google.appengine/appengine-api-1.0-sdk
Maven Repositoryサイトから最新バージョンをご確認ください。
```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>

  <groupId>com.appspot.sample</groupId>
  <artifactId>default</artifactId>

  <properties>
    <!-- uncomment if you wish to set your project here project- gcloud is used otherwise -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
    <archiveClasses>true</archiveClasses>
    <app.deploy.projectId>sample</app.deploy.projectId>	<!-- プロジェクトID -->
    <app.deploy.version>ver1.0</app.deploy.version>     <!-- デプロイバージョン -->
    <app.deploy.promote>false</app.deploy.promote>		<!-- デプロイ後に直接反映しない -->
    <appengine.version>2.0.29</appengine.version>		<!-- AppEngine API 1.0 SDK -->
  </properties>

  <prerequisites>
    <maven>3.5</maven>
  </prerequisites>

  <dependencies>
    <!-- Compile/runtime dependencies -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-1.0-sdk</artifactId>
      <version>${appengine.version}</version>
    </dependency>
	<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
	<dependency>
	    <groupId>jakarta.servlet</groupId>
	    <artifactId>jakarta.servlet-api</artifactId>
	    <version>6.1.0</version>
	    <scope>provided</scope>
	</dependency>
	<!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp/jakarta.servlet.jsp-api -->
	<dependency>
	    <groupId>jakarta.servlet.jsp</groupId>
	    <artifactId>jakarta.servlet.jsp-api</artifactId>
	    <version>4.0.0</version>
	    <scope>provided</scope>
	</dependency>
 
    <!-- Test Dependencies -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-testing</artifactId>
      <version>${appengine.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-stubs</artifactId>
      <version>${appengine.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-tools-sdk</artifactId>
      <version>${appengine.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.google.truth</groupId>
      <artifactId>truth</artifactId>
      <version>0.33</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.10.19</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <!-- for hot reload of the web application-->
    <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
    <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.3.1</version>
			</plugin>
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.4.4</version>
        <configuration>
    	    <projectId>${app.deploy.projectId}</projectId>
    	    <version>${app.deploy.version}</version>
    	    <promote>${app.deploy.promote}</promote>
        </configuration>
      </plugin>
            
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>3.0.0-M3</version>
        <executions>
          <execution>
            <id>enforce-maven</id>
            <goals>
                <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <!-- appengine-maven-plugin requires Maven 3.5.0 or later -->
                <requireMavenVersion>
                  <version>3.5.0</version>
                </requireMavenVersion>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

 </project>
```

## 6-2.app.yml の作成
![スクリーンショット 2024-10-16 153208.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/adec529e-95ca-b7d8-0d6c-900b8d731d21.png)
[main]フォルダ配下に[appengine]フォルダを作成します。
次に[appengine]フォルダ配下に「app.yaml」を作成します。
ファイルの中は空でも大丈夫です。何か記載する時はエンコードを「UTF-8」にしてください。
私は、ファイルの中に以下を記載していますが意味はありません。
```text:app.yaml
# ダミーファイル
# スタンダード環境では、appengine-web.xmlを利用する
# appengine-web.xmlが存在する場合は、app.yamlは無視される
# appengine-web.xmlを元に自動でapp.yamlが生成される
```

## 6-3.appengine-web.xml の編集
Javaランタイムの指定をJava21にします。
```xml
<runtime>java21</runtime>
```
あとはお好みで設定してください。
参考までに Google App Engine を無料で運用する設定を掲載しておきます。

```xml:appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <runtime>java21</runtime>
  <app-engine-apis>true</app-engine-apis>
  <threadsafe>true</threadsafe>
  <sessions-enabled>false</sessions-enabled>

  <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
  </system-properties>

  <instance-class>F1</instance-class>
  <automatic-scaling>
    <min-instances>0</min-instances>
    <max-instances>1</max-instances>
    <target-cpu-utilization>0.5</target-cpu-utilization>
    <target-throughput-utilization>0.6</target-throughput-utilization>
    <max-concurrent-requests>10</max-concurrent-requests>
    <min-pending-latency>300ms</min-pending-latency>
  </automatic-scaling>

</appengine-web-app>
```

## 6-4.web.xml の編集
https://cloud.google.com/appengine/docs/standard/java-gen2/upgrade-java-runtime?hl=ja
に従いweb.xmlを変更します。
「EE10 で Java 21 にアップグレードする」の項目になります。
```xml:web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="https://jakarta.ee/xml/ns/jakartaee" 
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0">

  <welcome-file-list>
    <welcome-file>default.html</welcome-file>
  </welcome-file-list>
  
  <error-page>
    <error-code>404</error-code>
    <location>/404.html</location>
  </error-page>

  <security-constraint>
	<web-resource-collection>
		<web-resource-name>Ssl</web-resource-name>
		<url-pattern>/*</url-pattern>
	</web-resource-collection>
	<user-data-constraint>
		<transport-guarantee>CONFIDENTIAL</transport-guarantee>
	</user-data-constraint>
  </security-constraint>
	
</web-app>
```

# 7.確認事項
ここまで設定できたらエラーが出ていないか確認をしていきます。
![スクリーンショット 2024-12-23 151808.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/1289d1d8-4405-4bc1-5d0b-19deb2cc211a.png)
ここらで１回 Projectの「Clean」と「Update Maven Project」を実行しておきましょう。

次にProject[default]を右クリック [Properties]をクリック
[Java Buld Path]を選択
![スクリーンショット 2024-10-16 152044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/16dabbc0-70e3-9cff-a2a7-99c572c9406e.png) 
JRE System Library [JavaSE-21] になっていることを確認
次に[Java Compiler]をクリック
![スクリーンショット 2024-10-16 152106.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/0038be5c-37c2-2d42-6c93-f86ba9382f27.png)
Use compliance from execution environment 'JavaSE-21' on the 'Java Build Path' にチェックする
* Compiler compliance level: 21

になっていることを確認する

# 8.Google App Engine for Java へのデプロイ
いよいよGAEへデプロイです。

![スクリーンショット 2024-12-23 153106.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/51a42dae-e4bf-e257-322e-6671a79bed15.png)
1. Project[default]を右クリック [Run As]をクリック
2. [Run Configurations...]をクリック

![スクリーンショット 2024-10-16 153408.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/9bc7af77-60b6-32e2-8b48-f10af7e8c86b.png)
* Name：次からはこの名前で実行できます
* Goals：clean package appengine:deploy

[Run]ボタンを押下するとDeployが実行されます。

```text
Your current Google Cloud CLI version is: 497.0.0
Installing components from version: 497.0.0
```
途中で「Google Cloud CLI」のバージョン確認があります。
最新版でない場合は、自動で最新版に更新されます。この場合、Deployが開始されるまで数分待ちが発生しますので気長に待ちましょう。

```text
[INFO] GCLOUD: File upload done.
[INFO] GCLOUD: Updating service [default]...
[INFO] GCLOUD: .....................done.
[INFO] GCLOUD: Deployed service [default] to [https://Ver1.0-dot-sample.appspot.com]
[INFO] GCLOUD: 
[INFO] GCLOUD: You can stream logs from the command line by running:
[INFO] GCLOUD:   $ gcloud app logs tail -s default
[INFO] GCLOUD: 
[INFO] GCLOUD: To view your application in the web browser run:
[INFO] GCLOUD:   $ gcloud app browse
[INFO] -----------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------------------
[INFO] Total time:  01:39 min
[INFO] Finished at: 2024-12-23T15:36:48+09:00
[INFO] -----------------------------------------------------------------------
```
最後はこんな感じでFinishedして終わります。
https://console.cloud.google.com/appengine
管理コンソールを確認して正常にブラウザで表示されるか確認してみてください。

# Appendix

# 付録1.外部JARの登録方法
Maven Projectで外部JAR を登録するにはローカルリポジトリ（通常は C:\Users\[ユーザ名]\.m2\repository） にインストールする必要があります。

例として D:\sample.jar に外部JARファイルを保管したと仮定します。

#### Mavenをインストールしている場合
コマンドプロンプトから mvn コマンドを実行してください。
```text:mvn コマンド
mvn install:install-file -Dfile=D:\sample.jar -DgroupId=[groupId名] -DartifactId=[artifactId名] -Dversion=[version名] -Dpackaging=jar
```
#### Mavenをインストールしていない場合
[8.Google App Engine for Java へのデプロイ](#8google-app-engine-for-java-へのデプロイ)に記載している手順で「Edit Configuration」を起動します。
1. Project[default]を右クリック [Run As]をクリック
2. [Run Configurations...]をクリック

Goals：に以下のコマンドを入力して[Run]ボタンを押下するとmvnコマンドが実行されます。
```text:Goals
install:install-file -Dfile=D:\sample.jar -DgroupId=[groupId名] -DartifactId=[artifactId名] -Dversion=[version名] -Dpackaging=jar
```

ローカルリポジトリにインストールした後に pom.xml にリポジトリを追記します。
```xml:pom.xml
<dependencies>
・・・・
    <dependency>
        <groupId>[groupId名]</groupId>
        <artifactId>[artifactId名]</artifactId>
        <version>[version名]</version>
    </dependency>
</dependencies>
```

ここらで１回 Projectの「Clean」と「Update Maven Project」を実行しておきましょう。

# 付録2.Firestore Datastoreモードの権限設定
Firestore Datastoreモードを利用するにはIAMを設定する必要があります。
管理コンソールから「IAM と 管理」の画面を開く

![スクリーンショット 2025-01-12 104316.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/b407a8de-7c6e-a09b-89bb-e6b04545127d.png)

+ プリンシパル：[プロジェクトID]@appspot.gserviceaccount.com
+ 名前：App Engine default service account
+ ロール：編集者

の「ロール」を追加します。

![スクリーンショット 2025-01-12 104341.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/4e942f29-9e8c-ec75-afb6-4a6ae12b54ef.png)

![スクリーンショット 2025-01-12 104419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/335be715-ef12-4258-6582-f5ef47ae4206.png)

+ ロール：Cloud Datastore ユーザー

を選択して[保存]ボタンを押下する。

![スクリーンショット 2025-01-12 104438.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197306/8d0ce7b3-ddf7-a108-bef6-8cb23ccaf383.png)


+ プリンシパル：[プロジェクトID]@appspot.gserviceaccount.com
+ 名前：App Engine default service account
+ ロール：Cloud Datastore ユーザー

が追加されていることを確認する。
※[編集者]権限は削除しないように注意してください。
　削除するとデプロイでエラーが発生します。

## 以上