Spring Boot + MVCでkotlinx.serializationを使ってリクエスト・レスポンスのシリアライズとデシリアライズを試してみました。
使用バージョンなど
↓のバージョンを使って試してみました。
- Spring Bootは、2.5.4
- kotlinx.serialization
build.gradle.kts
はこのようになっています。
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("org.springframework.boot") version "2.5.4" id("io.spring.dependency-management") version "1.0.11.RELEASE" kotlin("jvm") version "1.5.30" kotlin("plugin.spring") version "1.5.30" kotlin("plugin.serialization") version "1.5.30" } // 〜省略〜 dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("org.springframework.boot:spring-boot-starter-test") }
お試ししてみる
コード
実装的には、kotlinx.serialization
を使うためにdata classに@Serializable
アノテーションが設定されている感じですね。
なお、kotlinx-serialization-jsonに関連するクラスがクラスパス上にあると、自動的にkotlinx.serialization
用のHttpMessageConverter
が使われるようになります。(優先度的には、Jacksonより高くなる感じです。)
今回は、リクエストボディとレスポンスボディの変換でkotlinx.serialization
が使われることを確認できるコードを書いてみました。
@RestController @RequestMapping("/hello") class HelloController { private val logger = LoggerFactory.getLogger(HelloController::class.java) @GetMapping fun get(): Message { return Message("hello!!!") } @PostMapping fun post(@RequestBody message: Message) { logger.info("mesage: {}", message) } } @Serializable data class Message( val text: String )
実行結果
レスポンスボディの変換
kotlinx.serialization
を使ってるか非常に分かりづらいですが、レスポンスとして指定したdata classの内容がJSONで返ってきていますね。
$ curl localhost:8080/hello {"text":"hello!!!"}
リクエストボディの変換
curl -X POST -H 'content-type: application/json' localhost:8080/hello -d '{"text": "siosio!"}'
ログにリクエストボディを保持しているdata classの内容が出力されていますね。
2021-09-05 15:38:02.745 INFO 43536 --- [nio-8080-exec-3] s.b.HelloController : mesage: Message(text=siosio!)
カスタマイズして使ってみる
デフォルトの構成では何も設定が入っていない状態で使われるため、data classに定義されていない項目がリクエストのJSONにあったりすると400 Bad Requestが返されたりしちゃいます。
例えば、次のリクエストを投げると、Could not read JSON: Unexpected JSON token at offset 21: Encountered an unknown key 'hoge'.
なメッセージのログが出力され400エラーとなります。
curl -X POST -H 'content-type: application/json' localhost:8080/hello -d '{"text": "siosio!", "hoge": "fuga"}'
これでは、ちょっと使い勝手が悪いですよね。これは設定をカスタマイズしたkotlinx.serialization
用のHttpMessageConverter
を登録するだけで解決します。
カスタマイズしたHttpMessageConverter
は、WebMvcConfigurer
をimplementsしたクラスを作ってconfigureMessageConverters
をオーバライドすることで登録できます。
↓のコードのように、KotlinSerializationJsonHttpMessageConverter
に設定をカスタマイズしたものを指定し、convertersの先頭に追加します。(末尾に追加してしまうと、デフォルト設定のKotlinSerializationJsonHttpMessageConverter
が使われちゃうので注意です。)
@Configuration class WebConfig : WebMvcConfigurer { override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) { converters.add(0, KotlinSerializationJsonHttpMessageConverter(Json { ignoreUnknownKeys = true })) } }