Closed9

1bitもわからんけどKotlin (Ktor)してみる <リベンジ>

inomotoinomoto

前回とっかかりが悪すぎたのでシンプルにリベンジ。

vscode devcontainerでjavaとgradleが入っているところからスタート。

inomotoinomoto

gradle initすると、プロジェクト内にgradle自体やgradlewを含め諸々が生成されるもよう。
--typeにて雛形を指定できる。この場合はgradle init --type=kotlin-applicationといった感じか。
refs https://qiita.com/suin/items/96799c9f50a31ae54969 https://docs.gradle.org/current/userguide/build_init_plugin.html

gradlewというのはgradle wrapperらしい。単にgradleを実行したり、何やらdaemonを起動したり(ruby/bundlerでいうspring的な目的かな?)、またcloneしたてなどでgradleが手元に無い場合に所定のバージョンのをとってきたりするもよう。

inomotoinomoto

実行する。

vscode ➜ /workspaces/sbox_ktor (main) $ gradle init --type=kotlin-application
Starting a Gradle Daemon (subsequent builds will be faster)

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Kotlin) [1..2] 1

Project name (default: sbox_ktor): 
Source package (default: sbox_ktor): 

> Task :init
Get more help with your project: https://docs.gradle.org/6.8/samples/sample_building_kotlin_applications.html

BUILD SUCCESSFUL in 9s
2 actionable tasks: 2 executed

DSLはGroovyにした。そのほうがネット上の資料が多そうなので。

展開後のファイル

sbox_ktor> tree
.
├── app
│   ├── build.gradle
│   └── src
│       ├── main
│       │   ├── kotlin
│       │   │   └── sbox_ktor
│       │   │       └── App.kt
│       │   └── resources
│       └── test
│           ├── kotlin
│           │   └── sbox_ktor
│           │       └── AppTest.kt
│           └── resources
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

12 directories, 8 files
sbox_ktor> ls -a1
.
..
.devcontainer
.git
.gitattributes
.gitignore
.gradle
.vscode
app
gradle
gradlew
gradlew.bat
settings.gradle

.devcontainer .git .vscodeは元々あった。逆に言うと.gitattributes.gitignoreはコマンドにより生成された

inomotoinomoto

ん?gradle-wrapper.jarがgit管理なんだけどそういうもんなのか?

inomotoinomoto

gradleの初期解説的なのはざっとこれを見る
https://qiita.com/vvakame/items/83366fbfa47562fafbf4

初期生成されたbuild.gradle

app/build.gradle (コメント削除)
plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.4.20'
    id 'application'
}

repositories {
    jcenter()
}

dependencies {
    implementation platform('org.jetbrains.kotlin:kotlin-bom')
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    implementation 'com.google.guava:guava:29.0-jre'
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
    testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
}

application {
    mainClass = 'sbox_ktor.AppKt'
}

gradle自体の拡張としてpluginsが入っている感じか。試しにid 'application'をコメントアウトすると最下部のapplicationブロックがエラーになるので、そういう構文?機能?をpluginで入れていく流れに見える。

repositoriesは、jvm系はパッケージリポジトリが完全な中央集権になっていない故に指定するものなのだろう。
npmやruby gemsは言語デファクトのリポジトリがあるので明示的に指定せず必要なら足す感じになるが。

dependenciesは見たまんま。通常のとtestに分かれている。デプロイ用にはtestのを含めないとかそういうのだろうきっと。

application、たぶんgradleから「アプリケーションをrun」みたいなことをするにあたってエントリポイントを指定してるのかな。

inomotoinomoto

./gradlew testするとunit testが動くようだし、./gradlew runするとhello worldが動く。
アプリケーションコードを見ると

package sbox_ktor

class App {
    val greeting: String
        get() {
            return "Hello World!"
        }
}

fun main() {
    println(App().greeting)
}

適当なclassに属性とgetterを生やしている感じ。
classの属性宣言の直下に一段ネストしてget()を定義するの、C#にあったアクセサ的なやつか。ネストを要する文法含め、ちょっとおもしろい。
調べると、そもそもvalがimmutableでvarがmutableな定義らしい。なるほど。

inomotoinomoto

さてktorする。以下ページ・コンテンツを参考にする。信頼性が謎ではあるが、少なくとも公式より圧倒的にちゃんとquickstartになっている。
https://jp.ktor.work/quickstart/guides/application.html

build.gradleとApp.ktを書き換え...いや、ところによってbuild.gradleに書いてあることが違いすぎる。一つ一つ調べていこう。

inomotoinomoto

pluginsブロック or apply plugin

(ほぼ)同じ機能を提供する新旧の記法っぽい。 refs https://www.it-swarm-ja.tech/ja/groovy/gradleプラグインを適用することの違い/1056004156/
(参考サイト、翻訳前で読みたいんだが。。。)

gradleとしてはpluginsブロックのが正っぽい感じがする。gradle initでデフォルトで書いてあるくらいなので。
しかしながらネット上の資料はapply pluginがかなり多数派に見える。

どちらを選ぶかによって大きな障害は無い気がするので、今回はブロックをチョイス。

dependenciesのimplementation or compile

https://qiita.com/opengl-8080/items/6ad642e0b016465891de
また新旧、しかも古いほうが多数派か...これだからjava界隈は...

挙動が違うっぽいので悩みどころではあるが、Deprecatedなものを使うのもアレなのでimplementationに寄せてみる。

inomotoinomoto

とりあえず何か動いたもの

build.gradle
buildscript {
    ext.kotlin_version = '1.3.70'
    ext.ktor_version = '1.3.2'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.4.20'
    id 'application'
}

repositories {
    jcenter()
}

kotlin {
    experimental {
        coroutines "enable"
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    implementation "io.ktor:ktor-server-netty:$ktor_version"
    testImplementation group: 'junit', name: 'junit', version: '4.12'
}

application {
    mainClass = 'sbox_ktor.AppKt'
}

App.kt
package sbox_ktor

import io.ktor.application.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*

fun main(args: Array<String>) {
    embeddedServer(Netty, 8080) {
                routing { get("/") { call.respondText("Hello, world!", ContentType.Text.Html) } }
            }
            .start(wait = true)
}

hello worldが動いている。
...のだが、formatterがどう考えてもおかしい。

このスクラップは2021/02/27にクローズされました