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)


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow