Извлечете вложени обекти и стойности от JSON

Опитвам се да извлека проблеми от Jira и да ги поставя в List[Issue]. Разбрах как да изтегля и анализирам JSON:

val json = JsonParser.parse(content)

Мога също да извлека някои числа в корена на JSON:

val total = (json \ "total").extract[Int]
val maxResults = (json \ "maxResults").extract[Int]
println("Received " + total + " from " + maxResults + " issues")

Но когато се опитвам да извлека списък с всички проблеми

val issues = (json \ "issues")
println(issues)
issues.extract[List[Issue]]

Получавам грешка: Изключение в нишката "main" net.liftweb.json.MappingException: Няма използваема стойност за id Не знам как да преобразувам JString(13604) в int Не разбирам защо не може да преобразува 13604 в Вътр. Ето моя клас казус:

case class Issue(id: Int,
    key: String,
    summary: String,
    issueTypeName: String,
    resolutionName: Option[String],
    resolutionDate: Option[DateTime],
    timeSpent: Option[Int],
    creatorName: String,
    reporterName: String,
    updated: DateTime,
    created: DateTime,
    priorityName: String,
    description: String,
    dueDate: Option[DateTime],
    statusName: String,
    assigneeName: String,
    projectId: Int,
    projectKey: String,
    projectName: String,
    timeEstimate: Option[Int],
    ownerName: String,
    timeOriginalEstimate: Option[Int]
                    )
  1. Може ли някой да ми помогне с този Int проблем?

  2. Освен това JSON има вложени елементи за някои свойства, като проектът има вложени id, ключ и име. Преди да извлека проблеми с json \ "issues", видях друга грешка - вярвам, че е защото JSON екстракторът не знае, че трябва да отиде до вложените елементи. Как мога да го уведомя за това? Мислех, че мога да направя нещо подобно:

    for(issue ‹- issues) { val id = (issue \ "id").extract[Int] println(id)}

И използвайте issue \ "project" \ "id" за вложени елементи и след това създайте нов обект Case Class и го добавете към List var (променлив, но нямам идея как да го направя по друг начин). Но получавам грешка при компилиране:

 Error:(53, 16) value foreach is not a member of net.liftweb.json.JsonAST.JValue
        for(issue <- issues) {
                     ^

Аз съм нов в Scala и цялостната Java инфраструктура и рамки, така че ще съм благодарен за примери от код.


PS. Когато промених id на String в моя case клас, сега получавам друга грешка:

Exception in thread "main" net.liftweb.json.MappingException: No usable value for summary Did not find value which can be converted into java.lang.String

Това е така, защото „резюме“ е вложено в „полетата“. И така, вторият ми въпрос все още е актуален: 2. Как мога да работя с вложени стойности?

и нов свързан въпрос: 3. Ако искам да използвам Int за id - как мога да го конвертирам?


person Konstantin Trunin    schedule 29.06.2014    source източник


Отговори (2)


Това е така, защото полето id в json идва като низ ("id": "10230" https://developer.atlassian.com/display/JIRADEV/JIRA+REST+API+Example+-+Query+issues ), който liftjson автоматично преобразува в JString. Във вашия клас case трябва да направите полето id String.

2) използвайте класове за справяне с вложен json. Ако имате json, който изглежда така

{
  "id": "10230",
  "fields": {
    "summary": "testing"
  }
}

ще ви трябват два класа случаи

case class Issues(
   id: String,
   fields: Summary
)

case class Summary(
   summary: String
)

3) Не мисля, че можете да конвертирате в Int в метода за извличане, защото JSON структурата го дефинира като String. Преобразуването ще трябва да се случи, след като извлечете стойността.

person p3lagic    schedule 29.06.2014
comment
Благодаря за отговора - полезен е. Сега обаче получавам грешка: Изключение в основната нишка net.liftweb.json.MappingException: Няма използваема стойност за обобщение Не е намерена стойност, която може да бъде преобразувана в java.lang.String - това е така, защото резюмето е вложено в полетата. 1. Как мога да работя с вложени стойности? 2. Ако трябва да използвам Int за id - как мога да го конвертирам? - person Konstantin Trunin; 29.06.2014
comment
@KonstantinTrunin Получихте ли решение за проблема, който споменахте в коментара по-горе? TIA - person texens; 09.06.2015

Самият аз намерих решение:

val issues = (json \\ "issues").children
 for (issue <- issues) {
        val item = new Issue (
                    (issue \ "id").extract[String].toInt,
                    (issue \ "fields" \ "summary").extract[String],
                    (issue \ "fields" \ "issuetype" \ "name").extract[String],
                    (issue \ "fields" \ "resolutiondate").extractOrNone[String] match {
                        case None => None
                        case Some (null) => None
                        case Some (dt) => Some (dateTimeFormatter.withZoneUTC ().parseDateTime (dt))
                    },
        etc...) 
}

В този случай продължавам да използвам единичен клас (структурата, която дефинирам за собствените си нужди) и анализирам вложени json свойства в него, като правя трансформации на типове в движение, където е необходимо.

person Konstantin Trunin    schedule 04.07.2014