首页 > 解决方案 > Play Framework JSON 排序失败

问题描述

我有大量案例类,下面只是这些案例类的一个子集:

sealed trait BuiltInType { def id: Int }
  case class ZombieType          (a: String,        id: Int = 0) extends BuiltInType
  case class BooleanType         (a: Boolean,       id: Int = 1) extends BuiltInType
  case class ByteType            (a: Byte,          id: Int = 2) extends BuiltInType
  case class UByteType           (a: Byte,          id: Int = 3) extends BuiltInType
  case class Int16Type           (a: Int,           id: Int = 4) extends BuiltInType
  case class UInt16Type          (a: Int,           id: Int = 5) extends BuiltInType
  case class Int32Type           (a: Int,           id: Int = 6) extends BuiltInType
  case class UInt32Type          (a: Int,           id: Int = 7) extends BuiltInType
  case class Int64Type           (a: Long,          id: Int = 8) extends BuiltInType
  case class UInt64Type          (a: Long,          id: Int = 9) extends BuiltInType
  case class FloatType           (a: Float,         id: Int = 10) extends BuiltInType
  case class DoubleType          (a: Double,        id: Int = 11) extends BuiltInType
  case class StringType          (a: String,        id: Int = 12) extends BuiltInType
  case class DateTimeType        (a: Long,          id: Int = 13) extends BuiltInType // FIXME: Wrong type used, fix it later
  case class GuidType            (a: UUID,          id: Int = 14) extends BuiltInType
  case class ByteStringType      (a: Vector[Byte],  id: Int = 15) extends BuiltInType
  case class XmlElementType      (a: String,        id: Int = 16) extends BuiltInType
  case class NodeIdType          (a: NodeId,        id: Int = 17) extends BuiltInType
  case class ExpandedNodeIdType  (a: NodeId,        id: Int = 18) extends BuiltInType // FIXME: Wrong type used, fix it later
  case class StatusCodeType      (a: StatusCode,    id: Int = 19) extends BuiltInType
  case class QualifiedNameType   (a: QualifiedName, id: Int = 20) extends BuiltInType
  case class LocalizedTextType   (a: LocalizedText, id: Int = 21) extends BuiltInType
  case class ExtensionObjectType (a: ExtensionObject, id: Int = 22) extends BuiltInType 
  case class DataValueType       (a: DataValue,       id: Int = 23) extends BuiltInType 
  case class VariantType         (a: Variant,       id: Int = 24) extends BuiltInType
  case class DiagnosticInfoType  (a: String,        id: Int = 25) extends BuiltInType 

如您所见,我定义了其他几个复杂类型。例如,有一种称为 Variant 的类型,它本身就是这样的案例类:

  sealed trait VariantData
  case class SimpleOrder(rows: Vector[BuiltInType]) extends VariantData
  case class HigherOrder(matrices: Vector[VariantData]) extends VariantData

  case class Variant(data: VariantData)

然后我为 Play JSON 定义所有需要的隐式格式,如下所示:

implicit val strType = Json.format[StringType]
implicit val guidType = Json.format[GuidType]
implicit val int16Type = Json.format[Int16Type]
implicit val uint64Type = Json.format[UInt64Type]
implicit val int32Type = Json.format[Int32Type]
implicit val int64Type = Json.format[Int64Type]
implicit val uByteTyp = Json.format[UByteType]
implicit val qNameType = Json.format[QualifiedNameType]
implicit val nodeIdTyp = Json.format[NodeIdType]
implicit val locTextTyp = Json.format[LocalizedTextType]
implicit val zombType = Json.format[ZombieType]
implicit val statusCodeTyp = Json.format[StatusCodeType]
implicit val builtInType = Json.format[BuiltInType]

implicit val simpleFmt = Json.format[SimpleOrder]
implicit val higherFmt = Json.format[HigherOrder]
implicit val varDataFmt = Json.format[VariantData]

implicit val varFmt = Json.format[Variant]

我收到此错误:

Error:(66, 43) No instance of Reads is available for domain.CommonTypes.VariantType in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
    implicit val builtInType = Json.format[BuiltInType]

所以我改变了这样的隐含顺序:

implicit val simpleFmt = Json.format[SimpleOrder]
implicit val higherFmt = Json.format[HigherOrder]
implicit val varDataFmt = Json.format[VariantData]

implicit val varFmt = Json.format[Variant]

implicit val strType = Json.format[StringType]
implicit val guidType = Json.format[GuidType]
implicit val int16Type = Json.format[Int16Type]
implicit val uint64Type = Json.format[UInt64Type]
implicit val int32Type = Json.format[Int32Type]
implicit val int64Type = Json.format[Int64Type]
implicit val uByteTyp = Json.format[UByteType]
implicit val qNameType = Json.format[QualifiedNameType]
implicit val nodeIdTyp = Json.format[NodeIdType]
implicit val locTextTyp = Json.format[LocalizedTextType]
implicit val zombType = Json.format[ZombieType]
implicit val statusCodeTyp = Json.format[StatusCodeType]
implicit val builtInType = Json.format[BuiltInType]

但是现在,我收到了这个错误:

Error:(53, 41) No instance of play.api.libs.json.Format is available for scala.collection.immutable.Vector[domain.CommonTypes.BuiltInType] in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
    implicit val simpleFmt = Json.format[SimpleOrder]

所以我现在的问题是,这是一个订购问题还是我遗漏了什么,因为这里的抱怨是它期待一个

矢量[内置类型]

还是循环依赖导致了这个问题?

标签: scalatypeclassimplicitplay-json

解决方案


通常,您始终可以解决订购问题,例如:

把. formats_companion-objects

请参见下面的示例。

为了简化您的工作,sealed traits我会使用play-json-derived-codecs

进口:

import play.api.libs.json._
import julienrf.json.derived

很酷的事情是你只需要formattrait所有它subclasses都会自动完成:

  implicit val jsonFormat: OFormat[VariantData] = derived.oformat[VariantData]()
  implicit val jsonFormat: OFormat[BuiltInType] = derived.oformat[BuiltInType]()

format代码略有不同。

为了说明这如何简化代码,这里是Dmytro的示例:

  import play.api.libs.json._
  import julienrf.json.derived

  sealed trait BuiltInType { def id: Int }
  case class StringType(a: String, id: Int = 12) extends BuiltInType    
  case class ByteStringType(a: Seq[Byte], id: Int = 15) extends BuiltInType    
  case class VariantType(a: Variant, id: Int = 24) extends BuiltInType

  object BuiltInType {
    implicit val jsonFormat: OFormat[BuiltInType] = derived.oformat[BuiltInType]()
  }
  sealed trait VariantData
  case class SimpleOrder(rows: Seq[BuiltInType]) extends VariantData
  case class HigherOrder(matrices: Seq[VariantData]) extends VariantData

  object VariantData {
    implicit val jsonFormat: OFormat[VariantData] = derived.oformat[VariantData]()
  }

  case class Variant(data: VariantData)

  object Variant {
    implicit val jsonFormat: OFormat[Variant] = derived.oformat[Variant]()
  }

  val json = Json.toJson(VariantType(Variant(SimpleOrder(Seq(StringType("aaa"))))): BuiltInType)
  println(json) //{"a":{"data":{"_type":"App.SimpleOrder","rows":[{"a":"aaa","_type":"App.StringType","id":12}]}},"_type":"App.VariantType","id":24}

以您的示例为例,差异会更大。


推荐阅读