如何将JSON表示为案例类

时间:2018-04-09 07:37:54

标签: scala playframework-2.6

我想将JSON表示为案例类。

{
result:"success" or "fail"
message: "some message"
}

我的特殊要求是result只应取值“成功”或“错误”。任何其他值都应该无法解析JSON

我尝试创建一个特征,然后对其进行子类化,但我不明白如何限制result

的值
sealed trait JSONResult 

case class JSONResultError(final val result:String="error") extends JSONResult
case class JSONResultSuccess(final val result:String="success") extends JSONResult

case class JsonMessages (
                        result: JSONResult,
                        message: String
                        )

虽然我可以创建一个JsonMEssages类型的变量,但我无法区分结果是JSONResultSuccess还是JSONResultError

scala> val jm = JsonMessages(JSONResultError(),"some error message")
jm: JsonMessages = JsonMessages(JSONResultError(error),some error message)

scala>scala> jm.result.result //this doesn't work because result is of type JSONResult which hasn't got `result` though it holds object of type `JSONResultError`
<console>:13: error: value result is not a member of JSONResult
       jm.result.result
                 ^

scala> jm.result
res17: JSONResult = JSONResultError(error)

最后,我希望能够创建ReadsWrites,但我不相信这会有效。

object JSONMessagesImplicits {

  /*Writes (write to JsValue) are used by toJson method of Json object to convert data (say the model) to JsValue*/

  implicit val JsonResultErrorWrites: Writes[JSONResultError] = (JsPath \ "result").write[String](unlift(JSONResultError.unapply))
  implicit val JsonResultSuccessWrites: Writes[JSONResultSuccess] = (JsPath \ "result").write[String](unlift(JSONResultError.unapply))

  implicit val JsonMessagesWithErrorWrites: Writes[JsonMessages] = (
    (JsPath \ "result").write[JSONResultError] and
      (JsPath \ "message").write[String]) (unlift(JsonMessages.unapply))

  implicit val JsonMessagesWithSuccessWrites: Writes[JsonMessages] = (
    (JsPath \ "result").write[JSONResultSuccess] and
      (JsPath \ "message").write[String]) (unlift(JsonMessages.unapply))
}

1 个答案:

答案 0 :(得分:0)

错误消息非常明确:JSONResult不了解result字段,因此无法正确序列化。

JSONResult不一定是trait,仍然可以将其转换为抽象类,问题应该解决,例如:

sealed abstract class JsonResult(val result: String)

case class JsonResultSuccess(override val result: String = "success") extends JsonResult(result)
case class JsonResultError(override val result: String = "error") extends JsonResult(result)

case class JsonMessage(val result: JsonResult, val message: String)

然后,没有必要为所有内容创建单独的Write,它可以缩短到这一个:

implicit val resultWrites = new Writes[JsonMessage] {
  override def writes(message: JsonMessage) : JsValue = {
    Json.obj(
      "result" -> message.result.result,
      "message" -> message.message
    )
  }
}

更新

如果您仍然希望/必须使用该方法来定义具有功能语法的Writes,则仍有一些简化空间。

我认为创建JSONResult实体只是为了包装&#34;错误&#34;或者&#34;成功&#34;字符串有点过分,当你在原始问题中看到多个Writes时,它会使进一步的映射变得复杂。

我们可以想象密封的东西如下:

sealed abstract class JsonMessage(val result: String, val message: String)

case class JsonResultSuccess(override val message: String) extends JsonMessage("success", message)
case class JsonResultFailure(override val message: String) extends JsonMessage("failure", message)

是的,message字段现在与根级result一起出现; result值是后代中的常量。

我们还需要实施unapply JsonMessage

object JsonMessage {

  def unapply(jsonMessage: JsonMessage): Option[(String, String)] = {
    if (jsonMessage == null) None
    else Some((jsonMessage.result, jsonMessage.message))
  }

}

完成这些更改后,我们只能使用原始样式定义一个Writes

implicit val messageWrites: Writes[JsonMessage] =
  ((JsPath \ "result").write[String] and
   (JsPath \ "message").write[String]) (unlift(JsonMessage.unapply))

希望这有帮助。

结束更新