Какая библиотека сериализации JSON подойдет для следующего случая? - PullRequest
2 голосов
/ 26 января 2011

У меня есть следующий случай: я хотел бы сериализовать классы случаев Scala, которые расширяют родительский класс с помощью переменной типа java.util.UUID.Сериализация классов этого случая должна происходить без какой-либо их конфигурации - без аннотаций и определения пользовательских форматов.Любые подсказки сериализации могут находиться в родительском классе.

Я пробовал sjson, но сериализация на основе отражений не может сериализовать типы UUID, и сериализация на основе типов вынуждает меня определять форматы для каждого класса дел.Какая библиотека сериализации json лучше всего подходит для этого случая?

Ответы [ 4 ]

4 голосов
/ 26 января 2011

Вот одно решение с Lift JSON .

import java.util.UUID
import net.liftweb.json._
import net.liftweb.json.JsonAST._
import net.liftweb.json.JsonDSL._
import net.liftweb.json.Serialization._

sealed abstract class Parent {
  def uuid: UUID
}
case class Foo(uuid: UUID, name: String) extends Parent

object UUIDTest extends Application {
  implicit val formats =  Serialization.formats(NoTypeHints) + new UUIDSerializer

  val f = Foo(UUID.randomUUID, "foo")
  val ser = write(f)
  println(ser)
  val f2 = read[Foo](ser)
  assert(f == f2)

  // Special serializer for UUID type
  class UUIDSerializer extends Serializer[UUID] {
    private val Class = classOf[UUID]

    def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), UUID] = {
      case (TypeInfo(Class, _), json) => json match {
        case JObject(JField("mostSig", JInt(m)) :: JField("leastSig", JInt(l)) :: Nil) =>
          new UUID(m.longValue, l.longValue)
        case x => throw new MappingException("Can't convert " + x + " to UUID")
      }
    }

    def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case x: UUID =>
        ("mostSig" -> x.getMostSignificantBits) ~ ("leastSig" -> x.getLeastSignificantBits)
    }
  }
}

Он печатает:

{"uuid":{"mostSig":-8054689529719995935,"leastSig":-5722404370736228056},"name":"foo"}'

Другое решение, которое использует пользовательский сериализатор для родительского типа.

sealed abstract class Parent {
  var uuid: UUID = UUID.randomUUID
}
case class Foo(name: String) extends Parent

object UUIDTest extends Application {
  implicit val formats = 
    Serialization.formats(NoTypeHints) + new ParentSerializer

  val f = Foo("foo")
  val ser = write(f)
  println(ser)
  val f2 = read[Foo](ser)
  assert(f == f2)

  // Special serializer for Parent type
  class ParentSerializer extends Serializer[Parent] {
    def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Parent] = {
      case (t@TypeInfo(cl, _), json) if (classOf[Parent].isAssignableFrom(cl)) => 
        val x = Extraction.extract(json, t)(DefaultFormats).asInstanceOf[Parent]
        x.uuid = (for { 
          JField("mostSig", JInt(m))  <- json
          JField("leastSig", JInt(l)) <- json 
        } yield new UUID(m.longValue, l.longValue)).head
        x
    }

    def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case x: Parent =>
        Extraction.decompose(x)(DefaultFormats) ++ 
        JField("mostSig", x.uuid.getMostSignificantBits) ++ 
        JField("leastSig", x.uuid.getLeastSignificantBits)
    }
  }
}
2 голосов
/ 26 января 2011

Вы можете попробовать jerkson: https://github.com/codahale/jerkson

Это хорошо работает для моего использования, но это в основном структуры списка / карты.Не удивлюсь, если он поддержит ваши потребности, хотя ..

Редактировать: Попробовал это на следующем примере (вдохновленный примером подъема в другом ответе).Кажется, работает нормально.

import java.util.UUID
import com.codahale.jerkson.Json
import org.scalatest.FunSuite

sealed abstract class Parent {
   def uuid: UUID
}

case class Foo(uuid: UUID, name: String) extends Parent

class TmpJsonTest extends FunSuite {
   test("Json case class serialize") {
      val f = Foo(UUID.randomUUID, "foo")
      val ser = Json.generate(f)
      println(ser)
      val f2 = Json.parse[Foo](ser)
      assert(f === f2)
   }
}
2 голосов
/ 26 января 2011

Попробуйте библиотеку XStream , которая включает поддержку JSON. Я успешно использовал это в нескольких проектах. Он имеет несколько конвертеров по умолчанию, в том числе один для java.util.UUID. Полный список конвертеров по умолчанию находится здесь: http://x -stream.github.io / converters.html .

Краткое руководство по использованию XStream для чтения и записи JSON находится здесь: http://x -stream.github.io / json-tutorial.html . Код учебника написан для Java, но он должен работать точно так же и для Scala, поскольку отражение используется за кулисами.

Имейте в виду, что сериализация и последующая десериализация произвольных графов объектов не всегда возможны с этой библиотекой. В частности, петли в ваших данных не могут быть обработаны, то есть ваши данные должны быть чисто иерархическим деревом. Это разумное ограничение, учитывая намерения формата JSON.

Ссылочные ссылки:
Руководство по XStream JSON: http://x -stream.github.io / json-tutorial.html
Преобразователи по умолчанию XStream: http://x -stream.github.io / converters.html

2 голосов
/ 26 января 2011

Если тип важен, вы должны взглянуть на YAML.

http://www.google.fr/search?q=java+yaml

Это подмножество json с улучшенными вещами, такими как типизированная переменная.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...