kotlin 基礎 Part 11 -- Spring で マルチモジュールの Kotlin プロジェクトを作成する
Published: 2023-02-07 08:43:09

# IntelliJ が動くようにする。

---

## IntelliJ の DL

https://www.jetbrains.com/idea/download/#section=mac

公式サイトに行く。

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhqxgr6en2nwaoj0uhov.png)

macOS の コミュニティ エディションの　DMG ファイルを DL する。

---

## IntelliJ の起動

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8pnpguo277cz3edrq0z4.png)

IntelliJ が開けることを確認する。

---

## 便利プラグインを入れる

https://dev.to/kaede_io/intellij-chu-qi-she-ding-tocao-zuo-3003

この記事に書いた。

IdealVim など。

---
---










# Spring アプリが動くようにする

---

## Spring アプリの作成

https://start.spring.io/

このサイトで Springboot のアプリを作成する。

https://dev.to/kaede_io/kotlin-de-springboot-noapuriwozuo-cheng-siteqi-dong-suru-2a9l

前の記事を参考に作成

* Project: Gradle:Kotlin
* Language: Kotlin
* Springboot: 3.0.2
* Group: com.kaede
* Name, Artifact: kotlin1
* Java: 17
* Dependencies: Spring Web

これらの設定で作成する。

https://start.spring.io/#!type=gradle-project-kotlin&language=kotlin&platformVersion=3.0.2&packaging=jar&jvmVersion=17&groupId=com.kaede&artifactId=kotlin1&name=kotlin1&description=1st%20Project%20by%20kotlin%20in%20Mac&packageName=com.kaede.kotlin1&dependencies=web

このリンクから上記の設定で開ける。

これを DL する。

---

## IntelliJ で kotlin1 のプロジェクトを開く。

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6r3l8rc1gj3tqnazldn.png)

上記のプロジェクトを IntelliJ で開く。
しばらく待つと、実行可能になる。

---

## main から実行して Spring アプリが起動するのを確認

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0t7518l151fh8etk1itt.png)

実行すると Tomcat が 8080 で起動するのが見れる。
これで Spring アプリの起動は確認できた。

---

## Hello World を確認

```php
fun main(args: Array<String>) {
	runApplication<Kotlin1Application>(*args)
	println("Hello Kotlin1")

}
```

main に Hello World の文字列を入れる。

```php
2023-02-06T17:56:33.534+09:00  INFO 94815 --- 
[           main] 
com.kaede.kotlin1.Kotlin1ApplicationKt   : 
Started Kotlin1ApplicationKt in 3.191 seconds 
(process running for 3.77)
Hello Kotlin1
```

これで起動すると、Hello Kotlin1 の文字列がログとしてみれた。

----
----






# サブモジュール rest を作り、起点にする。

---

## rest モジュールを Java で作成

まず rest モジュールを kotlin1 のアプリに作成

左上の File から New -> Module を選ぶ。

- Name: rest
- Language: Java
- Bulid System: Gradle
- Gradle DSL: Kotlin
- parent: kotlin1

これらを指定してモジュールを作成。

すると　

```php
kotlin1/rest/src/main/java/com/kaede/Main.java
```

ここまで生成される。
この時に main/ には kotlin の言語空間は作成できない。

----

## rest モジュールで Kotlin が無効なことを確認

マルチモジュールにすると、そのままではサブモジュールで Kotlin を使用することができない。設定ファイルを書き換える必要がある。

まずはルートのプロジェクトから、main/ 下の kotlin/ をコピーする。

これを rest/src/main にコピーする。

java/ と違って kotlin/ は青色になっていない。
この段階では、言語フォルダとして認められていないからだ。
なので当然、main 関数は実行できない。

---

##　ルートの build.gradle.kts を変更

---

### springframework.boot の無効化

https://qiita.com/purini-to/items/6070c29ac4ed086e06be#main%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E7%84%A1%E3%81%84%E3%82%88%E3%81%A3%E3%81%A6%E6%80%92%E3%82%89%E3%82%8C%E3%82%8B

この記事を見るまでわからなくて何日も費やした。

```kotlin
plugins {
	//id("org.springframework.boot") version "3.0.2"
	id("io.spring.dependency-management") version "1.1.0"
	kotlin("jvm") version "1.7.22"
	kotlin("plugin.spring") version "1.7.22"
}
```

springframework.boot は無効化する。
サブプロジェクト ( rest ) で有効化する。
起点は rest だからだと解釈した。

----

### subprojects に plugin, dependences, tasks を移行する

subprojects というスコープを作る。
これで内部の設定を子供モジュールにも反映させられる。

これによって、kotlin が子供モジュールでも使えるようになると解釈。

```kotlin
subprojects {
	apply(plugin = "org.jetbrains.kotlin.jvm")
	apply(plugin = "io.spring.dependency-management")

	dependencies {
		implementation("org.springframework.boot:spring-boot-starter-web")
		implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
		implementation("org.jetbrains.kotlin:kotlin-reflect")
		implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
		testImplementation("org.springframework.boot:spring-boot-starter-test")
	}
	tasks.withType<KotlinCompile> {
		kotlinOptions {
			freeCompilerArgs = listOf("-Xjsr305=strict")
			jvmTarget = "17"
		}
	}
	tasks.withType<Test> {
		useJUnitPlatform()
	}
}
```

詳細としては

設定ファイルの前半にグローバルで書かれている

* kotlin.jvm
* spring.dependency-management

これらを 子供モジュール の内部で有効化している。

これで 子供モジュールでも kotlin や spring が使える。

また、dependencies としてグローバルに書いていた

- spring-boot-starter-web
- jackson-module-kotlin
- kotlin-reflect
- kotlin-stdlib-jdk8
- spring-boot-starter-test

これらも子供モジュールの中で使えるようになった。

tasks も jvm の実行のために必要、


----

## rest モジュールで kotlin が有効化されていることを確認

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdrxk1nxw39aujw1blub.png)

- 🟦 フォルダ名が青くなっている
- 🟩 main に実行可能を表す、緑三角が現れている

これにより、サブモジュールである rest モジュールで、Kotlin が有効化されていることを見れた。

---

## rest の main を叩いてみる

https://stackoverflow.com/questions/54543168/spring-tool-suite-configuration-class-may-not-be-final-remove-the-final-modif

```kotlin
open class MultiprojectApplication
```

サブモジュールでは main は open クラスじゃないとアプリケーションを起動できなかったので注意。

これを修正した上で、実際に　rest の　main を叩いてみる

```php
2023-02-07  INFO 99845 --- [main] 
com.kaede.kotlin1.RestApplicationKt : 
Started RestApplicationKt in 3.316 seconds 
(process running for 4.206)
Hello REST
```

rest を起点としてで Spring アプリが起動することを確認できた。

---

## 不必要なコードを消す

ルートの 
src/main/kotlin/ 以下は消す。使わないので。
src/test/kotlin/ も同時に消す。
テストだけ残すとビルドが落ちるので。

また、rest/src/main/java/ 以下も消す。
ビルド時にこっちが読み込まれる時があるので。

----

## ビルドして実行してみる

これができるまでかなり時間がかかった。

```php
./gradlew build                                  

BUILD SUCCESSFUL in 2s
9 actionable tasks: 9 up-to-date
```

コマンドでビルドして

```php
java -jar rest/build/libs/rest-0.0.1-SNAPSHOT.jar
```

スナップショット.jar を実行すると

```php
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.2)


main] com.kaede.MultiprojectApplicationKt      : 
Starting MultiprojectApplicationKt 
using Java 17.0.2 with PID 87742 (/Users/kaede0902/code/multiproject/rest/build/libs/
rest-0.0.1-SNAPSHOT.jar started by kaede0902 
in /Users/kaede0902/code/multiproject)

main] com.kaede.MultiprojectApplicationKt      : 
Started MultiprojectApplicationKt in 3.937 seconds 
(process running for 4.735)
```

無事にビルドされた jar ファイルから実行することができた。

これで Docker build して ECS コンテナで動かすことができるようになった。


---
---


# おまけ

----

## まだ API としては機能しないことを確認

```php
curl localhost:8080
{"timestamp":"2023-02-06T08:47:23.695+00:00","status":404,"error":"Not Found","path":"/"}
```

この段階で localhost 8080 を叩いても 404 しか返ってこない。

理由は GET MAPPING が設定されていないから。

なので、次は RestController を入れて、API として機能するようにする。

---

## RestController と GetMapping で API レスポンスを受け取るようにする

src/main/kotlin/com/kaede/

ここに先ほど作った RestApplication.kt がある。
これと並列に PersonResouce.kt を作成

```kotlin
@RestController
class PersonHandler {
    @GetMapping("/")
    fun root(): String {
        println("root accessed")
        return "Hello From PersonResource"
    }
}
```

ルートへのアクセスを受け取って、
Hello From PersonResource のレスポンスを返すようにする

---

## ルートへの curl で動作確認

```kotlin
kaede0902@rooter kotlin1 % curl localhost:8080/
Hello From PersonResource%  
```

ちゃんと帰ってきた。

これで Rest モジュールで API のエンドポイントが作れた。