LoginSignup
5
5

More than 5 years have passed since last update.

spray-jsonでキー名をスネークケースにしたい

Posted at

Scalaの命名規則的にcase classの属性はキャメルケースになる。spray-jsonがオブジェクトをJSONにシリアライズするとき、属性名をJSONオブジェクトのキー名にそのまま引き継ぐので、キー名はキャメルケースになる。RESTful APIで使うJSONはスネークケースのほうが好きなので、シリアライズするときに自動的に変換したい。

  • キャメルケース: productIdのようにアンダースコアを使わない書き方。
  • スネークケース: product_idのようにアンダースコアを使う書き方。
期待するJSONの書式
{"product_id": 1, "product_name": "...", ...}
spray-jsonがデフォルトで書きだすJSONの書式
{"productId": 1, "productName": "...", ...}

spray-jsonでキャメルケースのキーをスネークケースに変換するためのスニペットがGistのagemooij / SnakifiedSprayJsonSupport.scalaで紹介されていたので、ここでも紹介したい。

SnakifiedSprayJsonSupport.scala
package com.scalapenos.spray

import spray.json._

/**
 * A custom version of the Spray DefaultJsonProtocol with a modified field naming strategy
 */
trait SnakifiedSprayJsonSupport extends DefaultJsonProtocol {
  import reflect._

  /**
   * This is the most important piece of code in this object!
   * It overrides the default naming scheme used by spray-json and replaces it with a scheme that turns camelcased
   * names into snakified names (i.e. using underscores as word separators).
   */
  override protected def extractFieldNames(classTag: ClassTag[_]) = {
    import java.util.Locale

    def snakify(name: String) = PASS2.replaceAllIn(PASS1.replaceAllIn(name, REPLACEMENT), REPLACEMENT).toLowerCase(Locale.US)

    super.extractFieldNames(classTag).map { snakify(_) }
  }

  private val PASS1 = """([A-Z]+)([A-Z][a-z])""".r
  private val PASS2 = """([a-z\d])([A-Z])""".r
  private val REPLACEMENT = "$1_$2"
}

object SnakifiedSprayJsonSupport extends SnakifiedSprayJsonSupport

使い方は、特に自前のJsonProtocolを定義していなければ、SnakifiedSprayJsonSupport._importするだけでOKだ。
自前のJsonProtocolのオブジェクトを作っているなら、withSnakifiedSprayJsonSupportトレイトをミックスインするだけで、スネークケースの変換処理が追加される。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5