Преобразовать JsArray из JsArray в класс Case
Мой вопрос является своего рода продолжением этого и этого тоже.
Мой JSON выглядит так:
{
"id": "id1",
"results": [
{
"exceed_size": "yes",
"rows_count": 1001,
"runtime_seconds": 0.02199999988079071,
"columns": [
"COL_1",
"COL_2",
"COL_3",
"COL_4",
"COL_5",
"COL_6",
"COL_7",
"COL_8",
"COL_9"
],
"columns_type": [
"number",
"string",
"string",
"string",
"number",
"time",
"time",
"number",
"string"
],
"limit": 1000,
"index": 0,
"rows": [
[
"9",
" C68894",
" ",
"",
"0",
"2018-05-02 03:13:00.0",
"2017-12-02 22:32:00.0",
"",
"Approved "
],
[
"65",
"325806 ",
"msm ",
" ",
"2",
"2018-05-02 03:13:00.0",
"2018-07-06 06:00:00.0",
"13",
"Approved "
],
...
]
},
...
]
}
Я использую Play Framework, предоставленный JSON Library для анализа JSON.
Если вы посмотрите на rows
значение, это JsArray
из JsArray
строковых значений. Я пытался преобразовать rows
в список объектов класса case, где мой класс case будет выглядеть так:
case class Rows(col_1: String, col_2: String, ... , col_9: String)
Я пытался сделать что-то вроде:
val rows = (response \\ "rows").head.as[List[List[(String, String, ... , String)]]].flatten
Попытка этого способа вызвала ошибку, которая, я был уверен, не сработает. Как мне конвертировать такой JsArray
в список объектов класса case?
РЕДАКТИРОВАТЬ 1:
Как предложил @MilanRegmi, я попытался:
implicit val jsonFormat: Format[Rows] = Json.format[Rows]
val emails = (response \ "results" \ "rows").as[JsArray]
.value.map(j => j.validate[Rows].get)
Попытка это привело к:
Exception in thread "main" play.api.libs.json.JsResultException: JsResultException(errors:List((,List(JsonValidationError(List([{"exceed_size":"yes","rows_count":1001,"runtime_seconds":0.01600000075995922,"columns":["COL_1","COL_2","COL_3","COL_4","COL_5","COL_6","COL_7","COL_8","COL_9"],"columns_type":["number","string","string","string","number","time","time","number","string"],"limit":1000,"index":0,"rows":[["9"," C68894","","","0","2018-05-02 03:13:00.0","2017-12-02 22:32:00.0","","Approved "],["65","325806 ","msm "," ","2","2018-05-02 03:13:00.0","2018-07-06 06:00:00.0","13","Approved "],...]}] is not an object),WrappedArray())))))
at play.api.libs.json.JsReadable$$anonfun$2.apply(JsReadable.scala:25)
at play.api.libs.json.JsReadable$$anonfun$2.apply(JsReadable.scala:25)
at play.api.libs.json.JsError.fold(JsResult.scala:64)
at play.api.libs.json.JsReadable$class.as(JsReadable.scala:23)
at play.api.libs.json.JsUndefined.as(JsLookup.scala:181)
at com.cmdwldap.restapi.User.getEntitlementUserData(User.scala:150)
at com.cmdwldap.restapi.User$.main(User.scala:168)
at com.cmdwldap.restapi.User.main(User.scala)
PS: линия 150 соответствует месту, где val emails
упомянуто.
1 ответ
Попробуй это:
val rows: Seq[Rows] = (json \ "result" \ "rows").as[JsArray].value.map(j => j.validate[Rows].get)
Обновить:
После прохождения вашего вопроса несколько раз. Я получил ваш вопрос сейчас. Вы хотите конвертировать List[List[String]
в CaseClass
,
Во-первых, вы не можете напрямую преобразовать массив List of String в класс case. Итак, вам нужно конвертировать Array[String]
в JsObject
где key
должно быть fieldName
класса. После этого мы можем получить fieldName
используя отражение. Затем нам нужно создать JsObject
соответствовать caseClass
а также List[String]
с помощью fieldName
,
Программно, описанный выше сценарий может быть решен следующим образом:
case class Rows(col1: Option[String] = None,
col2: Option[String] = None,
col3: Option[String] = None,
col4: Option[String] = None,
col5: Option[String] = None,
col6: Option[String] = None,
col7: Option[String] = None,
col8: Option[String] = None,
col9: Option[String] = None)
implicit val reads = Json.reads[Rows]
Это наш случай класса и последствия reads
, Теперь выше объясненная часть ниже:
import scala.reflect.runtime.universe._
def classAccessors[T: TypeTag]: List[MethodSymbol] = typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}.toList
val rowFieldNames = classAccessors[Rows].map(k => k.name.toString)
val results = (json \ "results").as[JsArray].value.flatMap{
r => (r \ "rows").as[JsArray].value
}.map{row =>
val rowArray = row.as[JsArray]
val rowArraySeq = rowArray.value.map(_.as[JsString]).map(_.value)
val map = rowArraySeq.foldLeft(Map.empty[String, JsValue]){
(r, c) =>
val indexOfCurrentValue = rowArraySeq.indexOf(c)
val fieldName = rowFieldNames(indexOfCurrentValue)
r.+((fieldName, JsString(c)))
}
val rowJsObject = JsObject(map)
Json.toJson(rowJsObject)
}.toList