假设我有这个模型,我在其中定义了具有特定JSON格式的自定义案例类IPAddress地址。此类包含IPv4的String表示形式,并在构造函数中进行验证,如果输入字符串无效,则会引发IllegalArgumentException。
case class Node(id: UUID, name: String, ip: IPAddress)
case class IPAddress(s: String) {
val rx = """^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$""".r
require(rx.pattern.matcher(s).matches())
val ip = s
override def toString = ip
}
object JsonNodeFormat {
import play.api.libs.json.Json
implicit val midWrite: Writes[FMMid] = Writes {
(mid: FMMid) => JsString(mid.toString)
}
implicit val midRead: Reads[FMMid] = JsPath.read[String].map(FMMid(_))
implicit val NodeFormat = Json.format[Node]
}
然后我让我的控制器有一个动作,创建一个新节点并将其写入数据库(在我的情况下,我使用ReactiveMongo,但这是无关紧要的)
class Nodes extends Controller with MongoController {
def collection: JSONCollection = db.collection[JSONCollection]("nodes")
import models._
import models.JsonNodeFormat._
def createTest = Action.async(parse.json) {
request =>
request.body.validate[Node].map {
node =>
collection.insert(node).map {
lastError =>
Created(s"Node Created")
}
}.getOrElse(Future.successful(BadRequest("invalid json")))
}
}
如果使用有效的json
发出请求{
"id": "0879d4be-78bb-4cc0-810b965b",
"ip": "192.168.0.10",
"name": "node1"
}
一切正常。该对象已正确添加到db。我希望控制器在传递无效的IP地址时返回BadRequest响应。相反,如果我传递带有无效IP地址的Json
{
"id": "0879d4be-78bb-4cc0-810b965b",
"ip": "192.168.0.foo",
"name": "node1"
}
它导致内部服务器错误,控制台上打印了所有堆栈(因为没有人捕获构造函数异常)。我希望当传递无效的IPAddress时,request.body.validate函数失败并且执行落在getOrElse语句中。
另请注意,传递无效的UUID不会产生错误,但会产生BadRequest回复。
我的IPAddress类中缺少什么?
答案 0 :(得分:1)
最终我找到了解决方案。我发现在其他Reads验证帮助程序之间有一个名为pattern,它将一个String与一个正则表达式匹配。所以我改变了我的Json Reads为
implicit val midRead: Reads[FMMid] = JsPath.read[String](pattern("""^5\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$""".r)).map(FMMid(_))
一切都按照我的预期开始了。
P.S。仍然无法理解UUID如何在没有任何自定义验证器的情况下工作。