2012-08-09 15 views
11

Il mio problema è che ricevo un testo JSON da dire, twitter. Quindi voglio convertire questo testo in un oggetto nativo in scala. C'è un metodo standard per fare questo? Sto anche utilizzando Play 2Come convertire JSON in un tipo in Scala

Ecco quello che ho

import scala.io.Source.{fromInputStream} 
import java.net._ 

val url = new URL("https://api.twitter.com/1/trends/1.json") 
val content = fromInputStream(url.openStream).getLines.mkString("\n") 
val json = Json.parse(content) 
val a = (json \ "trends") 
Ok(a(0)) 

voglio ottenere tutte le tendenze nome dal JSON

+1

possibile duplicato di [Come posso costruire e analizzare una stringa JSON in Scala/Ascensore] (http://stackoverflow.com/questions/927983/how-can-i-construct-and-parse-a-json-string-in-scala-lift) –

+0

c'è anche Jerkson e alcune altre librerie meno conosciute –

+1

@ om-nom-nom: non penso che questo conta come un duplicato - l'altra domanda riguarda specificamente Lift, non Play (ed è abbastanza antica, comunque). –

risposta

4

Io personalmente preferisco lift-json, ma è abbastanza facile da fare questo con Play's JSON library:

import play.api.libs.json._ 
import scala.io.Source 

case class Trend(name: String, url: String) 

implicit object TrendReads extends Reads[Trend] { 
    def reads(json: JsValue) = Trend(
    (json \ "name").as[String], 
    (json \ "url").as[String] 
) 
} 

val url = new java.net.URL("https://api.twitter.com/1/trends/1.json") 
val content = Source.fromInputStream(url.openStream).getLines.mkString("\n") 
val trends = Json.parse(content) match { 
    case JsArray(Seq(t)) => Some((t \ "trends").as[Seq[Trend]]) 
    case _ => None 
} 

In questo momento questo produce il seguente:

scala> trends.foreach(_.foreach(println)) 
Trend(#TrueFactsAboutMe,http://twitter.com/search/?q=%23TrueFactsAboutMe) 
Trend(#200mFinal,http://twitter.com/search/?q=%23200mFinal) 
Trend(Jamaica 1,2,3,http://twitter.com/search/?q=%22Jamaica%201,2,3%22) 
Trend(#DontComeToMyHouse,http://twitter.com/search/?q=%23DontComeToMyHouse) 
Trend(Lauren Cheney,http://twitter.com/search/?q=%22Lauren%20Cheney%22) 
Trend(Silver & Bronze,http://twitter.com/search/?q=%22Silver%20&%20Bronze%22) 
Trend(Jammer Martina,http://twitter.com/search/?q=%22Jammer%20Martina%22) 
Trend(Japan 2-0,http://twitter.com/search/?q=%22Japan%202-0%22) 
Trend(Prata e Bronze,http://twitter.com/search/?q=%22Prata%20e%20Bronze%22) 
Trend(Final 200m,http://twitter.com/search/?q=%22Final%20200m%22) 

Quindi sì, sembra giusto.

3

Suggerisco di usare Jackson JSON processor. Funziona sia per Java che per Scala. Basta aggiungere annotazioni alle classi che descrivono come si desidera mappare i dati JSON ai propri oggetti nativi.

Un esempio:

import scala.reflect.BeanProperty 
import org.codehaus.jackson.map.ObjectMapper; 
import org.codehaus.jackson.annotate._ 

class User { 
    @BeanProperty var gender: String = null 
    @BeanProperty var verified: Boolean = false 
    @BeanProperty var userImage: Array[Byte] = null 
    @BeanProperty var name: Name = null 
} 

case class Name { 
    @BeanProperty var first: String = null; 
    @BeanProperty var last: String = null; 
} 

object Json { 
    def main(argv: Array[String]) { 
    val input = """{ 
    "name" : { "first" : "Joe", "last" : "Sixpack" }, 
    "verified" : false, 
    "userImage" : "Rm9vYmFyIQ==" 
}"""; 

    val mapper = new ObjectMapper(); // can reuse, share globally 
    val user: User = mapper.readValue(input, classOf[User]); 

    print(user.name.first); 
    } 
} 

Questa soluzione ha un leggero fastidio che si deve annotare ogni campo con @BeanProperty, ma non so un modo più semplice.


Nota: Per quanto ne so, Jackson non usa javax.bean.Introspector, si cerca di trovare getter/setter esaminando i metodi di per sé. Se così fosse, le cose sarebbero state più facili, sarebbe possibile scrivere solo

@scala.reflect.BeanInfo 
case class Name { 
    var first: String; 
    var last: String; 
} 
3

Date un'occhiata al Lift-Json. Fa parte del framework Web Lift, ma può essere utilizzato come libreria autonoma. Può analizzare json in case classes (e raccolte di quelle, ad es. Liste e mappe), e non richiede di aggiungere annotazioni. Supporta anche le classi di rendering come json e la fusione e l'interrogazione di json.

Ecco un esempio tratto dal loro sito:

import net.liftweb.json._ 
implicit val formats = DefaultFormats // Brings in default date formats etc. 

case class Child(name: String, age: Int, 
       birthdate: Option[java.util.Date]) 
case class Address(street: String, city: String) 
case class Person(name: String, address: Address, 
       children: List[Child]) 
val json = parse(""" 
     { "name": "joe", 
      "address": { 
      "street": "Bulevard", 
      "city": "Helsinki" 
      }, 
      "children": [ 
      { 
       "name": "Mary", 
       "age": 5 
       "birthdate": "2004-09-04T18:06:22Z" 
      }, 
      { 
       "name": "Mazy", 
       "age": 3 
      } 
      ] 
     } 
     """) 

json.extract[Person] 
/* Person = Person(joe, Address(Bulevard,Helsinki), 
        List(Child(Mary,5,Some(Sat Sep 04 18:06:22 EEST 2004)), 
         Child(Mazy,3,None))) 
*/ 
Problemi correlati