Kotlin と Java EE

id:nobuoka / @nobuoka
4/2 (土) Kotlin 1.0 リリース記念勉強会 in 京都

こんにちは!

  • はてな id:nobuoka
  • ソフトウェア開発者
    • モバイルアプリ開発 (Android、UWP)
    • Web 開発 (Scala、Java、TypeScript、Perl)
  • 仕事は Android アプリ 「はてなブックマーク」 開発

祝! Kotlin 1.0 リリース!

  • Android は takuji さんに任せてサーバーサイドで使ってみる
  • Kotlin と Java の相互運用性はどんなものか?
  • Java EE で使ってみてどうなるのか?
  • → Kotlin で Java EE アプリケーションを書いてみた
https://github.com/nobuoka/kotlin-java-ee-sample

使用している Java EE の技術要素

  • CDI : 依存注入
  • JAX-RS と MVC 1.0 : HTTP 周り
  • JPA : DB 周り

Kotlin と CDI

@field:Inject
private lateinit var mCommentApplication: CommentApplication

@field:Inject
private lateinit var models: Models

アノテーションの付与先の指定

プロパティやプライマリコンストラクタのパラメータにアノテーション
複数の Java 要素がターゲットになりうる

class Example(@field:Ann val foo,  // annotate Java field
              @get:Ann val bar,    // annotate Java getter
              @param:Ann val quux) // annotate Java constructor parameter
(Annotations - Kotlin Programming Language より)

Late-Initialized Properties (lateinit)

  • non-null 型のプロパティは通常コンストラクタで初期化する必要
  • CDI やユニットテストの setup メソッドでの初期化の場合には不便
  • プロパティに lateinit 修飾子を付ける!
@field:Inject
private lateinit var models: Models
(Properties and Fields - Kotlin Programming Language より)

Kotlin と JAX-RS / MVC

@Path("/comments")
@RequestScoped
open class CommentController {
    @field:Inject
    private lateinit var mCommentApplication: CommentApplication

    @Controller
    @GET
    @Produces("text/html")
    open fun getTest(): Response {
        mModels.put("comments", mCommentApplication.readComments())
        return Response.ok("comments.jsp").build()
    }
}

open アノテーション

  • デフォルトでクラスは final
  • メソッドも final
  • open アノテーションで継承可能に
  • CDI ビーンとして使用するには proxyable でなければならない (?) ので open を付ける

Kotlin と JPA

@Entity
@Table(name = "comment")
@NamedQuery(name = "Comment.findAll", query = "SELECT c FROM Comment c")
class Comment(text: String) : Serializable {
    companion object {
        private const val serialVersionUID = 1L
    }

    @field:Column(name = "text")
    var text: String = text
}

fun EntityManager.createNamedQueryCommentFindAll() =
        this.createNamedQuery("Comment.findAll", Comment::class.java)

Java の static フィールド

  • companion object のプロパティ → static backing field を持ちうる
  • 通常 private だが、Java 側から見えるようにできる
class Key(val value: Int) {
    companion object {
        @JvmField
        val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value }
    }
}
(Calling Kotlin from Java - Kotlin Programming Language より)

Java のクラスリテラル相当

val c = MyClass::class.java
(Reflection - Kotlin Programming Language)

拡張関数

  • Java のクラスにも拡張関数を定義できる!
fun EntityManager.createNamedQueryCommentFindAll() =
        this.createNamedQuery("Comment.findAll", Comment::class.java)
(Extensions - Kotlin Programming Language)

感想

  • Java と Kotlin を混ぜて使うのに困ることはほぼ無さそう
  • どうするのがいいのかで悩む箇所は出てきそう
  • Java で書かれたアプリケーションを少しずつ Kotlin で書いていくのも現実的ぽい
  • ググって出てくる Kotlin 情報は古いことも多かった → 公式のドキュメントを見よう!

参考ページ

Kotlin + Java EE

Kotlin 全般