Grafitti Rules: jugando con JSON [Snow]

Hace ya unos meses hablamos de Spray, un toolkit que nos permitía construir API’s REST de una forma sencilla con un DSL bastante completo.

Uno de los componentes que forman el toolkit es spray-json. Con este modulo podemos serializar y deserializar nuestros objetos a un formato JSON. Hoy vamos a ver como trabajar con él de forma muy rápida y sencilla.

¿Cómo crear los serializadores de las distintas clases? Pues existen dos opciones en función de cómo esté definida la clase que queramos serializar.

Opción fácil: cuando tenemos una case class

Esto está tirado. Lo único que tenemos que utilizar es el método jsonFormatN() donde N representa el número de argumentos que tiene el método apply de la case class. Veamos un ejemplo:

case class Character(name: String, family: String, isDead: Boolean)

object MyJsonProtocol extends DefaultJsonProtocol {

 implicit val characterFormat = jsonFormat3(Character.apply)

}

Como se puede ver, para crear un serializador para la case class Character creamos un valor implícito con la ayuda de jsonFormat3 (ya que tiene 3 atributos). Dicho objeto implícito lo definiremos dentro de un trait que extenderá de DefaultJsonProtocol. En este trait están definidos los serializadores para los tipos básicos de Scala: Int, String, Boolean … Fácil y sencillo.

tumblr_mfuulmem1p1qem4feo1_250

Opción menos fácil: cuando no tenemos una case class o queremos serializar una case class de una forma distinta.

En este caso, es necesario picarnos a mano como debe ser la serialización y la deserialización del tipo en cuestión. Para ello, es necesario crear un implicit object que extienda de RootJsonFormat[T] donde T es el tipo que se quiere serializar. Dicho trait contiene dos métodos a implementar. Por un lado existe un método write, que convierte un tipo T en un Json, y por otro lado un tipo read, que realiza el proceso inverso. A continuación vemos un ejemplo con el mismo tipo que antes:

class Character(val name: String, val family: String, val isDead: Boolean)

object MyJsonProtocol extends DefaultJsonProtocol {

  implicit object CharacterJsonFormat extends RootJsonFormat[Character] {

    def write(c: Character) =
      JsArray(JsString(c.name), JsString(c.family), JsBoolean(c.isDead))

    def read(value: JsValue) = value match {
      case JsArray(Vector(JsString(name), JsString(family), JsBoolean(isDead))) =>
        new Character(name, family, isDead.toBoolean)
      case _ => throw new DeserializationException("Character expected")
    }
  }
}

Como se puede observar, es un poco más tedioso pero no demasiado complicado.

¿Y cómo lo usamos? Basta con importar el objeto donde hemos definido los implícitos y realizar llamadas a los métodos toJson o convertTo[T].

import MyJsonProtocol._

val json = Character("Jon Snow", "Stark", ???).toJson //....You know nothing!!!!
// Returns {"name": "Jon Snow", "family": "Stark", "isDead": ???}
val jonSnow = json.convertTo[Character]

giphy

Además, si usamos la API REST de Spray, la transformación se hará de forma transparente y no será necesario llamar a toJson o convertTo de forma explícita. Pero esto para otro post. La semana que viene, se hará una pequeña mención a esta librería, por lo que no venía mal dar unas pequeñas pinceladas antes 🙂
Agur de limón!

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s