この記事に関して
最近、Kotlinを座学で勉強しています。今までの自分の経験から、自分の性質では、自分で何か作らないと身につかないです。そこで、最近投稿してるシリーズのJavaFXによるDynamoDBツールをKotlinに移植してみようと思いました。
まだまだ機能追加予定なので、今後はKotlinでの機能追加したいという考えです。
目的は違えど同じような事をする人はいるかと思いますので、その人達の参考の一つになれば幸いです。
※そんな感じで勉強している最中で、今の自分はKotlinマスターではないです。こちらの記事で間違っている部分や考慮不足がある可能性があります。その点ご注意ください。
JavaをKotlinに変換する方法の考察
IntelliJやAndroidStudioでは標準で変換機能がついている様です。自分も別記事でやりましたが、AndroidStudioもIntellijの派生らしいです。そんな機能がついているぐらいだから独立してツール化したものがあってよさそうですが、自分はそんなツールを見つける事が出来ませんでした。検索しても大体IntelliJの機能を使っていたり、AndroidStudioでの話でした。
この状況から判断すると、IntelliJを使わなければならない事になります。現在、対象プロジェクトがEclipseなので、これをIntelliJのプロジェクトに変換する必要があります。
EclipseプロジェクトをIntelliJプロジェクトに変換する
公式ページ、「Eclipse から IntelliJ IDEA に移行する」にその必要が無い事が書いてありました。mvnプロジェクト作る時、mvn eclipse:eclipse
とかやってたので、IntelliJ専用のコマンドがあるとか思ってましたが、そうでもなさそうです。pom.xmlさえあれば普通にImport出来そうです。
Importしてみる
Open
を選択すると、プロジェクトのフォルダを選択する画面になる。そこで対象フォルダを選択すると以下画面が出てきました。
もしかしたら自分が今まで勘違いしていたのかもしれません。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を作る方法を参考に、jarを出力してみます。こちらの記事のトレースなので特に書く事は無いのですが、ちゃんとjarが出力され、実行も出来ました。
gitにアップ
ここまででEclipseプロジェクトをIntelliJプロジェクトに変換できたと思うので、gitにアップしようと思います。しかし、なんか中間生成ファイルが大量に発生し、.gitignore
の対応が必須と思われます。GithubGistにあったサンプルを参考に、.gitignore
を編集します
javaからKotlinへ一括変換する
ここまでくれば後はIntelliJの機能を使って一括変換できるはずです。
JavaからKotlinに変換する7つのテクニック Kotlinらしさを生かした簡潔なコードに置き換えよう を参考に、「メニューバーの「Code」→「Convert Java File to Kotlin File」メニュー」を実行します。
ここで、ファイルを選択していると対象ファイルだけKotlinになってしまうので、srcフォルダを選択して実行した方がよさそうです。
エラー部分を修正する
結構エラーが出てる状態です。データクラスとか依存が少ないクラスから修正していこうと思います。
まずはimport宣言の修正
どうやら、他クラスの内部クラスも宣言してしまいエラーになってる様なので、削除します。また、全ソースにプロジェクトで使ってるimportが全て記載されてしまっているみたいなので、使ってるもの以外削除します。
Lombockのgetter/setter対応
どうやらLombockアノテーションで提供されるgetter/setterメソッドが使えずに出てるエラーが沢山。
javaからkotlin変換の色々メモによるとlombockは使えない模様です。
package com.silverboxsoft.dynamodbtool.classes
import lombok.Data
@Data
class DynamoDbColumn {
private val columnName: String? = null
private val columnType: DynamoDbColumnType? = null
}
単純置き換えだと下のような感じになると思います。
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を許可しない形に修正します。
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で宣言すればよいと思います。
class DynamoDbColumn(val columnName: String, val columnType: DynamoDbColumnType)
変数持ちenum
package com.silverboxsoft.dynamodbtool.classes
enum class DynamoDbConditionType(condStr: String) {
EQUAL(" = "), GREATER_THAN(" > "), LESSER_THAN(" < "), GREATER_THAN_EQ(" >= "), LESSER_THAN_EQ(" <= ");
}
内部変数を記載し、getterを追加します。
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を無くす形に修正し、かつコンストラクタ変数でフィールド変数も宣言してしまう形に修正します。一括変換時、なんでこの形になってなかったか不明です。もしかしたら間違って修正しちゃっていたかもしれません。
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に変更
attrNameList.sort(
Comparator.comparing { attrName: String -> getDynamoDbColumnType(dynamoDbRecord[attrName]).displayOrder })
return attrNameList
return attrNameList.sortedWith(
Comparator.comparing { attrName: String -> getDynamoDbColumnType(dynamoDbRecord[attrName]).displayOrder }
)
if文のネストをwhenに変更
javaでswitchが使えない処理で、ifのネストしてた部分があったので、エラーではないけどIntelliJの自動修正機能でwhenに修正
Mapのデータ取得対応
Mapのデータを取得する時、getだと、Null可能性が残るので、getOrDefault関数を使用
fun getColumnIndexByName(colName: String): Int? {
return if (colNameIndex.containsKey(colName)) {
colNameIndex[colName]
} else -1
fun getColumnIndexByName(colName: String): Int {
return colNameIndex.getOrDefault(colName, -1)
}
jafaFXのApplication起動部分修正
Kotlin+JavaFXの基本的なコードを参考にさせて頂きました。
// ・・前略・・
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)
}
}
}
// ・・前略・・
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で行いました。
現在のソースでも、githubにKotlinと認識されたようです。
その他気になった事
Eclipseでは、実行可能jarを作る際、関係モジュールをjarに埋め込むか、サブフォルダに出力するかなど選べたのですが、IntelliJでのやり方が解りませんでした。とりあえず今はpom.xmlでmaven-assembly-pluginを使ってmvn package
をする事でjar生成しています。サイズ大きいので、依存jarは分けたいと思っている所です。
過去のシリーズ記事
第1回記事:DynamoDBの情報を読み込んでJavaFXで表示してみる
第2回記事:JavaFXで動的にテーブル列を設定する
第3回記事:AWS java SDKでDynamoDBテーブル情報を取得してみる
第4回記事:JavaFX の TableView の選択範囲をクリップボードにコピーする。
第5回記事:JavaFX でコンポーネント作って動的生成してみる
第6回記事:DynamoDBのデータ型をjava SDKから把握してみる。
第7回記事:JavaFXでジェネリック使って入力ダイアログ作成してみる
第8回記事:JavaFXで各種サイズ制御
第9回記事:JavaFXのDialogで入力値チェック制御
第10回記事:DynamoDBでPartiQLをjavaSDKで実行してみる。
第11回記事:JavaFXでダイアログの入力チェック制御をちゃんと考えてみる
第12回記事:javaFX、TableViewのソート後の情報取得不具合対応
参考にさせて頂いたページ
公式ページ
Eclipse から IntelliJ IDEA に移行する
皆さんの良記事
JavaからKotlinに変換する7つのテクニック Kotlinらしさを生かした簡潔なコードに置き換えよう
Intellij IDEAで実行可能なjarを作る方法
javaからkotlin変換の色々メモ
Kotlin+JavaFXの基本的なコード