Scala Language
JSON
Suche…
JSON mit Spray-Json
spray-json bietet eine einfache Möglichkeit, mit JSON zu arbeiten. Bei Verwendung impliziter Formate geschieht alles "hinter den Kulissen":
Machen Sie die Bibliothek mit SBT verfügbar
So verwalten Sie spray-json
mit verwalteten SBT-Bibliotheksabhängigkeiten :
libraryDependencies += "io.spray" %% "spray-json" % "1.3.2"
Beachten Sie, dass der letzte Parameter, die Versionsnummer ( 1.3.2
), in verschiedenen Projekten unterschiedlich sein kann.
Die spray-json
Bibliothek wird auf repo.spray.io gehostet.
Importieren Sie die Bibliothek
import spray.json._
import DefaultJsonProtocol._
Das Standard-JSON-Protokoll DefaultJsonProtocol
enthält Formate für alle DefaultJsonProtocol
. Verwenden Sie zur Bereitstellung der JSON-Funktionalität für benutzerdefinierte Typen entweder Convenience Builder für Formate oder explizit Schreibformate.
Lesen Sie JSON
// generates an intermediate JSON representation (abstract syntax tree)
val res = """{ "foo": "bar" }""".parseJson // JsValue = {"foo":"bar"}
res.convertTo[Map[String, String]] // Map(foo -> bar)
Schreibe JSON
val values = List("a", "b", "c")
values.toJson.prettyPrint // ["a", "b", "c"]
DSL
DSL wird nicht unterstützt.
Schreib-Lese-Fallklassen
Das folgende Beispiel zeigt, wie ein Fallklassenobjekt in das JSON-Format serialisiert wird.
case class Address(street: String, city: String)
case class Person(name: String, address: Address)
// create the formats and provide them implicitly
implicit val addressFormat = jsonFormat2(Address)
implicit val personFormat = jsonFormat2(Person)
// serialize a Person
Person("Fred", Address("Awesome Street 9", "SuperCity"))
val fredJsonString = fred.toJson.prettyPrint
Dies führt zu folgendem JSON:
{
"name": "Fred",
"address": {
"street": "Awesome Street 9",
"city": "SuperCity"
}
}
Diese JSON kann wiederum in ein Objekt deserialisiert werden:
val personRead = fredJsonString.parseJson.convertTo[Person]
//Person(Fred,Address(Awesome Street 9,SuperCity))
Benutzerdefiniertes Format
Schreiben Sie ein benutzerdefiniertes JsonFormat
wenn eine spezielle Serialisierung eines Typs erforderlich ist. Zum Beispiel, wenn die Feldnamen in Scala anders sind als in JSON. Oder wenn unterschiedliche konkrete Typen basierend auf der Eingabe instanziiert werden.
implicit object BetterPersonFormat extends JsonFormat[Person] {
// deserialization code
override def read(json: JsValue): Person = {
val fields = json.asJsObject("Person object expected").fields
Person(
name = fields("name").convertTo[String],
address = fields("home").convertTo[Address]
)
}
// serialization code
override def write(person: Person): JsValue = JsObject(
"name" -> person.name.toJson,
"home" -> person.address.toJson
)
}
JSON mit Circe
Circe stellt abgeleitete Codecs zur Kompilierzeit für en / decode json in Fallklassen bereit. Ein einfaches Beispiel sieht so aus:
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
case class User(id: Long, name: String)
val user = User(1, "John Doe")
// {"id":1,"name":"John Doe"}
val json = user.asJson.noSpaces
// Right(User(1L, "John Doe"))
val res: Either[Error, User] = decode[User](json)
JSON mit Play-Json
play-json verwendet implizite Formate als andere Json-Frameworks
SBT-Abhängigkeit: libraryDependencies += ""com.typesafe.play" %% "play-json" % "2.4.8"
import play.api.libs.json._
import play.api.libs.functional.syntax._ // if you need DSL
DefaultFormat
enthält Standardformate zum Lesen / Schreiben aller Basistypen. Um JSON-Funktionen für Ihre eigenen Typen bereitzustellen, können Sie Convenience Builder für Formate verwenden oder explizit Schreibformate verwenden.
Lesen Sie Json
// generates an intermediate JSON representation (abstract syntax tree)
val res = Json.parse("""{ "foo": "bar" }""") // JsValue = {"foo":"bar"}
res.as[Map[String, String]] // Map(foo -> bar)
res.validate[Map[String, String]] //JsSuccess(Map(foo -> bar),)
Schreibe json
val values = List("a", "b", "c")
Json.stringify(Json.toJson(values)) // ["a", "b", "c"]
DSL
val json = parse("""{ "foo": [{"foo": "bar"}]}""")
(json \ "foo").get //Simple path: [{"foo":"bar"}]
(json \\ "foo") //Recursive path:List([{"foo":"bar"}], "bar")
(json \ "foo")(0).get //Index lookup (for JsArrays): {"foo":"bar"}
Wie immer bevorzugen Sie den Musterabgleich mit JsSuccess
/ JsError
und versuchen Sie, .get
und array(i)
-Aufrufe zu vermeiden.
Lesen und schreiben Sie in die Fallklasse
case class Address(street: String, city: String)
case class Person(name: String, address: Address)
// create the formats and provide them implicitly
implicit val addressFormat = Json.format[Address]
implicit val personFormat = Json.format[Person]
// serialize a Person
val fred = Person("Fred", Address("Awesome Street 9", "SuperCity"))
val fredJsonString = Json.stringify(Json.toJson(Json.toJson(fred)))
val personRead = Json.parse(fredJsonString).as[Person] //Person(Fred,Address(Awesome Street 9,SuperCity))
Eigenes Format
Sie können Ihr eigenes JsonFormat schreiben, wenn Sie eine spezielle Serialisierung Ihres Typs benötigen (z. B. die Felder in scala und Json anders benennen oder verschiedene konkrete Typen basierend auf der Eingabe instanziieren).
case class Address(street: String, city: String)
// create the formats and provide them implicitly
implicit object AddressFormatCustom extends Format[Address] {
def reads(json: JsValue): JsResult[Address] = for {
street <- (json \ "Street").validate[String]
city <- (json \ "City").validate[String]
} yield Address(street, city)
def writes(x: Address): JsValue = Json.obj(
"Street" -> x.street,
"City" -> x.city
)
}
// serialize an address
val address = Address("Awesome Street 9", "SuperCity")
val addressJsonString = Json.stringify(Json.toJson(Json.toJson(address)))
//{"Street":"Awesome Street 9","City":"SuperCity"}
val addressRead = Json.parse(addressJsonString).as[Address]
//Address(Awesome Street 9,SuperCity)
Alternative
Wenn der Json nicht genau mit Ihren isAlive
( isAlive
in is_alive
vs is_alive
in is_alive
):
case class User(username: String, friends: Int, enemies: Int, isAlive: Boolean)
object User {
import play.api.libs.functional.syntax._
import play.api.libs.json._
implicit val userReads: Reads[User] = (
(JsPath \ "username").read[String] and
(JsPath \ "friends").read[Int] and
(JsPath \ "enemies").read[Int] and
(JsPath \ "is_alive").read[Boolean]
) (User.apply _)
}
Json mit optionalen Feldern
case class User(username: String, friends: Int, enemies: Int, isAlive: Option[Boolean])
object User {
import play.api.libs.functional.syntax._
import play.api.libs.json._
implicit val userReads: Reads[User] = (
(JsPath \ "username").read[String] and
(JsPath \ "friends").read[Int] and
(JsPath \ "enemies").read[Int] and
(JsPath \ "is_alive").readNullable[Boolean]
) (User.apply _)
}
Zeitstempel von Json lesen
Stellen Sie sich vor, Sie haben ein Json-Objekt mit einem Unix-Zeitstempelfeld:
{
"field": "example field",
"date": 1459014762000
}
Lösung:
case class JsonExampleV1(field: String, date: DateTime)
object JsonExampleV1{
implicit val r: Reads[JsonExampleV1] = (
(__ \ "field").read[String] and
(__ \ "date").read[DateTime](Reads.DefaultJodaDateReads)
)(JsonExampleV1.apply _)
}
Kundenspezifische Fallklassen lesen
Wenn Sie nun Ihre Objektkennungen für die Typsicherheit einpacken, werden Sie dies genießen. Siehe das folgende Json-Objekt:
{
"id": 91,
"data": "Some data"
}
und die entsprechenden Fallklassen:
case class MyIdentifier(id: Long)
case class JsonExampleV2(id: MyIdentifier, data: String)
Jetzt müssen Sie nur noch den primitiven Typ (Long) lesen und Ihrer ID zuordnen:
object JsonExampleV2 {
implicit val r: Reads[JsonExampleV2] = (
(__ \ "id").read[Long].map(MyIdentifier) and
(__ \ "data").read[String]
)(JsonExampleV2.apply _)
}
Code unter https://github.com/pedrorijo91/scala-play-json-examples
JSON mit Json4s
Json4s verwendet implizite Formate als andere Json-Frameworks.
SBT-Abhängigkeit:
libraryDependencies += "org.json4s" %% "json4s-native" % "3.4.0"
//or
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.4.0"
Importe
import org.json4s.JsonDSL._
import org.json4s._
import org.json4s.native.JsonMethods._
implicit val formats = DefaultFormats
DefaultFormats
enthält Standardformate zum Lesen / Schreiben aller DefaultFormats
.
Lesen Sie Json
// generates an intermediate JSON representation (abstract syntax tree)
val res = parse("""{ "foo": "bar" }""") // JValue = {"foo":"bar"}
res.extract[Map[String, String]] // Map(foo -> bar)
Schreibe json
val values = List("a", "b", "c")
compact(render(values)) // ["a", "b", "c"]
DSL
json \ "foo" //Simple path: JArray(List(JObject(List((foo,JString(bar))))))
json \\ "foo" //Recursive path: ~List([{"foo":"bar"}], "bar")
(json \ "foo")(0) //Index lookup (for JsArrays): JObject(List((foo,JString(bar))))
("foo" -> "bar") ~ ("field" -> "value") // {"foo":"bar","field":"value"}
Lesen und schreiben Sie in die Fallklasse
import org.json4s.native.Serialization.{read, write}
case class Address(street: String, city: String)
val addressString = write(Address("Awesome stree", "Super city"))
// {"street":"Awesome stree","city":"Super city"}
read[Address](addressString) // Address(Awesome stree,Super city)
//or
parse(addressString).extract[Address]
Lesen und Schreiben von heterogenen Listen
Um eine heterogene (oder polymorphe) Liste zu serialisieren und zu deserialisieren, müssen bestimmte Typhinweise angegeben werden.
trait Location
case class Street(name: String) extends Location
case class City(name: String, zipcode: String) extends Location
case class Address(street: Street, city: City) extends Location
case class Locations (locations : List[Location])
implicit val formats = Serialization.formats(ShortTypeHints(List(classOf[Street], classOf[City], classOf[Address])))
val locationsString = write(Locations(Street("Lavelle Street"):: City("Super city","74658")))
read[Locations](locationsString)
Eigenes Format
class AddressSerializer extends CustomSerializer[Address](format => (
{
case JObject(JField("Street", JString(s)) :: JField("City", JString(c)) :: Nil) =>
new Address(s, c)
},
{
case x: Address => ("Street" -> x.street) ~ ("City" -> x.city)
}
))
implicit val formats = DefaultFormats + new AddressSerializer
val str = write[Address](Address("Awesome Stree", "Super City"))
// {"Street":"Awesome Stree","City":"Super City"}
read[Address](str)
// Address(Awesome Stree,Super City)