Какую библиотеку JSON использовать при хранении объектов case?

Мне нужно сериализовать события akka в json. На основе «Какую библиотеку JSON использовать в Scala?" я попытался несколько библиотек. Поскольку мой сериализатор ничего не должен знать обо всех моих конкретных событиях, события, состоящие из классов case и объектов case, должны быть сериализованы с использованием отражения. json4s лучше всего соответствует моим требованиям.

class Json4sEventAdapter(system: ExtendedActorSystem) extends EventAdapter {
  implicit val formats = Serialization.formats(FullTypeHints(List(classOf[Evt])))
  override def toJournal(event: Any): Any = event match {
case e: AnyRef =>
  write(e).getBytes(Charsets.UTF_8)}

override def fromJournal(event: Any, manifest: String): EventSeq = event match {
case e: Array[Byte] => {
      EventSeq.single(read[Evt](new String(e.map(_.toChar))))}}

Проблема с использованием json4s заключается в том, что независимо от того, какая реализация используется, десериализация объектов создает разные экземпляры. Поскольку мы активно используем сопоставление с образцом для объекта case, это ломает весь наш существующий код.

Итак, мой вопрос: какую библиотеку JSON можно использовать с постоянством scala и akka при хранении объектов case?

Есть ли хотя бы одна библиотека, которая правильно обрабатывает десериализацию объектов case через отражение? - или у кого-нибудь есть хороший обходной путь?


person Beat Sager    schedule 27.07.2015    source источник


Ответы (2)


Я не могу комментировать Json4s, так как я никогда не использовал его, но я знаю, что это не проблема в play-json. Вы бы сделали что-то вроде:

import play.api.libs.json._

sealed trait MyEventBase
case object MyEvent extends MyEventBase

implicit val myEventBaseFormat: Format[MyEventBase] = Format(Reads.StringReads.collect(ValidationError("must be the string `MyEvent`") {
  case "MyEvent" => MyEvent
}, Writes.pure("MyEvent"))

В этом случае сериализация осуществляется в пустую строку, поэтому я использую встроенный StringReads, чтобы утверждать, что элемент должен быть десериализуем в строку, а затем использую collect, чтобы сузить его до конкретной строки. Но основная идея заключается в том, что вы предоставляете конкретное значение, которое хотите вернуть после десериализации в своем экземпляре Reads. Здесь это синглтон case object. Итак, всякий раз, когда вы десериализуете MyEventBase, что приводит к MyEvent, вы обязательно получите тот же экземпляр обратно.

В реальном мире у MyEventBase, вероятно, есть другие подтипы, и поэтому вы структурируете свой экземпляр Writes, чтобы создать некоторую форму тега типа для сериализации, от которой ваш экземпляр Reads может отказаться для десериализации в правильный подтип. Например, вы можете сериализовать объект JSON вместо пустой строки, и этот объект будет иметь поле type, которое идентифицирует подтип. Или просто используйте что-то вроде Play JSON Extensions, чтобы автоматически синтезировать разумное Format для вашего sealed trait .

person acjay    schedule 02.11.2015

Я настоятельно рекомендую вам взглянуть на Stamina. Он был реализован для решения большинства обычных проблем, с которыми вы столкнетесь при работе с akka-persistence.

Он предоставляет сериализатор json (на основе spray-json и shapeless), который поддерживает управление версиями, автоматическую миграцию во время чтения, а также набор тестов, чтобы гарантировать, что все старые версии постоянных событий по-прежнему доступны для чтения.

person Pascal Rodriguez    schedule 02.08.2016