Класс Scala ключ / значение для Json

Учитывая следующий класс дела:

case class ValueItem(key: String, value: String)

и следующий форматер json:

implicit val valueItemFormat: Format[ValueItem] = (
        (__ \ "key").format[String] and
        (__ \ "value").format[String])(ValueItem.apply, unlift(ValueItem.unapply))

представление json экземпляра ValueItem, например

ValueItem("fieldname", "fieldValue")

является

{ "key" : "fieldName" , "value" : "fieldValue" }

Мне интересно, как получить JSON в сериализации плоский ключ / значение, как

{ "fieldName" : "fieldValue" }

2 ответа

Решение

Я не могу придумать хороший способ сделать это с помощью комбинаторов, так как большинство подходов требуют более прямого способа сопоставления значений в путях к полям класса case.

Вот решение, которое будет работать для таких объектов, как {"fieldName" : "fieldValue"},

import play.api.libs.json._
import play.api.data.validation.ValidationError

implicit val fmt: Format[ValueItem] = new Format[ValueItem] {

    def reads(js: JsValue): JsResult[ValueItem] = {
        js.validate[JsObject].collect(ValidationError("Not a key-value pair")) {
            case JsObject(Seq((key, str: JsString))) => ValueItem(key, str.value)
        }
    }

    def writes(v: ValueItem): JsValue = Json.obj(v.key -> v.value)

}

Я прибег к определению reads а также writes вручную, как вы можете видеть. Reads это сложная часть, так как мы не привыкли вводить имена путей в классы дел. Мы можем validate объект как JsObject будет первый collect только объекты, которые соответствуют точной структуре, которую мы ищем (только одна пара ключ-значение, где значение является JsString). Writes гораздо проще, так как Json.obj можем делать именно то, что мы хотим.

В бою:

scala> Json.parse(""" { "fieldName" : "fieldValue" } """).validate[ValueItem]
res0: play.api.libs.json.JsResult[ValueItem] = JsSuccess(ValueItem(fieldName,fieldValue),)

scala> val item = ValueItem("myKey", "myValue")
item: ValueItem = ValueItem(myKey,myValue)

scala> Json.toJson(item)
res2: play.api.libs.json.JsValue = {"myKey":"myValue"}

Play выпустила свой модуль для работы с JSON, независимый от Play Framework, Play WS

Сделал запись в блоге о чтении JSON для case-классов, но write довольно похожа. проверить это на http://pedrorijo.com/blog/scala-json/

Используя case-классы и Play WS (уже включены в Play Framework), вы конвертируете case-классы между json и case-классами, используя неявную однострочную строку

case class User(username: String, friends: Int, enemies: Int, isAlive: Boolean)

object User {
  implicit val userJsonFormat = Json.format[User]
}
Другие вопросы по тегам