如何将 JSON 表示为案例 class
how to represent a JSON as a case class
我想将 JSON 表示为一个案例 class。
{
result:"success" or "fail"
message: "some message"
}
我的特殊要求是 result
只能取值 "success" 或 "error"。任何其他值都应该无法解析 JSON
我尝试创建一个特征,然后对它进行子class,但我不明白如何限制 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)
最终,我希望能够如下创建 Reads
或 Writes
,但我不确定这是否可行。
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))
}
错误消息非常明确:JSONResult
不知道 result
字段,因此无法正确序列化。
JSONResult
不一定是trait
,还是可以转化成抽象的class,问题应该解决了,例如:
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
)
}
}
更新
如果您仍然want/have使用函数式语法定义Writes
的方法,则仍有一定的简化空间。
我认为创建 JSONResult
实体只是为了包装 "error" 或 "success" 字符串有点矫枉过正,它使进一步的映射复杂化,正如您看到的那样,多个 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
fo 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))
希望这对您有所帮助。
End-of-update
我想将 JSON 表示为一个案例 class。
{
result:"success" or "fail"
message: "some message"
}
我的特殊要求是 result
只能取值 "success" 或 "error"。任何其他值都应该无法解析 JSON
我尝试创建一个特征,然后对它进行子class,但我不明白如何限制 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)
最终,我希望能够如下创建 Reads
或 Writes
,但我不确定这是否可行。
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))
}
错误消息非常明确:JSONResult
不知道 result
字段,因此无法正确序列化。
JSONResult
不一定是trait
,还是可以转化成抽象的class,问题应该解决了,例如:
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
)
}
}
更新
如果您仍然want/have使用函数式语法定义Writes
的方法,则仍有一定的简化空间。
我认为创建 JSONResult
实体只是为了包装 "error" 或 "success" 字符串有点矫枉过正,它使进一步的映射复杂化,正如您看到的那样,多个 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
fo 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))
希望这对您有所帮助。
End-of-update