Я пишу несколько тестовых примеров RESTful API, и у меня мало опыта работы с scala playframwork.
Вот пример моего JSON.
[ {
"size" : "5082",
"date-created" : "Wed Nov 19 17:10:39 CST 2014",
"id" : "546d236fb84e894eefd8f769",
"content-type" : "image/png",
"filename" : "chrome-on-windows.PNG"
}, {
"size" : "15684",
"date-created" : "Mon Jan 12 17:28:02 CST 2015",
"id" : "54b4588266b3d11b1c1e9db6",
"content-type" : "image/png",
"filename" : "logos_ncsa.png"
}, {
"size" : "1267871",
"date-created" : "Mon Jan 12 17:28:03 CST 2015",
"id" : "54b4588366b3d11b1c1e9dba",
"content-type" : "image/jpg",
"filename" : "morrowplots.jpg"
} ]
Как видите, у меня есть список / массив элементов JSON. Я хочу получить идентификатор файла morrowplots.jpg и сохранить его в переменной, которая будет использоваться для успешных вызовов API.
Итак, я установил свой код, чтобы он выглядел следующим образом. Переменная результата в приведенном ниже коде - это строка JSON, которую вы видите выше.
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
implicit val fileReads: Reads[FileName] = (
(__ \\ "size").read[String] and
(__ \\ "datecreated").read[String] and
(__ \\ "id").read[String] and
(__ \\ "content-type").read[String] and
(__ \\ "filename").read[String]
)(FileName.apply _)
val json: JsValue = Json.parse(contentAsString(result))
val nameResult: JsResult[FileName] = json.validate[FileName](fileReads)
info("Right after validate")
nameResult match {
case s: JsSuccess[FileName] => {
val testfile: FileName = s.get
// Do something with testfile
info("Success")
}
case e: JsError => {
info("Error")
info("Errors: " + JsError.toFlatJson(e).toString())
}
}
Это дает мне следующую ошибку.
[info] + Ошибки: {"obj size": [{"msg": "error.path.result.multiple", "args": []}], "obj filename": [ {"msg": "error.path.resul t.multiple", "args": []}], "obj id": [{"msg": "error.path.result.multiple", " args ": []}]," obj content-type ": [{" msg ":" error.path .result.multiple "," args ": []}]," obj * datecreated ": [{"msg": "error.path.missing", "args": []}]}
Итак, как мне исправить эту проблему со списком / массивом и как выполнить поиск по имени файла, чтобы получить идентификатор?
Заранее спасибо.
Ответ 1 · рейтинг 4 · Justin Pihony
Я не эксперт по игре, так что это может быть не идиоматично, но должно решить вашу проблему. Во-первых, ваш json date-created по сравнению с вашим scala, ожидающим datecreated. Во-вторых, вы должны использовать только одну косую черту для своего Reads. Затем вам нужно запустить validate против List[FileName].
Что касается поиска по имени файла, теперь вы можете извлечь список из JsSuccess и запустить filter против него.
Окончательный код будет выглядеть примерно так
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
implicit val fileReads: Reads[FileName] = (
(__ \ "size").read[String] and
(__ \ "date-created").read[String] and
(__ \ "id").read[String] and
(__ \ "content-type").read[String] and
(__ \ "filename").read[String]
)(FileName)
val json: JsValue = Json.parse(contentAsString(result))
val nameResult = json.validate[List[FileName]]
val list = nameResult match {
case JsSuccess(list : List[FileName], _) => list
case e: JsError => {
info("Errors: " + JsError.toFlatJson(e).toString())
List()
}
}
list filter(_.filename contains "morrow")
Ответ 2 · рейтинг 6 · Agemen
Во-первых, вы можете решить использовать встроенные утилиты json, а не выполнять синтаксический анализ вручную.
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
object FileName {
implicit val formatFileName = Json.format[FileName]
}
Здесь у вас есть все, что вам нужно для синтаксического анализа базового объекта json. Компилятор будет использовать макрос (IIRC) для генерации кода, эквивалентного тому, который вы написали вручную. Поскольку у вас нет экзотических проверок в ваших полях, ручное написание классов Reads и Writes не требуется.
Тогда вы можете прочитать это так:
def readString(str: String) = {
val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
jsr.fold(
error => {
???
},
success => {
???
}
)
}
jsr - это JsResult. Это может быть либо JsSuccess, либо JsError.
Также обратите внимание на полный тип. Поскольку у вас есть массив в качестве ввода, вы должны поместить свой вывод в коллекцию, например, Seq.
Вы можете сбросить свой JsResult. fold ожидает двух функций. Один для случая ошибки, он имеет тип Seq [(JsPath, Seq [ValidationError])] => X, где X - тип возвращаемого значения вашей функции. Он показывает вам все проблемы, из-за которых ваш json не удалось преобразовать в Seq [FileName].
Другой - на случай успеха. Он имеет тип Seq [FileName] => X с тем же X, что и раньше.
Теперь вы можете решить, что добавить в эти две функции.
Как указал Джастин, вы тоже можете написать это со спичкой. Это может быть проще, даже если оно менее функционально:
def readString(str: String) = {
val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
jsr match {
case JsResult(seq) => ???
case e: JsError => ???
}
}