JavaFX含みのjavaのEclipseプロジェクトをKotlinのIntelliJプロジェクトに移行してみる

# この記事に関して

最近、Kotlinを座学で勉強しています。今までの自分の経験から、自分の性質では、自分で何か作らないと身につかないです。そこで、[最近投稿してるシリーズ](https://qiita.com/silverbox/items/4e4a76cba9337aba45fc)のJavaFXによるDynamoDBツールをKotlinに移植してみようと思いました。
まだまだ機能追加予定なので、今後はKotlinでの機能追加したいという考えです。

目的は違えど同じような事をする人はいるかと思いますので、その人達の参考の一つになれば幸いです。

※そんな感じで勉強している最中で、今の自分はKotlinマスターではないです。こちらの記事で間違っている部分や考慮不足がある可能性があります。その点ご注意ください。

# JavaをKotlinに変換する方法の考察

IntelliJやAndroidStudioでは標準で変換機能がついている様です。自分も[別記事](https://qiita.com/silverbox/items/1b514f80a7bbbef8ba9f)でやりましたが、AndroidStudioもIntellijの派生らしいです。そんな機能がついているぐらいだから独立してツール化したものがあってよさそうですが、自分はそんなツールを見つける事が出来ませんでした。検索しても大体IntelliJの機能を使っていたり、AndroidStudioでの話でした。
この状況から判断すると、IntelliJを使わなければならない事になります。現在、対象プロジェクトがEclipseなので、これをIntelliJのプロジェクトに変換する必要があります。

# EclipseプロジェクトをIntelliJプロジェクトに変換する

公式ページ、[「Eclipse から IntelliJ IDEA に移行する」](https://pleiades.io/help/idea/migrating-from-eclipse-to-intellij-idea.html#migratingEclipseProject)にその必要が無い事が書いてありました。mvnプロジェクト作る時、`mvn eclipse:eclipse`とかやってたので、IntelliJ専用のコマンドがあるとか思ってましたが、そうでもなさそうです。pom.xmlさえあれば普通にImport出来そうです。

## Importしてみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530376/045e3456-59c6-6755-875d-f6adc0ef0221.png)

`Open`を選択すると、プロジェクトのフォルダを選択する画面になる。そこで対象フォルダを選択すると以下画面が出てきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530376/5ad9fc78-0ae8-17d6-6650-4411d39e62c2.png)

もしかしたら自分が今まで勘違いしていたのかもしれません。`Eclipse project`と`Maven project`が別物だったっぽいですね。EclipseでMavenプロジェクトを開発していると思っていましたが、`mvn eclipse:eclipse`でpom.xmlを元にEclipseプロジェクトを作っていたという事だったのですね。だからpom.xmlを修正する度にこのコマンドが必要だった、という事ですね。（認識間違っていたらすいません）

で、今回はEclipseからの脱却を目指すという意味でも`Maven project`を選んでみます。

## ビルドしてみる

まだjavaですが、一旦ビルドします。`Build` → `Build project`を実行したら設定が無いと言われたので、新設に表示されたリンクから設定ページを開き、存在していたjava1.8を選択。出力フォルダも適当に設定します。ビルドは成功し、targetフォルダ配下に出力されていました（さっき設定した出力フォルダじゃなかった）。

## jar出力してみる

[Intellij IDEAで実行可能なjarを作る方法](https://qiita.com/nwtgck/items/7a61c5bb9d5b2d266cfe)を参考に、jarを出力してみます。こちらの記事のトレースなので特に書く事は無いのですが、ちゃんとjarが出力され、実行も出来ました。

## gitにアップ

ここまででEclipseプロジェクトをIntelliJプロジェクトに変換できたと思うので、gitにアップしようと思います。しかし、なんか中間生成ファイルが大量に発生し、`.gitignore`の対応が必須と思われます。[GithubGistにあったサンプル](https://gist.github.com/lordofthelake/5833336)を参考に、`.gitignore`を編集します

# javaからKotlinへ一括変換する

ここまでくれば後はIntelliJの機能を使って一括変換できるはずです。

[JavaからKotlinに変換する7つのテクニック Kotlinらしさを生かした簡潔なコードに置き換えよう ](https://eh-career.com/engineerhub/entry/2019/05/14/103000)を参考に、「メニューバーの「Code」→「Convert Java File to Kotlin File」メニュー」を実行します。
ここで、ファイルを選択していると対象ファイルだけKotlinになってしまうので、srcフォルダを選択して実行した方がよさそうです。

# エラー部分を修正する

結構エラーが出てる状態です。データクラスとか依存が少ないクラスから修正していこうと思います。

## まずはimport宣言の修正

どうやら、他クラスの内部クラスも宣言してしまいエラーになってる様なので、削除します。また、全ソースにプロジェクトで使ってるimportが全て記載されてしまっているみたいなので、使ってるもの以外削除します。

## Lombockのgetter/setter対応

どうやらLombockアノテーションで提供されるgetter/setterメソッドが使えずに出てるエラーが沢山。
[javaからkotlin変換の色々メモ](https://qiita.com/hibinohirokatsu/items/975918efc1c4579303e2)によるとlombockは使えない模様です。

```Kotlin:修正前（Kotlinへ自動変換直後）
package com.silverboxsoft.dynamodbtool.classes

import lombok.Data

@Data
class DynamoDbColumn {
    private val columnName: String? = null
    private val columnType: DynamoDbColumnType? = null
}
```

単純置き換えだと下のような感じになると思います。

```Kotlin:単純修正後
package com.silverboxsoft.dynamodbtool.classes

import lombok.Data

@Data
class DynamoDbColumn {
    private var columnName: String? = null
    private var columnType: DynamoDbColumnType? = null
    fun getColumnName(): String? {
        return columnName
    }
    fun getColumnType(): DynamoDbColumnType? {
        return columnType
    }
    fun setColumnName(name: String) {
        this.columnName = name
    }
    fun setColumnType(type: DynamoDbColumnType) {
        this.columnType = type
    }
}
```

せっかくKotlin化をしようとしているので、nullを許可しない形に修正します。

```Kotlin:?を外した形
package com.silverboxsoft.dynamodbtool.classes

import lombok.Data

@Data
class DynamoDbColumn(columnNamePrm: String, columnType: DynamoDbColumnType) {
    private val columnName: String = columnNamePrm
    private val columnType: DynamoDbColumnType = columnType
    fun getColumnName(): String {
        return columnName
    }
    fun getColumnType(): DynamoDbColumnType {
        return columnType
    }
}
```

当然連鎖反応的にこれを使用している部分を修正していきます。関連する`?`を取る事が出来ました。
ここまで修正した後に色々Kotlinのページを見ていると、Kotlinは特getter/setterを設けずに、変数に直接アクセスするのがベストプラクティスっぽいと感じ、その方向で修正する事にしました。読み込みだけしたい場合などはvalで宣言すればよいと思います。

```Kotlin:コンストラクタ引数をそのままフィールド値にする形式にしました。
class DynamoDbColumn(val columnName: String, val columnType: DynamoDbColumnType)
```

### 変数持ちenum

```Kotlin:変更前（Kotlin変換直後）
package com.silverboxsoft.dynamodbtool.classes

enum class DynamoDbConditionType(condStr: String) {
    EQUAL(" = "), GREATER_THAN(" > "), LESSER_THAN(" < "), GREATER_THAN_EQ(" >= "), LESSER_THAN_EQ(" <= ");
}
```

内部変数を記載し、getterを追加します。

```Kotlin:変更後
package com.silverboxsoft.dynamodbtool.classes

enum class DynamoDbConditionType(condStr: String) {
    EQUAL(" = "), GREATER_THAN(" > "), LESSER_THAN(" < "), GREATER_THAN_EQ(" >= "), LESSER_THAN_EQ(" <= ");
    private val condStr = condStr
    fun getCondStr(): String{
        return this.condStr
    }
}
```

ここから、さらにgetterを無くす形に修正し、かつコンストラクタ変数でフィールド変数も宣言してしまう形に修正します。一括変換時、なんでこの形になってなかったか不明です。もしかしたら間違って修正しちゃっていたかもしれません。


```Kotlin:変更後
enum class DynamoDbConditionType(val condStr: String) {
    EQUAL(" = "), GREATER_THAN(" > "), LESSER_THAN(" < "), GREATER_THAN_EQ(" >= "), LESSER_THAN_EQ(" <= ");
}
```

## ListでaddメソッドつかっているものをMutableListに変更

プロパティの中がListだったりした時には自動変換が検知できない様です。
※plusメソッドは、新しい要素を追加した、新しいリストを返すメソッドなので既存のロジックの置き換えでは使わないほうが良さそうです。

## ListのsortをsortedWithに変更

```Kotlin:修正前
attrNameList.sort(
    Comparator.comparing { attrName: String -> getDynamoDbColumnType(dynamoDbRecord[attrName]).displayOrder })
return attrNameList
```
```Kotlin:修正後
return attrNameList.sortedWith(
    Comparator.comparing { attrName: String -> getDynamoDbColumnType(dynamoDbRecord[attrName]).displayOrder }
)
```

## if文のネストをwhenに変更

javaでswitchが使えない処理で、ifのネストしてた部分があったので、エラーではないけどIntelliJの自動修正機能でwhenに修正

### Mapのデータ取得対応

Mapのデータを取得する時、getだと、Null可能性が残るので、getOrDefault関数を使用

```Kotlin:修正前
    fun getColumnIndexByName(colName: String): Int? {
        return if (colNameIndex.containsKey(colName)) {
            colNameIndex[colName]
        } else -1
```

```Kotlin:修正後
    fun getColumnIndexByName(colName: String): Int {
        return colNameIndex.getOrDefault(colName, -1)
    }
```

## jafaFXのApplication起動部分修正

[Kotlin+JavaFXの基本的なコード](https://qiita.com/SUZUKI_Masaya/items/be4e30bf448321912e8f)を参考にさせて頂きました。

```Kotlin:修正前
// ・・前略・・
class App : Application() {
    @Throws(Exception::class)
    override fun start(stage: Stage) {
        prepareControl(stage)
        stage.show()
    }
    // ・・中略・・
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            launch(*args)
        }
    }
}
```

```Kotlin:修正後
// ・・前略・・
class App : Application() {
    @Throws(Exception::class)
    override fun start(stage: Stage) {
        prepareControl(stage)
        stage.show()
    }
    // ・・中略・・
}

fun main(args: Array<String>) {
    Application.launch(App::class.java, *args)
}
```

ここまででビルドとFX起動まで完了

## javaFXコンポーネント

javaFXのコンポーネント（@FXMLアノテーションで関連付けされるオブジェクト）は、initブロックを処理する時にはまだインジェクションされていない。別のinitialize関数を作って、コンストラクタ以後に呼ばなくてはいけなさそうです。

# 無事にjavaFXをKotlinで動かせました。

記事に書いてる部分だけだとスムーズに行ったように見えましたが、初学者の私は結構時間かかりました。でもちゃんと動くようになりました。微妙に前回からボタンのレイアウト位置変えてます。この際のレイアウト変更は、今まで通りjavaFX Scene Builderで行いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530376/02f9b26e-f2d8-983a-1122-338c6b56226a.png)

[現在のソース](https://github.com/silverbox/dynamodbtool)でも、githubにKotlinと認識されたようです。

# その他気になった事

Eclipseでは、実行可能jarを作る際、関係モジュールをjarに埋め込むか、サブフォルダに出力するかなど選べたのですが、IntelliJでのやり方が解りませんでした。とりあえず今はpom.xmlでmaven-assembly-pluginを使って`mvn package`をする事でjar生成しています。サイズ大きいので、依存jarは分けたいと思っている所です。

# 過去のシリーズ記事

第１回記事：[DynamoDBの情報を読み込んでJavaFXで表示してみる](https://qiita.com/silverbox/items/eba824a9f003df67181e)
第２回記事：[JavaFXで動的にテーブル列を設定する](https://qiita.com/silverbox/items/904a01d561014d800696)
第３回記事：[AWS java SDKでDynamoDBテーブル情報を取得してみる](https://qiita.com/silverbox/items/3caefb782f1bb269490f)
第４回記事：[JavaFX の TableView の選択範囲をクリップボードにコピーする。](https://qiita.com/silverbox/items/19e131bd3da02940a8c1)
第５回記事：[JavaFX でコンポーネント作って動的生成してみる](https://qiita.com/silverbox/items/3128fd2128374e11c1f7)
第６回記事：[DynamoDBのデータ型をjava SDKから把握してみる。](https://qiita.com/silverbox/items/3a434ec4a85262f973c9)
第７回記事：[JavaFXでジェネリック使って入力ダイアログ作成してみる](https://qiita.com/silverbox/items/bb3cee5a328ccc63246c)
第８回記事：[JavaFXで各種サイズ制御](https://qiita.com/silverbox/items/17b7982683be06c32240)
第９回記事：[JavaFXのDialogで入力値チェック制御](https://qiita.com/silverbox/items/ad7542db5d34a442dce5)
第１０回記事：[DynamoDBでPartiQLをjavaSDKで実行してみる。](https://qiita.com/silverbox/items/4c80f34285b8691af93a)
第１１回記事：[JavaFXでダイアログの入力チェック制御をちゃんと考えてみる](https://qiita.com/silverbox/items/5fe9a9215f2cf9a2461e)
第１２回記事：[javaFX、TableViewのソート後の情報取得不具合対応](https://qiita.com/silverbox/items/4e4a76cba9337aba45fc)


# 参考にさせて頂いたページ

## 公式ページ

[Eclipse から IntelliJ IDEA に移行する ](https://pleiades.io/help/idea/migrating-from-eclipse-to-intellij-idea.html#CodingAssistance)

## 皆さんの良記事

[JavaからKotlinに変換する7つのテクニック Kotlinらしさを生かした簡潔なコードに置き換えよう ](https://eh-career.com/engineerhub/entry/2019/05/14/103000)
[Intellij IDEAで実行可能なjarを作る方法](https://qiita.com/nwtgck/items/7a61c5bb9d5b2d266cfe)
[javaからkotlin変換の色々メモ](https://qiita.com/hibinohirokatsu/items/975918efc1c4579303e2)
[Kotlin+JavaFXの基本的なコード](https://qiita.com/SUZUKI_Masaya/items/be4e30bf448321912e8f)