🤔

ktor 2.0.3 でThymeleafが動かない問題の解決方法

2022/07/30に公開

背景

ktor 1.6.8 でシステム開発中、 v 2.0 が出てしまい、Migration Guide に沿って修正したのに、Thymeleafが動かない。GETリクエストに対してバカ正直にJSONを返してしまう。

その上、初期状態のプロジェクトを起こしなおしても、現象が改善しない。謎。

——最終的には、すごいしょうもない仕様変更による問題だとわかったので、メモとして書き残す。

現象の環境再現

問題なく動く環境

  • Ktor Project Generator
    • 以下のプラグインにチェック
      • Routing
      • Thymeleaf
    • 生成物をDLして展開しておく
  • gradle run

    • gradlrew が同梱されていないので、ローカルの gradle で動かすか、IntelliJ IDEAでプロジェクトを開く
  • http://localhost:8080
    • まずは、「Hello World!」が返ってくることを確認する
  • http://localhost:8080/html-thymeleaf
    • この環境では動くはず。

問題の環境

  • Ktor Project Generator
    • Engine -> Tomcat に変更
    • 以下のプラグインにチェック(開発中の環境に寄せている)
      • Authentication
      • AutoHeadResponse
      • DoubleReceive
      • Locations
      • Routing
      • Static Content
      • CachingHeaders
      • ContentNegotiation
      • CORS
      • DefaultHeaders
      • ForwardedHeaders
      • CallLogging
      • GSON
      • Thymeleaf
    • 生成物をDLして展開しておく
  • gradle run

    • gradlrew が同梱されていないので、ローカルの gradle で動かすか、IntelliJ IDEAでプロジェクトを開く
  • http://localhost:8080
    • まずは、「Hello World!」が返ってくることを確認する
  • http://localhost:8080/html-thymeleaf
    • 動かないと思う。

原因

kotlin/com/example/Application.kt のソースコード参照

@Suppress("unused") // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {
    configureSerialization()
    configureTemplating()
    configureMonitoring()
    configureHTTP()
    configureSecurity()
    configureRouting()
}

ぱっと見、何も問題がないように見える。が実はこれがまずい

@Suppress("unused") // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {configureSerialization()configureTemplating()
    configureMonitoring()
    configureHTTP()
    configureSecurity()
    configureRouting()
}

ktor 2.0.3 においては 、

install(ContentNegotiation)

install(Thymeleaf)
より前に呼ばれてはいけない仕様に変更されている。

1.6.8 では順序を気にせずとも動作していたので、Migration Guide通りにパッケージ名を置き換えて、一部のクラス名を置き換えただけではテンプレートエンジンが動かないバグに見舞われるのである。

対策

@Suppress("unused") // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {
    configureTemplating()
    configureSerialization()
    ... 中略 ...
}

にて万事解決!

ちなみに、この問題、Ktor Project Generatorにて特定のプラグインの組み合わせをセットすると生成コードの順序が入れ替わって発生する。つまりKtor Project Generator側の実装ミス。誰かIssueあげて欲しい。

Discussion