Buscar..


JSON con spray-json

spray-json proporciona una manera fácil de trabajar con JSON. Usando formatos implícitos, todo sucede "detrás de escena":

Haga que la biblioteca esté disponible con SBT

Para administrar spray-json con las dependencias de la biblioteca administrada SBT :

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

Tenga en cuenta que el último parámetro, el número de versión ( 1.3.2 ), puede ser diferente en diferentes proyectos.

La biblioteca spray-json está alojada en repo.spray.io .

Importar la biblioteca

import spray.json._
import DefaultJsonProtocol._

El protocolo JSON predeterminado DefaultJsonProtocol contiene formatos para todos los tipos básicos. Para proporcionar la funcionalidad JSON para tipos personalizados, use los constructores de conveniencia para los formatos o los formatos de escritura explícitamente.

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

Escribir json

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

DSL

DSL no es compatible.

Lectura-escritura a clases de casos

El siguiente ejemplo muestra cómo serializar un objeto de clase de caso en el formato JSON.

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

Esto resulta en el siguiente JSON:

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

Ese JSON puede, a su vez, deserializarse de nuevo en un objeto:

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

Formato personalizado

Escriba un JsonFormat personalizado si se JsonFormat una serialización especial de un tipo. Por ejemplo, si los nombres de campo son diferentes en Scala que en JSON. O, si diferentes tipos de concreto son instanciados basados ​​en la entrada.

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

Circe proporciona códecs derivados de tiempo de compilación para en / decode json en clases de casos. Un ejemplo simple se ve así:

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

play-json usa formatos implícitos como otros frameworks json

Dependencia de SBT: 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 contiene formatos predeterminados para leer / escribir todos los tipos básicos. Para proporcionar la funcionalidad JSON para sus propios tipos, puede usar constructores de conveniencia para formatos o escribir formatos explícitamente.

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

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

Como siempre, prefiera la coincidencia de patrones con JsSuccess / JsError e intente evitar las .get , array(i) .

Leer y escribir a clase de caso

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

Formato propio

Puede escribir su propio JsonFormat si necesita una serialización especial de su tipo (por ejemplo, nombre los campos de forma diferente en scala y Json o ejemplifique diferentes tipos concretos en función de la entrada)

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)

Alternativa

Si el json no coincide exactamente con los campos de su clase de caso ( isAlive en la clase de caso vs is_alive en 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 con campos opcionales

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

Lectura de marcas de tiempo de json

Imagina que tienes un objeto Json, con un campo de marca de tiempo Unix:

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

solución:

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

Leer clases de casos personalizados

Ahora, si envuelve sus identificadores de objetos para la seguridad de tipos, disfrutará esto. Vea el siguiente objeto json:

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

y las clases de casos correspondientes:

case class MyIdentifier(id: Long)

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

Ahora solo necesita leer el tipo primitivo (Largo) y asignarlo a su idenfier:

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

código en https://github.com/pedrorijo91/scala-play-json-examples

JSON con json4s

json4s usa formatos implícitos como otros frameworks json.

Dependencia de SBT:

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

Importaciones

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

implicit val formats = DefaultFormats

DefaultFormats contiene formatos predeterminados para leer / escribir todos los tipos básicos.

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

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

Leer y escribir a clase de caso

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]

Leer y escribir listas heterogéneas

Para serializar y deserializar una lista heterogénea (o polimórfica), se deben proporcionar sugerencias de tipo específicas.

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)

Formato propio

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow