Kotlinで未実装を表す方法

小ネタです。

Scalaでは ??? という関数を実行することで、未実装を表す scala.NotImplementedError を返すことができます。

Kotlinにも例外 kotlin.NotImplementedError があり、それを呼び出す関数として TODO() が定義されています。

github.com

使い方

メソッドに対して、コンパイルを通しつつ未実装を表す場合は、以下のように書きます。 引数に文字列を指定することで、例外にコメントを追加することも可能です。

fun hoge(s: String): String = TODO()

// 未実装コメントを追加することも可能。
fun fuga(s: String): String = TODO("未実装ですよ")

また、inline修飾子が付いているため、メソッドの途中に書くことでIntellijの場合はそれ以降の処理が実行されないという警告が表示されます。

fun foo(s: String): String = {

  println("before: $s")

  TODO()

  println("after: $s")

}

f:id:rabitarochan:20160225082936p:plain

まとめ

未実装を表す kotlin.NotImplementedErrorTODO() について紹介しました。

TODO() のように、例外のみを返すメソッドをインライン展開させるという書き方も便利なので、ぜひ使ってみてください。

SpringBoot + Kotlin + Devtools を IntelliJ IDEA で上手く動かす

Kotlin で Web 開発をするために、とりあえず今は Spring Boot を使っています。

Eclipse の HTML, JavaScript エディタが自分に合わない(合うプラグインを見つけられなかった)ため、IntelliJ IDEA を使おうと思って設定を始めたのですが、上手く動かす方法を見つけるのが大変だったのでここでまとめておこうと思います。備忘録。

1. プロジェクト作成

Spring Boot のプロジェクトについては、Spring Initializr を使って作ります。

今回は以下の内容で作ります。

  • Gradle project
  • Spring Boot Version 1.3.1
  • Dependencies:
    • Web
    • Devtools
    • Thymeleaf

Group と Artifact はご自由に。今回は com.rabitarochanspringboot-kotlin-intellij で作ってみます。

プロジェクトファイル一式を ZIP ファイルでダウンロードしたら、任意のディレクトリに展開します。

2. build.gradle 修正

次に、build.gradle に Kotlin 用の設定を追加していきます。

先に、変更箇所をコメントで記載した build.gradle 全体を載せます。

buildscript {
    ext {
        springBootVersion = '1.3.1.RELEASE'
        // (1) Kotlin のバージョンを指定
        kotlinVersion = '1.0.0-beta-4584'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        // (2) Kotlin の Gradle plugin を追加
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
    }
}

apply plugin: 'java'
// (3) Kotlin plugin を有効化
apply plugin: 'kotlin'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot' 

jar {
    baseName = 'springboot-kotlin-intellij'
    version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    // (4) Kotlin のライブラリを参照追加
    compile("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
    compile('org.springframework.boot:spring-boot-devtools')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test') 
}

// (5) IntelliJ IDEA 用の設定を追加
idea {
    module {
        inheritOutputDirs = false
        outputDir = file("$buildDir/classes/main/")
    }
}

eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.9'
}

(1) で、Kotlin のバージョンをプロパティとして定義します。Kotlin は現時点 (2016/1/12) でバージョン 1.0 のベータ版という状態のため、新しいバージョンが頻繁に出ます。今回の build.gradle でも 2 箇所で Kotlin のバージョンが必要となりますので、プロパティにしておいたほうがいいでしょう。

Kotlin のバージョンは、Kotlin の Twitter アカウントUsing Gradle で確認しています。

(2)、(3) で、Kotlin の Gradle プラグインを有効化しています。

(4) で、Kotlin の標準ライブラリを依存ライブラリに追加します。

(5) では、IntelliJ IDEA で make した際の出力ディレクトリを上書きしています。これは、Spring Boot Devtools の自動再起動を有効化するために必要です。

IntelliJ IDEA では make した際のデフォルト出力先は out ディレクトリとなっていますが、Spring Boot Devtools はこのディレクトリではなく、idea.module.outputDirs で指定した $buildDir/classes/main/ を見ているようです。IntelliJ IDEA プラグインの設定については IdeaModule - Gradle DSL Version 2.10 をご参照ください。

3. IntelliJ IDEA のショートカット登録

Spring Boot + IntelliJ IDEA で調べるとすぐ発覚するのですが、IntelliJ IDEA で実行 / デバッグ実行中に自動 make が起動しないという仕様があります。これに対応するために、Ctrl (or Cmd) + Shift + S でファイル保存と make をするマクロを実行するように設定していきます。

3.1. Save all and make マクロを作成する

勝手に名前つけましたが、以下の手順で上で書いたマクロを作成していきます。

  1. IntelliJ IDEA を起動します
  2. メニューの [Edit] → [Macros] → [Start Macro Recording] をクリックします。(これ以降の操作がマクロの内容となります。)
  3. 【操作1】メニューの [File] → [Save All] をクリックします。
  4. 【操作2】メニューの [Build] → [Make Project] をクリックします。
  5. メニューの [Edit] → [Macros] → [Stop Macro Recording] をクリックし、マクロの記録を停止します。
  6. マクロ名を入力するダイアログが表示されるので、適当に名前を入力します。(ここでは Save all and make と入力します。)

3.2. マクロを実行するショートカットを設定する

マクロを Ctrl (or Cmd) + Shift + S で実行できるようにするため、以下の手順でショートカットを登録します。

  1. メニューの [IntelliJ IDEA] → [Preferences...] をクリックします。(これは OS X の場合です。Windows は [File] → [Preferences...] だったはず・・・)
  2. 設定一覧の [Keymap] を選択します。
  3. 右側に検索ボックスが表示されているので、[save all] で検索すると、先ほど作成したマクロが表示されるので、[右クリック] → [Add Keyboard Shortcut] をクリックします。
  4. ダイアログが表示されるので、設定するショートカットを入力します。ショートカットの内容を確認して [OK] ボタンをクリックします。

これで IntelliJ IDEA の設定は完了です。

4. IntelliJ IDEA のプロジェクトを作成する

gradle のコマンドで IntelliJ IDEA のプロジェクトファイルを作成します。

ターミナルを起動して ./gradlew idea を実行するだけです。Windows の場合は gradlew idea です。

あとは、IntelliJ IDEA からプロジェクトのディレクトリを指定して Open します。

5. 実行する

まだ Kotlin は書いてませんが、実行方法を書いておきます。

  1. Applicationクラスを [右クリック] → [Debug ...] をクリックします。
  2. あとはソース、HTML ファイル等を編集して、上で登録したショートカットを押すと、デバッグ実行中でも自動再起動やホットスワップがおこなわれ、スムーズに開発できます!

また、コントローラーにルーティングを追加した場合や、クラスのメソッドを追加した際には、ホットスワップが上手く動かないらしく以下のメッセージが表示されます。

Hot Swap failed:
com.rabitarochan.MyApplication: add method not implemented;
com.rabitarochan.MyApplication: Operation not supported by VM

メッセージ的には failed と書いてありますが、Devtools の自動再起動にてちゃんと認識してくれるようですので、あまり気にしなくてもいいでしょう。ちゃんと認識しない場合はちゃんと再起動してあげたほうがいいです。

まとめ

あまり大きなアプリを開発しているわけではありませんが、以上の手順で今のところスムーズに開発できてます。

Kotlin で Spring Boot を書くためには少し工夫が必要だったりするので、それについてはまた後で記事を書こうと思います。まずは開発環境を構築するということで、ご査収ください。

今回のソースは以下のリポジトリです。Application クラスと Controller を Kotlin で実装したソースもありますので、記事を書くまではこちらをご参照ください。

github.com

でわ。

2016年の抱負

もう1/5ですが、あけましておめでとうございます。

これまで抱負的なものは書いてなかったので、今年は書いてみようと思います。

  1. Kotlin の学習
  2. Web サービス作る
  3. iOS / Android のキャッチアップ
  4. 社内勉強会の継続

Kotlin の学習

昨年の10月あたりから Kotlin 触ってました。Android 開発に人気があるみたいですが、自分の領域的には Web などバックエンド側が多いので、そっち寄りを中心に学習していこうと思います。

まだまだ純 Kotlin のフレームワーク・ライブラリも多くないことから、時間を見つけて作ってみたいです。

あと、Scala も置いていかれない程度に追いかけたい。

Web サービス作る

まずは社内向けに Web サービスを作ろうと思っています。「この Web サービスいいんだけど、ウチの社員数的に利用料金が高くなる・・・。」というものが結構多いので、それを代替できるようなものを作っていこうと思います。

仕事・業務以外でも1つくらい作りたい。

iOS / Android のキャッチアップ

昨年末に iOS アプリの研修を受けたので、その時作りかけたアプリをリリースするところまで持って行きたいです。ついでに Android 版も作ってみて、一通り iOS / Android 開発を経験しておきたいです。

社内勉強会の継続

自分が言い出しっぺというわけではないですが、社内勉強会・アイディアソンを何回かやりました。これは今年も継続していきたいです。

アイディアソンでは色々とアイディアはでる一方、実現までたどり着けていないのが多いので、今年は少しでも前進しなくてはと思ってます。

直近の目標としては、社員旅行制度を使ってハッカソンやりたい。


やりたいことはいっぱいあるので、ゆっくりじっくり取り組んでいきたいです。本年もどうぞよろしくお願いいたします。

Kotlinのプロパティをタイプセーフに取得する

おはようございます。Kotlinアドベントカレンダー2015の22日目の記事でございます。 DBアクセスライブラリを作っていたときに見つけたものを紹介します。

Kotlinのプロパティをタイプセーフに取得する

Kotlinのプロパティは、Java8のメソッド参照のように書くことでプロパティ定義(kotlin.reflect.KProperty1<T, R>)を取得することができます。

// データクラスを定義
data class Person(val name: String, val age: String)

fun main(args: Array<String>): Unit {
    val prop1 = Person::name
    println(prop1.name) // => "name"

    val prop2 = Person::age
    println(prop2.name) // => "age"
}

コンパイル結果を確認していないので不確かですが、上記のプロパティ名を取得する処理については、コンパイル時に解決しているのかループで回してもあまりコストがかかっていませんでした。

もちろん、プロパティ名を変更した場合は参照箇所がコンパイルエラーになるため、プロパティ名をハードコーディングしていた箇所を置き換えることができます。

データベースの問い合わせ結果をマッピングする

Scala の Skinny Framework や Scalikejdbc の作者の @seratch さんが、Kotlin の DB アクセスライブラリを書いていました。

seratch/kotliquery https://github.com/seratch/kotliquery

ことりクエリーかわいい。自分のDBアクセスライブラリは置いといてこっち触りましょうw ことりクエリーでは、問い合わせ結果が Row という ResultSet をラップしたクラスで返ってきます。このクラスに上で書いたプロパティ参照を受け取るメソッドを追加することで、プロパティ名をハードコーディングしなくてもよくなります。

// 追加するメソッドの例
fun <T> get(prop: KProperty1<T, String?>): String? {
    val columnLabel = camelToSnake(prop.name) // camelCase を snake_case に変換するメソッド
    return string(columnLabel)
}

fun <T> get(prop: KProperty1<T, Int?>): Int? {
    val columnLabel = camelToSnake(prop.name)
    return int(columnLabel)
}

// データ型の数だけ続く・・・
// マッピング
val toMemberReflection: (Row) -> Member = { row ->
    // プロパティ名のハードコーディングがなくなる!
    Member(row.get(Member::id)!!, row.get(Member::name), row.get(Member::createdAt)!!)
}

この拡張をしてみたソースを置いておきます。

kotliquery/Row.kt at mapping-reflection · rabitarochan/kotliquery https://github.com/rabitarochan/kotliquery/blob/mapping-reflection/src/main/kotlin/kotliquery/Row.kt

まとめ

例として、データベースの結果を取得する方法をあげましたが、Webリクエストのパラメータを取得する、JSONシリアライズ/デシリアライズなど使える箇所はいろいろあると思います。 プロパティ以外にも、メソッド参照も取得できますし、JavaのClassも取得することができます。みなさんもKotlinのリフレクションを触ってみてください!

明日は mattak さんです!!

Kotlin で Loan パターン (別解)

最近 Kotlin ばっかりやってます。

さて、Qiita に同じ内容の記事が出てました。

Kotlin - Kotolin で Loan パターン - Qiita http://qiita.com/deadbeef/items/862b908ac54fdd58c3df

やり始めた時に自分も作ってたので載せておこうと思います。 合わせて、疑問点も書いておきます。

package sandbox.loanpattern

fun <T : Closeable, R> using(resource: T, f: (T) -> R): R {
    try {
        return f(resource)
    } finally {
        resource.close()
    }
}

使い方

using (ByteArrayOutputStream()) { outStream ->
    outStream.write(...)
}

ほぼ Scala と同じにかけます。

疑問

using 関数の定義を見てみると、リソースと、リソースを利用する関数の2引数を取るものとなっています。 しかし、使い方を見てみると using 関数に渡す引数 f はカッコの外に書いています。

これって言語的にはどういう機能で、リファレンスに記載のあるものでしょうか?(見つけられなかった)

IntelliJ IDEA 14 で SQL ファイルの方言を指定する

SQLファイルの方言を設定する方法をいつも忘れるのでメモ。 画面は Mac 版ですが、Windows 版でも同じはず。

  1. [Preferences] を開く
  2. [Languages & Frameworks] → [SQL Dialects] を選択
  3. カレントプロジェクトのファイルが表示されるので、該当のファイル・ディレクトリのDBサーバーを指定する。
    • ファイルごとに異なるDBサーバーを指定できる。
    • ディレクトリを指定すると、今後作成されるSQLファイルについても同じDBサーバーが設定される。 f:id:rabitarochan:20150925231520p:plain

以上です。

Windows Server に Apache を利用して Subversion サーバーを構築して ActiveDirectory 認証を設定する

タイトルの通り。以下の環境・アプリケーションを使用して Subversion サーバーを構築する。

1. 準備

ApacheHaus の Web ページから、Apache および Subversion のモジュールをダウンロードする。 Windows 向けのパッケージは ApacheHaus 以外のサイトでも公開されているが、ApacheHaus だと Subversion のモジュールも一緒に提供されているので安心感がある。

http://www.apachehaus.com/cgi-bin/download.plx

今回は以下のモジュールをダウンロード。 Apache および Subversion のモジュールは VC9 でコンパイルされたものと VC11 でコンパイルされたものの 2 種類があるので揃えるように注意する。

2. モジュールを展開する

ダウンロードしたモジュールを展開する。今回はそれぞれ以下のディレクトリに展開する。

D:\
  `- Application\
     `- Apache\
        `- httpd-2.4.16-x64\

3. リポジトリを配置するディレクトリを作成する

Subversionリポジトリを配置するディレクトリを作成する。今回は D:\Application\Apache\_svn\repositories というディレクトリを作成。

4. Apache の設定ファイルを修正

Apache の設定ファイルを修正。主な修正内容は以下のとおり。

httpd.conf

  • デフォルトの設定だと ServerRoot が存在しないディレクトリをを指しているので修正
  • 必要なモジュールを有効化
  • 今回用に作成する設定ファイルを読み込むように設定

svn.conf (新規作成)

httpd.conf

修正する箇所のみ記載。

(デフォルトの設定だと `ServerRoot` が存在しないディレクトリをを指しているので修正)
- Define SRVROOT "/Apache24"
+ Defile SRVROOT "D:/Application/Apache/httpd-2.4.16-x64"

(必要なモジュールを有効化。それぞれ先頭の # を削除してコメント解除。)
- #LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
+ LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
- #LoadModule ldap_module modules/mod_ldap.so
+ LoadModule ldap_module modules/mod_ldap.so

(今回用に作成する設定ファイルを読み込むように設定)
+ Include conf/svn.conf

svn.conf

httpd-2.4.16-x64\conf ディレクトリ内に新規ファイルとして作成する。

#### Subversion サーバー
# モジュールロード
LoadModule dav_module       modules/mod_dav.so
LoadModule dav_fs_module    modules/mod_dav_fs.so
LoadModule dav_svn_module   modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
# バーチャルホスト設定
<VirtualHost *:80>
    ServerAdmin administrator@example.com
    ServerName svn.example.com
    CustomLog "logs/svn.example.com/access.log" common
    ErrorLog "logs/svn.example.com/error.log"
    Timeout 1200
    ProxyTimeout 1200

    <Location /svn/>
        DAV                 svn
        SVNParentPath       "D:/Application/Apache/_svn/repositories"
        SVNListParentPath   on
        AuthzSVNAccessFile  "D:/Application/Apache/_svn/access-rule.txt"
        
        # LDAP認証
        AuthType Basic
        AuthName "Subversion Repository"
        AuthBasicProvider ldap
        AuthLDAPUrl "ldap://ad.example.com:389/DC=example,DC=com?sAMAccountName?sub?(objectClass=user)"
        AuthLDAPBindDN  Administrator@example.com
        AuthLDAPBindPassword  administrator-password
        Require valid-user
        LDAPReferrals Off
    </Location>
</VirtualHost>

以下、簡単にディレクティブの設定を解説。詳しくはお調べください。

  • CustomLog, ErrorLog
    該当のバーチャルホストにアクセスされた際のアクセスログとエラーログの出力先を指定。
    今回は logs\svn.example.com ディレクトリにログを出力するように設定しているが、svn.example.com ディレクトリを事前に作成していないと apache の起動に失敗するので注意。
  • SVNParentPath
    Subversion リポジトリが配置されているディレクトリを指定。
  • AuthzSVNAccessFile
    リポジトリごとにアクセス権限を設定するためのファイルを指定。権限の設定方法は後述。
  • AuthLDAPUrl, AuthLDAPBindDN, AuthLDAPBindPassword
    LDAP サーバー (今回は ActiveDirectory) に接続するための情報を指定。
  • LDAPReferrals Off
    よくわからないけど付けないとエラーが発生する。

5. リポジトリの作成

D:/Application/Apache/_svn/repositories ディレクトリにリポジトリを作成する。他のサーバーに作成済みの Subversion リポジトリをコピーしてきても OK 。 リポジトリを作成するためのコマンドは、Apache ディレクトリに統合した際に httpd-2.4.16-x86\bin に展開されているので、パスを通すか直接呼び出す。

初期ディレクトリの作成が長くて打ち間違えると大変なので、バッチ化した方がいい。

(リポジトリのルートディレクトリに移動)
> cd D:\Application\Apache\_svn\repositories

(リポジトリ hoge を作成)
> D:\Application\Apache\httpd-2.4.16-x64\bin\svnadmin.exe create hoge

(初期ディレクトリ作成)
> D:\Application\Apache\httpd-2.4.16-x64\bin\svn.exe mkdir ^
    file:///D:/Application/Apache/_svn/repositories/hoge/trunk ^
    file:///D:/Application/Apache/_svn/repositories/hoge/branches ^
    file:///D:/Application/Apache/_svn/repositories/hoge/tags ^
    -m "Create base directories"

6. リポジトリの権限設定

D:/Application/Apache/_svn/access-rule.txtリポジトリのアクセス権限を設定するためのファイルを作成する。

[groups]
hoge = rabitarochan, user_aaa, user_bbb
fuga = user_aaa, user_bbb

[repo_hoge:/]
* = 
@hoge = rw

[repo_fuga:/]
* = 
@fuga = rw

以下、簡単に解説。詳細は AuthzSVNAccessFile でググろう。

  • [groups] 以下にグループを定義することができる。<グループ名> = <ユーザー名> の形式で記述し、ユーザー名はカンマで区切る。
  • [<リポジトリ(ディレクトリ)名>:<パス>] 以下にアクセス権限を定義できる。パスは /hoge のように詳細に設定することも可能。
    • * = をはじめに定義し、全てのユーザーからのアクセスを禁止する。
    • @hoge = rw を定義し、hoge グループのユーザーに対して read / write 権限を追加。
      読み取り専用の権限を設定する場合は @hoge = r と記述する。
    • グループは必ず作成する必要はなく、user_ccc = rw とユーザーの権限を直接定義することも可能。

7. ApacheWindows サービスに登録する。

コマンドプロンプトにて以下のコマンドを実行。

(Windows サービスに登録)
> D:\Application\Apache\httpd-2.4.16-x64\bin\httpd.exe -k install

以下、オプションなど補足。

  • -n <サービス名> とすると、サービス名を指定できる。デフォルトは Apache2.4
  • Windows サービスを解除する場合は -k uninstall を実行する。もし -n オプションでサービス名を指定して登録した場合は、名前を揃える必要があるので注意する。

8. 起動, 動作確認

Windows サービスの管理画面から、登録したサービスを開始する。Apache の設定ファイルの記載ミスや、必要なファイル, ディレクトリがない場合は起動に失敗するため、Apache のログファイルを参照して解決する。

まとめ

Apache + Subversion on Windows Server の手順をほぼ 1 から解説してみました。 Collabnet Subversion Edge が遅いと苦情を受けた方 (おれおれ!!) は、ぜひお試しください。