Json ke kelas kasus dengan Option[Long]

Pertimbangkan kelas kasus ini

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

Saya bisa menulis "toJson" seperti ini:

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

tapi saya kesulitan dengan "fromJson":

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

Penjelasan: Id sebenarnya harus disetel oleh lapisan persistensi, jadi saya tidak ingin memberikannya secara manual.

Saya juga mencoba:

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

tapi sayangnya kemudian saya mendapatkan:

Tidak ditemukan deserializer Json untuk tipe Option[Long]. Cobalah untuk menerapkan Bacaan atau Format implisit untuk jenis ini.

Apakah saya benar-benar perlu membuat implisit untuk itu juga?

Kenapa ini bisa berhasil (seperti dalam: kompilasi)? Saya bertanya karena itu sangat sepele bagi manusia, namun tiba-tiba ada yang tersirat dan terkompilasi. Meskipun aku tidak yakin apakah ini masuk akal, tapi aku khawatir tidak

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

edit: jelas tidak masuk akal.

Jika saya mengirim curl --include --request POST --header "Content-type:application/json" --data '{"name": "Gondor", "id": "2"}' localhost:9000 saya mendapatkan:

HTTP/1.1 500 Kesalahan Server Internal
Panjang Konten: 8029
Tipe Konten: teks/html; charset=utf-8
Tanggal: Sabtu, 08 Okt 2016 21:49:51 GMT

Saya juga tidak bisa membiarkan id kosong :(


person Community    schedule 08.10.2016    source sumber


Jawaban (4)


Play Framework mendukung bidang Option di luar kotak.

Anda harus menggunakan readNullable[Long], bukan read[Option[Long]].

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

Anda juga dapat menggunakan writeNullable[Long] di locationWrites Anda.

Dengan write[Option[Long]] json yang dihasilkan akan berisi id bidang yang disetel ke null jika id adalah None. Dengan bidang writeNullable[Long] id tidak akan ada sama sekali untuk kasus 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

Tidak yakin mengapa json lib tidak mendukung Option secara langsung, coba ini:

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

Tampaknya mereka mendukungnya, coba ini:

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

yay dsls kurasa.

Atau gunakan perpustakaan json yang lebih canggih, mis. http://argonaut.io/ + https://github.com/alexarchambault/argonaut-takberbentuk atau https://travisbrown.github.io/circe/

person Reactormonk    schedule 08.10.2016

data yang Anda kirim adalah "id": "2" , itu adalah string. Kalau mau kirim Long, saya rasa coba "id": 2

person manish    schedule 09.10.2016

Play json mendukung pembuatan fungsi serialisasi/deserialisasi otomatis untuk kelas kasus, cukup gunakan Json.format yang secara otomatis membuat Reads dan Writes yang diperlukan. Letakkan di objek pendamping untuk kelas kasus Anda.

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

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

Kemudian gunakan:

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
Uff... kenapa ada halaman ini: playframework.com/documentation/2.5.x /ScalaJsonHttp (ada lebih banyak halaman). Itu masuk akal, tapi... - person ; 09.10.2016
comment
Anda benar, dokumen harus menyebutkan format dengan lebih jelas. Saya telah menemukan bahwa itulah yang paling Anda perlukan sepanjang waktu. - person engineerC; 09.10.2016