Расширение Circe до запечатанной черты, расширенной несколькими классами случаев - PullRequest
0 голосов
/ 22 мая 2018

Я видел подобные вопросы раньше, но ни один из них не работал.Я думаю, что они спрашивают что-то другое, поэтому я спрашиваю здесь.У меня есть что-то вроде этого в одном файле:

sealed trait Thing
case class SomeThing() extends Thing
case class OtherThing() extends Thing

и в другом файле:

val str = //valid json
val decoded = decode[Thing](str)
println(decoded)

, и я получаю:

Left(DecodingFailure(...))

Это работает, если я сделал:

val str = //valid json
val decoded = decode[SomeThing](str)
println(decoded)

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

Мне пришлось написать собственный кодер и декодер для сериализации / десериализации.

пример,

import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._

object CirceSubtypesSerialisers {

  def main(args: Array[String]): Unit = {

    sealed trait Data

    case class OptionsData(data: Seq[String]) extends Data
    case class TextData(data: String) extends Data

    object Data {
      implicit val decodeData: Decoder[Data] = Decoder[OptionsData].map[Data](identity).or(Decoder[TextData].map[Data](identity))

      implicit val encodeData: Encoder[Data] = Encoder.instance {
        case options @ OptionsData(_) => options.asJson
        case text @ TextData(_) => text.asJson
      }
    }

    val optionsJson ="""{ "data": ["option1", "option2"] }""".stripMargin

    decode[Data](optionsJson) match {
      case Right(r: OptionsData) => println(r)
      case Left(l) => println(l)
    }


    val textJson ="""{ "data": "hey, how can i help ya?" }""".stripMargin

    decode[Data](textJson) match {
      case Right(r: TextData) => println(r)
      case Left(l) => println(l)
    }

  }

}

вывод:

OptionsData(List(option1, option2))
TextData(hey, how can i help ya?)

Это также упоминается в https://circe.github.io/circe/codec.html#warnings-and-known-issues и JsonCodec для запечатанных признаков требует явного определения объекта

0 голосов
/ 22 мая 2018

вы можете использовать circe-generic и добавить маркировку типов для ваших jsons:

В вашем build.sbt:

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core" % "0.9.3",
  "io.circe" %% "circe-generic" % "0.9.3",
  "io.circe" %% "circe-parser" % "0.9.3"
)

Теперь давайте определим наши классы и сериализуем + десериализовать их:

sealed trait Thing
case class SomeThing() extends Thing
case class OtherThing() extends Thing

import io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._
val thing: Thing = SomeThing()


// serialize Thing to json
val jsString: String = thing.asJson.spaces2
println(s"serialized $thing to:\n$jsString")
/* serialized SomeThing() to:
{
   "SomeThing" : {

   }
}
*/


// deserialize json to Thing
val errorOrMyTrait: Either[io.circe.Error, Thing] = for {
  json <- parse(jsString) // either ADT, since this may not be a legal json
  myDecodedClass <- json.as[Thing] // ADT, since this may be a json that is not in Thing Format
} yield myDecodedClass

println(errorOrMyTrait) // Right(SomeThing())

Обратите внимание, что теперь сериализованный json содержит тип запечатанного класса

0 голосов
/ 22 мая 2018

Похоже, вы могли столкнуться с этой известной проблемой .

В соответствии с обсуждением, возможно, вы могли бы попробовать:

import io.circe.generic.JsonCodec

@JsonCodec sealed trait Thing
case class SomeThing() extends Thing
case class OtherThing() extends Thing

object Thing
...