Лучшее обходное решение для неявных и проблем с заказом при сериализации в JSON с помощью Spray?

Я использую библиотеку Spray JSON для сериализации наших классов case в JSON. Проблема в том, что у нас есть некоторые взаимно рекурсивные определения. Я работаю по примеру сериализации запечатанных признаков здесь: http://www.cakesolutions.net/teamblogs/2012/11/30/spray-json-and-adts/

Вот простой пример, который работает. Обратите внимание на определение C:

import spray.json._
import DefaultJsonProtocol._

sealed trait BaseTrait
sealed trait SpecializedTrait extends BaseTrait

case class A(argA: BaseTrait, foo: Int) extends SpecializedTrait
case class B(argB: BaseTrait, foo: Int) extends SpecializedTrait

case class C(foo: Int) extends BaseTrait

object BaseTrait {
  implicit val cJsonFormat = jsonFormat1(C)

  implicit object BaseTraitJsonFormat extends RootJsonFormat[BaseTrait] {
    override def write(obj: BaseTrait): JsValue = throw new IllegalStateException("Not Implemented")
    override def read(v: JsValue): BaseTrait = throw new IllegalStateException("Not Implemented")
  }
}

object SpecializedTrait {
  implicit val aJsonFormat = jsonFormat2(A)
  implicit val bJsonFormat = jsonFormat2(B)

  implicit object SpecializedTraitJsonFormat extends RootJsonFormat[SpecializedTrait] {
    override def write(obj: SpecializedTrait): JsValue = throw new IllegalStateException("Not Implemented")
    override def read(v: JsValue): SpecializedTrait = throw new IllegalStateException("Not Implemented")
  }
}

Когда вы меняете определение «C» на исходное взаимно рекурсивное определение,.

...
case class C(argC: SpecializedTrait, foo: Int) extends BaseTrait

object BaseTrait {
  implicit val cJsonFormat = jsonFormat2(C)

...

Очевидно, вы не можете просто сказать «нет», у меня не может быть взаимно рекурсивных структур данных. Кажется, компилятор спотыкается из-за правил разрешения для неявных объектов.

Есть ли обходной путь для этого? Я обошел это, изменив объекты на объявления анонимных классов, т.е.

import spray.json._
import DefaultJsonProtocol._

sealed trait BaseTrait
sealed trait SpecializedTrait extends BaseTrait

case class A(argA: BaseTrait, foo: Int) extends SpecializedTrait
case class B(argB: BaseTrait, foo: Int) extends SpecializedTrait

case class C(argC: SpecializedTrait, foo: Int) extends BaseTrait

object BaseTrait {
  implicit val cJsonFormat : RootJsonFormat[C] = jsonFormat2(C)

  implicit val baseTraitFormat : RootJsonFormat[BaseTrait] = new RootJsonFormat[BaseTrait] {
    def write(obj: BaseTrait): JsValue = throw new IllegalStateException("Not Implemented")
    def read(v: JsValue): BaseTrait = throw new IllegalStateException("Not Implemented")
  }
}

object SpecializedTrait {
  implicit val aJsonFormat : RootJsonFormat[A] = jsonFormat2(A)
  implicit val bJsonFormat : RootJsonFormat[B] = jsonFormat2(B)

  implicit val specializedTraitFormat : RootJsonFormat[SpecializedTrait] = new RootJsonFormat[SpecializedTrait] {
    override def write(obj: SpecializedTrait): JsValue = throw new IllegalStateException("Not Implemented")
    override def read(v: JsValue): SpecializedTrait = throw new IllegalStateException("Not Implemented")
  }
}

Этот последний фрагмент работает, обратите внимание на изменение с «неявного объекта» на «неявный val» и последующий анонимный класс.


person user3246214    schedule 25.03.2014    source источник


Ответы (1)


Определите имплициты по порядку и поместите их в один объект.

import spray.json._
import DefaultJsonProtocol._

sealed trait BaseTrait
sealed trait SpecializedTrait extends BaseTrait

case class A(argA: BaseTrait, foo: Int) extends SpecializedTrait
case class B(argB: BaseTrait, foo: Int) extends SpecializedTrait
case class C(argC: SpecializedTrait, foo: Int) extends BaseTrait

object SomeProtocol {
  implicit object BaseTraitJsonFormat extends RootJsonFormat[BaseTrait] {
    override def write(obj: BaseTrait): JsValue = throw new IllegalStateException("Not Implemented")
    override def read(v: JsValue): BaseTrait = throw new IllegalStateException("Not Implemented")
  }
  implicit object SpecializedTraitJsonFormat extends RootJsonFormat[SpecializedTrait] {
    override def write(obj: SpecializedTrait): JsValue = throw new IllegalStateException("Not Implemented")
    override def read(v: JsValue): SpecializedTrait = throw new IllegalStateException("Not Implemented")
  }
  implicit val aJsonFormat = jsonFormat2(A)
  implicit val bJsonFormat = jsonFormat2(B)
  implicit val cJsonFormat = jsonFormat2(C)
}
person Dave Swartz    schedule 25.03.2014
comment
Это не сработает, если у вас есть взаимно рекурсивные запечатанные черты, которые необходимо сериализовать. - person user3246214; 29.03.2014
comment
SomeProtocol позволяет де / сериализовать классы случаев A, B и C, на которые вы ссылались в своем вопросе (при условии, что вы реализуете методы read и write. Я думал, что это именно то, что вы хотели сделать. - person Dave Swartz; 29.03.2014