パースエラー内容を保持しない方法
import play.api.libs.json.{ Format, JsValue, Json }
case class HogeJson(
id: String,
data: String
)
object HogeJson {
implicit val format: Format[HogeJson] = Json.format[HogeJson]
def fromJson(json: JsValue): Option[HogeJson] = Json.fromJson(json)(format).asOpt
}
成功パターン
val str = """{ "id": "aa", "data": "bb" }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
res12: Option[HogeJson] = Some(HogeJson(aa,bb))
失敗パターン(必須プロパティが空)
val str = """{ "id": "aa" }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
res14: Option[HogeJson] = None
失敗するとNoneがかえるが、複雑なJsonだとどこでエラーになっているか調べるのが辛くなる。
パースエラー内容を保持する方法
import com.typesafe.scalalogging.LazyLogging
import scalaz.Scalaz.ToEitherOps
import scalaz.\/
import play.api.data.validation.ValidationError
import play.api.libs.json.{ Format, JsError, JsPath, JsSuccess, JsValue, Json }
case class HogeJson(
id: String,
data: String
)
object HogeJson extends LazyLogging {
implicit val format: Format[HogeJson] = Json.format[HogeJson]
def fromJson(json: JsValue) =
Json.fromJson(json)(format).fold(
valid = s => s.right,
invalid = e => {
e.foreach { case (path, errors) =>
logger.error(s"""path:[${path.toString}] msg:[${errors.map(x => x.message).mkString(",")}] arg:[${errors.map(_.args.toString).mkString(",")}] """)
}
e.left
}
)
}
成功パターン
val str = """{ "id": "aa", "data": "bb" }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
res12: Option[HogeJson] = Some(HogeJson(aa,bb))
失敗パターン1(必須プロパティが空)
val str = """{ "id": "aa" }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
09:22:40.948 [run-main-0] ERROR $line79.$read$$iw$$iw$HogeJson$ - path:[/data] msg:[error.path.missing] arg:[WrappedArray()]
res50: scalaz.\/[Seq[(play.api.libs.json.JsPath, Seq[play.api.data.validation.ValidationError])],HogeJson] = -\/(List((/data,List(ValidationError(List(error.path.missing),WrappedArray())))))
失敗パターン2(型エラー)
val str = """{ "id": 1, "data": 2 }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
09:23:40.447 [run-main-0] ERROR $line79.$read$$iw$$iw$HogeJson$ - path:[/data] msg:[error.expected.jsstring] arg:[WrappedArray()]
09:23:40.447 [run-main-0] ERROR $line79.$read$$iw$$iw$HogeJson$ - path:[/id] msg:[error.expected.jsstring] arg:[WrappedArray()]
res51: scalaz.\/[Seq[(play.api.libs.json.JsPath, Seq[play.api.data.validation.ValidationError])],HogeJson] = -\/(List((/data,List(ValidationError(List(error.expected.jsstring),WrappedArray()))), (/id,List(ValidationError(List(error.expected.jsstring),WrappedArray())))))
ネストもOK
import com.typesafe.scalalogging.LazyLogging
import scalaz.Scalaz.ToEitherOps
import scalaz.\/
import play.api.data.validation.ValidationError
import play.api.libs.json.{ Format, JsError, JsPath, JsSuccess, JsValue, Json }
case class HogeJson(
id: String,
data: HogeJson2
) {
def toJson: JsValue = Json.toJson(this)(HogeJson.format)
}
object HogeJson extends LazyLogging {
implicit val format: Format[HogeJson] = Json.format[HogeJson]
def fromJson(json: JsValue) = Json.fromJson(json)(format).fold(
valid = s => s.right,
invalid = e => {
e.foreach { case (path, errors) =>
logger.error(s"""path:[${path.toString}] msg:[${errors.map(x => x.message).mkString(",")}] arg:[${errors.map(_.args.toString).mkString(",")}] """)
}
e.left
}
)
}
case class HogeJson2(value: String) {
def toJson: JsValue = Json.toJson(this)(HogeJson2.format)
}
object HogeJson2 extends LazyLogging {
implicit val format: Format[HogeJson2] = Json.format[HogeJson2]
}
成功パターン
val str = """{ "id": "1", "data": { "value": "a" } }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
res57: scalaz.\/[Seq[(play.api.libs.json.JsPath, Seq[play.api.data.validation.ValidationError])],HogeJson] = \/-(HogeJson(1,HogeJson2(a)))
失敗パターン2(HogeJson2の型エラー)
val str = """{ "id": "1", "data": { "value": 1 } }"""
val jsValue = Json.parse(str)
scala> HogeJson.fromJson(jsValue)
10:06:46.333 [run-main-0] ERROR $.$read$$iw$$iw$$iw$$iw$HogeJson$ - path:[/data/value] msg:[error.expected.jsstring] arg:[WrappedArray()]
res59: scalaz.\/[Seq[(play.api.libs.json.JsPath, Seq[play.api.data.validation.ValidationError])],HogeJson] = -\/(List((/data/value,List(ValidationError(List(error.expected.jsstring),WrappedArray())))))