Json для класса case с Option[Long]

Рассмотрим этот класс случаев

case class Location(val name: String, val id: Option[Long] = None)

Я могу написать "toJson" так:

implicit val locationWrites: Writes[Location] = (
      (JsPath \ "name").write[String] and
      (JsPath \ "id").write[Option[Long]]
    ) (unlift(Location.unapply))

но я борюсь с "fromJson":

implicit val locationReads: Reads[Location] = (
      (JsPath \ "name").read[String]
    ) (Location.apply _, None)

Объяснение: на самом деле идентификатор должен быть установлен уровнем сохраняемости, поэтому я не хочу указывать его вручную.

Я также пробовал:

implicit val locationReads: Reads[Location] = (
      (JsPath \ "name").read[String] and
      (JsPath \ "id").read[Option[Long]]
    ) (Location.apply _)

но, к сожалению, тогда я получаю:

Не найден десериализатор Json для типа Option[Long]. Попробуйте реализовать неявное чтение или формат для этого типа.

Мне действительно нужно создать имплицит для этого?

Как это работает (например: компилируется)? Я спрашиваю, потому что это абсолютно тривиально для людей, но вдруг появляется неявное, и оно компилируется. Не уверен, что это вообще имеет смысл, но боюсь, что нет.

implicit val optionalLongReads: Reads[Option[Long]] = (
    (JsPath \ "optional").read[Option[Long]]
    )

edit: определенно не имеет смысла.

Если я отправлю curl --include --request POST --header "Content-type:application/json" --data '{"name": "Gondor", "id": "2"}' localhost:9000, я получу:

HTTP/1.1 500 Внутренняя ошибка сервера
Content-Length: 8029
Content-Type: text/html; charset=utf-8
Дата: суббота, 08 октября 2016 г., 21:49:51 по Гринвичу

Я тоже не могу оставить id пустым :(


person Community    schedule 08.10.2016    source источник


Ответы (4)


Play Framework поддерживает поле Option из коробки.

Вы должны использовать readNullable[Long] вместо read[Option[Long]].

implicit val locationReads: Reads[Location] = (
  (JsPath \ "name").read[String] and
  (JsPath \ "id").readNullable[Long]
)(Location.apply _)

Вы также можете использовать writeNullable[Long] в своем locationWrites.

С write[Option[Long]] результирующий json будет содержать поле id со значением null в случае, если id равно None. С writeNullable[Long] поле id вообще не будет присутствовать для случая None:

val location = Location("Gondor", None)

// locationWrites with (JsPath \ "id").write[Option[Long]]
{
   "name":"Gondor",
   "id":null
}

// locationWrites with (JsPath \ "id").writeNullable[Long]
{
   "name":"Gondor"
}
person Josef Vlach    schedule 09.10.2016

Не уверен, почему эта библиотека json не поддерживает Option напрямую, попробуйте следующее:

implicit def readOption[T](implicit inner: Reads[T]): Reads[Option[T]] = inner.map(Some.apply).orElse(Reads.pure(None))

По-видимому, они поддерживают это, попробуйте следующее:

(JsPath \ "id").nullable[Long]

ну dsls я думаю.

Или используйте более продвинутую библиотеку json, например. http://argonaut.io/ + https://github.com/alexarchambault/argonaut-бесформенный или https://travisbrown.github.io/circe/

person Reactormonk    schedule 08.10.2016

данные, которые вы отправляете, это "id": "2", это строка. Если вы хотите отправить Long, я думаю, попробуйте "id": 2

person manish    schedule 09.10.2016

Play json поддерживает автоматическое создание функций сериализации/десериализации для классов случаев из коробки, просто используйте Json.format, который автоматически создает необходимые Reads и Writes. Поместите его в объект-компаньон для вашего класса case.

case class Location(val name: String, val id: Option[Long] = None)

object Location {
  implicit val locationFormat = Json.format[Location]
}

Затем используйте:

val withId = """{"name":"Bob","id":1234}"""
val withoutId = """{"name":"Charlie"}"""

val bob = Json.parse(withId).as[Location]
println(bob)
// Location(Bob,Some(1234))

val charlie = Json.parse(withoutId).as[Location]
println(charlie)
// Location(Charlie,None)
person engineerC    schedule 09.10.2016
comment
Уфф... зачем тогда эти страницы: playframework.com/documentation/2.5.x /ScalaJsonHttp (есть больше страниц). Это имеет смысл, но... - person ; 09.10.2016
comment
Вы правы, в документах format должно быть более заметно. Я обнаружил, что это все, что вам нужно большую часть времени. - person engineerC; 09.10.2016