§JSON temelleri
Modern web uygulamaları sıklıkla JSON (JavaScript Object Notation) formatı içinde veriyi ayrıştırmaya ve oluşturmaya ihtiyaç duyar. Play JSON JSON kütüphanesi ile bunu destekler.
JSON hafif bir veri takas formatıdır ve aşağıdaki gibi görünür:
{
"name" : "Watership Down",
"location" : {
"lat" : 51.235685,
"long" : -1.309197
},
"residents" : [ {
"name" : "Fiver",
"age" : 4,
"role" : null
}, {
"name" : "Bigwig",
"age" : 6,
"role" : "Owsla"
} ]
}
JSON hakkında daha fazla bilgi almak json.org adresine bakabilirsiniz.
§Play JSON Kütüphanesi
play.api.libs.json
JSON verisi sunmak için gereken veri yapılarını ve bu veri yapıları ile
diğer veri sunuş biçimleri arasında çevrim yapmak için gerekli olaran araçları içerir. İlgili tipler:
§JsValue
Herhangi bir JSON değerini sunmak için var olan bir trait
’dir. JSON kütüphanesi geçerli JSON tiplerini gösterebilmek için JsValue
’den türetilmiş bir case class
’a sahiptir:
gibi çeşitli JsValue
tipleri kullanılır, sizde herhangi bir JSON yapısı oluşturabilirsiniz.
§Json
Json objesi gerekli yardımcı bileşenleri sağlar, öncelikli olarak JsValue yapıları arasındaki çevirme işlemleri içindir.
§JsPath
JsValue yapısın içine bir yol sunar, XML için olan XPath’e benzerdir. JsValue yapıları içersinde gezinmek için ve örtük dönüştürücüler için desenler içinde kullanılır.
§Bir JsValue’ye çevirmek
§String ayrıştırma kullanarak
import play.api.libs.json._
val json: JsValue = Json.parse("""
{
"name" : "Watership Down",
"location" : {
"lat" : 51.235685,
"long" : -1.309197
},
"residents" : [ {
"name" : "Fiver",
"age" : 4,
"role" : null
}, {
"name" : "Bigwig",
"age" : 6,
"role" : "Owsla"
} ]
}
""")
§Sınıf yapısı kullanarak
import play.api.libs.json._
val json: JsValue = JsObject(Seq(
"name" -> JsString("Watership Down"),
"location" -> JsObject(Seq("lat" -> JsNumber(51.235685), "long" -> JsNumber(-1.309197))),
"residents" -> JsArray(Seq(
JsObject(Seq(
"name" -> JsString("Fiver"),
"age" -> JsNumber(4),
"role" -> JsNull
)),
JsObject(Seq(
"name" -> JsString("Bigwig"),
"age" -> JsNumber(6),
"role" -> JsString("Owsla")
))
))
))
Json.obj
and Json.arr
yapıyı bir parça basitleştirebilir. Şunu unutmayın ki çoğu değer JsValue sınıf ile belirtik olarak sarmalanmaya ihtiyacı yoktur, fabrika metodları örtük dönüşüm kullanır (daha fazlası aşağıda).
import play.api.libs.json.{JsNull,Json,JsString,JsValue}
val json: JsValue = Json.obj(
"name" -> "Watership Down",
"location" -> Json.obj("lat" -> 51.235685, "long" -> -1.309197),
"residents" -> Json.arr(
Json.obj(
"name" -> "Fiver",
"age" -> 4,
"role" -> JsNull
),
Json.obj(
"name" -> "Bigwig",
"age" -> 6,
"role" -> "Owsla"
)
)
)
§Writes çeviricilerini kullanmak
Scala’dan JsValue’ye çevirme işlemi Json.toJson[T](T)(implicit writes: Writes[T])
yardımcı metodu ile gerçekleşir. Bu fonksiyonel bağlılık Writes[T]
tipi üzerindedir, T
değeri bir JsValue
değerine dönüştürülür.
Play JSON API temel tipler için örtülü olarak Writes
sağlar. Int
, Double
, String
ve Boolean
bunların içindedir. Aynı zamanda Writes
, Writes[T]
herhangi bir T
tipi ile var olan herhangi bir tip kolleksiyonunuda destekler.
import play.api.libs.json._
// basic types
val jsonString = Json.toJson("Fiver")
val jsonNumber = Json.toJson(4)
val jsonBoolean = Json.toJson(false)
// collections of basic types
val jsonArrayOfInts = Json.toJson(Seq(1, 2, 3, 4))
val jsonArrayOfStrings = Json.toJson(List("Fiver", "Bigwig"))
Kendi modellerinizi JsValues’e dönüştürebilirisiniz, örtülü olarak Writes
çeviricileri tanımlamalı ve kapsamın içinde olmasını sağlamalısınız.
case class Location(lat: Double, long: Double)
case class Resident(name: String, age: Int, role: Option[String])
case class Place(name: String, location: Location, residents: Seq[Resident])
import play.api.libs.json._
implicit val locationWrites = new Writes[Location] {
def writes(location: Location) = Json.obj(
"lat" -> location.lat,
"long" -> location.long
)
}
implicit val residentWrites = new Writes[Resident] {
def writes(resident: Resident) = Json.obj(
"name" -> resident.name,
"age" -> resident.age,
"role" -> resident.role
)
}
implicit val placeWrites = new Writes[Place] {
def writes(place: Place) = Json.obj(
"name" -> place.name,
"location" -> place.location,
"residents" -> place.residents)
}
val place = Place(
"Watership Down",
Location(51.235685, -1.309197),
Seq(
Resident("Fiver", 4, None),
Resident("Bigwig", 6, Some("Owsla"))
)
)
val json = Json.toJson(place)
Alternatif olarak birleştiren desenle kendiniz Writes
tanımlayabilirsiniz.
Not: Birleştiren desen konusu JSON Reads/Writes/Formats Combinators detaylı bir şekilde anlatılmıştır.
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val locationWrites: Writes[Location] = (
(JsPath \ "lat").write[Double] and
(JsPath \ "long").write[Double]
)(unlift(Location.unapply))
implicit val residentWrites: Writes[Resident] = (
(JsPath \ "name").write[String] and
(JsPath \ "age").write[Int] and
(JsPath \ "role").writeNullable[String]
)(unlift(Resident.unapply))
implicit val placeWrites: Writes[Place] = (
(JsPath \ "name").write[String] and
(JsPath \ "location").write[Location] and
(JsPath \ "residents").write[Seq[Resident]]
)(unlift(Place.unapply))
§Bir JsValue yapısında gezinme
Bir JsValue
yapısında gezinebilir ve belirli değerleri alabilirsiniz. Sözdizim ve fonksiyonellik olarak Scala XML işlemeye benzerdir.
Not: Aşağıdaki örnekler bir önceki örnekte oluşturulan JsValue yapısına uygulanmıştır.
§Basit yol \
Bir JsValue
’ye \
operatörünü uygulamak bunun bir JsObject olduğunu farz edersek alan argümanına eş olan özelliği döndürecektir.
val lat = json \ "location" \ "lat"
// returns JsNumber(51.235685)
§Rekürsif yol \\
\\
operatörünü uygulamak mevcut objede ve aynı soydan olanlarda alan için bir arama yapacaktır.
val names = json \\ "name"
// returns Seq(JsString("Watership Down"), JsString("Fiver"), JsString("Bigwig"))
§İndeks bakınma (JsArray’lar için)
apply operatörü ile indeks numarası kullanarak Bir JsArray
içindeki değere ulaşabilirisiniz.
val bigwig = (json \ "residents")(1)
// returns {"name":"Bigwig","age":6,"role":"Owsla"}
§Bir JsValue’den çevirmek
§String yardımcıları kullanarak
Küçültülmüş:
val minifiedString: String = Json.stringify(json)
{"name":"Watership Down","location":{"lat":51.235685,"long":-1.309197},"residents":[{"name":"Fiver","age":4,"role":null},{"name":"Bigwig","age":6,"role":"Owsla"}]}
Okunabilir:
val readableString: String = Json.prettyPrint(json)
{
"name" : "Watership Down",
"location" : {
"lat" : 51.235685,
"long" : -1.309197
},
"residents" : [ {
"name" : "Fiver",
"age" : 4,
"role" : null
}, {
"name" : "Bigwig",
"age" : 6,
"role" : "Owsla"
} ]
}
§JsValue.as/asOpt kullanmak
Bir JsValue
’yi başka tipe çevirmenin en kolay yolu JsValue.as[T](implicit fjs: Reads[T]): T
kullanmaktır. Bir JsValue
’yi T
tipine çevirmek için (Writes[T]
’nin tersi) Reads[T]
tipinde bir örtülü çevirici olması zorunludur. Writes
ile JSON API temel tipler için Reads
sağlar.
val name = (json \ "name").as[String]
// "Watership Down"
val names = (json \\ "name").map(_.as[String])
// Seq("Watership Down", "Fiver", "Bigwig")
Eğer yol bulunamazsa yada çevirme imkansızsa, as
metodu bir JsResultException
fırlatacaktır. JsValue.asOpt[T](implicit fjs: Reads[T]): Option[T]
güvenli bir metoddur.
val nameOption = (json \ "name").asOpt[String]
// Some("Watership Down")
val bogusOption = (json \ "bogus").asOpt[String]
// None
Buna rağman asOpt
metodu daha güvenlidir, herhangi bir hata bilgisi kaybolmaz.
§Doğrulama Kullanmak
Bir JsValue
’den başka bir tipe dönüştürmek için tercih edilen yol validate
metodunun kullanılmasıdır (Reads
tipinde bir argüman alır). Bu hem doğrulama hem de çevirme işlemini sağlar, JsResult
tipinde bir sonuç döndürür. JsResult
iki sınıf tarafından uygulanmıştır:
JsSuccess
- Başarılı doğrulama/çevirme sunar ve sonucu sarmalar.JsError
- Başarısız doğrulama/çevirme sunar ve doğrulama hatalarının bir listesini içerir.
Doğrulama sonucunu işlemek için çeşitli desenler uygulayabilirsiniz:
val json = { ... }
val nameResult: JsResult[String] = (json \ "name").validate[String]
// Pattern matching
nameResult match {
case s: JsSuccess[String] => println("Name: " + s.get)
case e: JsError => println("Errors: " + JsError.toFlatJson(e).toString())
}
// Fallback value
val nameOrFallback = nameResult.getOrElse("Undefined")
// map
val nameUpperResult: JsResult[String] = nameResult.map(_.toUpperCase())
// fold
val nameOption: Option[String] = nameResult.fold(
invalid = {
fieldErrors => fieldErrors.foreach(x => {
println("field: " + x._1 + ", errors: " + x._2)
})
None
},
valid = {
name => Some(name)
}
)
§JsValue’den bir modele
JsValue’den bir modele çevirmek için, örtülü bir Reads[T]
tanımlamalısınız. T
sizin modelinizin tipini gösterir.
Not: Desen
Reads
’i uygulaman için kullanılır, özelliştirilmiş doğrulama JSON Reads/Writes/Formats Combinators konusunda anlatılmıştır.
case class Location(lat: Double, long: Double)
case class Resident(name: String, age: Int, role: Option[String])
case class Place(name: String, location: Location, residents: Seq[Resident])
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val locationReads: Reads[Location] = (
(JsPath \ "lat").read[Double] and
(JsPath \ "long").read[Double]
)(Location.apply _)
implicit val residentReads: Reads[Resident] = (
(JsPath \ "name").read[String] and
(JsPath \ "age").read[Int] and
(JsPath \ "role").readNullable[String]
)(Resident.apply _)
implicit val placeReads: Reads[Place] = (
(JsPath \ "name").read[String] and
(JsPath \ "location").read[Location] and
(JsPath \ "residents").read[Seq[Resident]]
)(Place.apply _)
val json = { ... }
val placeResult: JsResult[Place] = json.validate[Place]
// JsSuccess(Place(...),)
val residentResult: JsResult[Resident] = (json \ "residents")(1).validate[Resident]
// JsSuccess(Resident(Bigwig,6,Some(Owsla)),)
Sonraki: HTTP ile JSON
Dokümantasyonun bu çevirisi Play ekibi tarafından yapılmamaktadır. Eğer bir hata bulduysanız, bu sayfanın kaynak kodu burada bulunmaktadır. Dokümantasyon yönergelerini okuduktan sonra lütfen katkı yapmaktan çekinmeyin.