Zoeken…


JSON met spray-json

spray-json biedt een eenvoudige manier om met JSON te werken. Met impliciete formaten gebeurt alles "achter de schermen":

Maak de bibliotheek beschikbaar met SBT

spray-json beheren met SBT-beheerde bibliotheekafhankelijkheden :

libraryDependencies += "io.spray" %% "spray-json" % "1.3.2"

Merk op dat de laatste parameter, het versienummer ( 1.3.2 ), in verschillende projecten anders kan zijn.

De spray-json bibliotheek wordt gehost op repo.spray.io .

Importeer de bibliotheek

import spray.json._
import DefaultJsonProtocol._

Het standaard JSON-protocol DefaultJsonProtocol bevat indelingen voor alle basistypen. Om JSON-functionaliteit voor aangepaste typen te bieden, gebruikt u gemaksmakers voor indelingen of schrijft u indelingen expliciet.

Lees 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)

Schrijf JSON

val values = List("a", "b", "c")
values.toJson.prettyPrint // ["a", "b", "c"]

DSL

DSL wordt niet ondersteund.

Lezen en schrijven naar casusklassen

Het volgende voorbeeld laat zien hoe een case-klasseobject in de JSON-indeling moet worden geserialiseerd.

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

Dit resulteert in de volgende JSON:

{
  "name": "Fred",
  "address": {
    "street": "Awesome Street 9",
    "city": "SuperCity"
  }
}

Dat JSON op zijn beurt weer kan worden gedeserialiseerd in een object:

val personRead = fredJsonString.parseJson.convertTo[Person] 
//Person(Fred,Address(Awesome Street 9,SuperCity))

Aangepast formaat

Schrijf een aangepast JsonFormat als een speciale serialisatie van een type vereist is. Als de veldnamen bijvoorbeeld in Scala anders zijn dan in JSON. Of, als verschillende betonsoorten worden geconcretiseerd op basis van de invoer.

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 met Circe

Circe biedt compilatie-tijd afgeleide codecs voor en / decoderen json in case-klassen. Een eenvoudig voorbeeld ziet er zo uit:

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 met play-json

play-json gebruikt impliciete formaten als andere json-frameworks

SBT-afhankelijkheid: 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 bevat standaardformaten om alle basistypes te lezen / schrijven. Om JSON-functionaliteit voor uw eigen typen te bieden, kunt u ofwel gemaksmakers voor formaten gebruiken of expliciet formaten schrijven.

Lees 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),)

Schrijf 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"}

Zoals altijd de voorkeur aan patroonherkenning tegen JsSuccess / JsError en probeer te voorkomen .get , array(i) gesprekken.

Lees en schrijf naar case-klasse

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))

Eigen indeling

U kunt uw eigen JsonFormat schrijven als u een speciale serialisatie van uw type nodig hebt (bijvoorbeeld de velden anders in scala en Json anders benoemen of verschillende betonsoorten instantiëren op basis van de invoer)

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)

Alternatief

Als de json niet exact overeenkomt met de velden van uw isAlive ( isAlive in case class versus is_alive in json):

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 met optionele velden

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 _)
}

Tijdstempels lezen van json

Stel je voor dat je een Json-object hebt, met een Unix-tijdstempelveld:

{
  "field": "example field",
  "date": 1459014762000
}

oplossing:

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 _)
}

Aangepaste case-klassen lezen

Nu, als u uw object-ID's voor typeveiligheid inpakt, zult u hiervan genieten. Zie het volgende json-object:

{
  "id": 91,
  "data": "Some data"
}

en de bijbehorende case-klassen:

case class MyIdentifier(id: Long)

case class JsonExampleV2(id: MyIdentifier, data: String)

Nu hoeft u alleen het primitieve type (lang) te lezen en toe te wijzen aan uw identiteit:

object JsonExampleV2 {
  implicit val r: Reads[JsonExampleV2] = (
      (__ \ "id").read[Long].map(MyIdentifier) and
    (__ \ "data").read[String]
    )(JsonExampleV2.apply _)
}

code op https://github.com/pedrorijo91/scala-play-json-examples

JSON met json4s

json4s gebruikt impliciete formaten als andere json-frameworks.

SBT-afhankelijkheid:

libraryDependencies += "org.json4s" %% "json4s-native" % "3.4.0"
//or
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.4.0"

invoer

import org.json4s.JsonDSL._
import org.json4s._
import org.json4s.native.JsonMethods._

implicit val formats = DefaultFormats

DefaultFormats bevat standaardindelingen om alle basistypes te lezen / schrijven.

Lees 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)

Schrijf 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"}

Lees en schrijf naar case-klasse

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]

Lees en schrijf heterogene lijsten

Om een heterogene (of polymorfe) lijst te serialiseren en te deserialiseren, moeten specifieke type-hints worden verstrekt.

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)

Eigen indeling

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow