定义 Reads[X],其中 X 具有私有构造函数
Defining Reads[X] where X has Private Constructor
给定 Person
class 和 'smart constructor',即 Person#build
中只有 "valid" 个值将构造 Person
:
case class Person private(age: Int)
object Person {
def build(age: Int): Option[Person] =
if (age >= 0 && age <= 125) Some(Person(age)) else None
}
我通过将它放入 Person
的伴生对象中创建了一个 Reads[Person]
:
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val reads: Reads[Person] =
(__ \ 'age).read[Int].map(a =>
Person.build(a).getOrElse(throw new RuntimeException("invalid age")
)
有没有更好的方法?如果可能的话,我宁愿避免这个例外。
如果您愿意放弃游戏功能风格,您可以利用 JsResult
monad:
new Format[Person] {
override def writes(o: Person): JsValue = ???
override def reads(json: JsValue): JsResult[Person] = {
try{
json.as[JsObject].value.get("age")
.flatMap(age => Person.build(age.as[Int])).map(JsSuccess(_))
.getOrElse(JsError("wrong age"))
} catch {
case e: Exception =>
JsError("wrong age")
}
}
}
val person = Json.toJson(Person.build(30))
val parsed: \/[String, Person] = person.validate[Person].map(\/-(_)).getOrElse(-\/("some bad request"))
所以它比我在评论中建议的要复杂一些,但基本上你可以将解析包装到一个方法中,该方法将 JsSuccess
转换为右侧,将 JsError
转换为左侧, try/catch
我用来捕获发送的 json 不是一个对象而只是一个值或者年龄字段不是整数的情况。
给定 Person
class 和 'smart constructor',即 Person#build
中只有 "valid" 个值将构造 Person
:
case class Person private(age: Int)
object Person {
def build(age: Int): Option[Person] =
if (age >= 0 && age <= 125) Some(Person(age)) else None
}
我通过将它放入 Person
的伴生对象中创建了一个 Reads[Person]
:
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val reads: Reads[Person] =
(__ \ 'age).read[Int].map(a =>
Person.build(a).getOrElse(throw new RuntimeException("invalid age")
)
有没有更好的方法?如果可能的话,我宁愿避免这个例外。
如果您愿意放弃游戏功能风格,您可以利用 JsResult
monad:
new Format[Person] {
override def writes(o: Person): JsValue = ???
override def reads(json: JsValue): JsResult[Person] = {
try{
json.as[JsObject].value.get("age")
.flatMap(age => Person.build(age.as[Int])).map(JsSuccess(_))
.getOrElse(JsError("wrong age"))
} catch {
case e: Exception =>
JsError("wrong age")
}
}
}
val person = Json.toJson(Person.build(30))
val parsed: \/[String, Person] = person.validate[Person].map(\/-(_)).getOrElse(-\/("some bad request"))
所以它比我在评论中建议的要复杂一些,但基本上你可以将解析包装到一个方法中,该方法将 JsSuccess
转换为右侧,将 JsError
转换为左侧, try/catch
我用来捕获发送的 json 不是一个对象而只是一个值或者年龄字段不是整数的情况。