My problem is I receive an JSON text from say, twitter. Then I want to convert this text to an native object in scala. Is there a standard method to do this? I\'m also using Pla
convert to jsvalue by using Json.parse(string) then add operator as[T] to extract the value
Have a look at Lift-Json. It is part of the Lift web framework, but can be used as a stand-alone library. It can parse json into case classes (and collections of those, e.g., lists and maps), and it does not require you to add annotations. It also supports rendering classes as json, and merging and querying of json.
Here is an example taken from their website:
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)))
*/
I personally prefer lift-json
, but it's pretty easy to do this with 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
}
Right now this produces the following:
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)
So yeah, looks about right.
Try Jerkson lib: https://github.com/codahale/jerkson/
It is a json library for scala based on Jackson. It is included to play 2: http://www.playframework.org/documentation/2.0.2/ScalaJson
Example:
case class Person(id: Long, name: String)
parse[Person]("""{"id":1,"name":"Coda"}""") //=> Person(1,"Coda")
I suggest to use Jackson JSON processor. It works both for Java and Scala. You just add annotations to your classes which describe how you want to map JSON data to your native objects.
An example:
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);
}
}
This solution has a slight hassle that you have to annotate every field with @BeanProperty
, but I don't know a simpler way.
Remark: As far as I know, Jackson doesn't use javax.bean.Introspector
, it tries to find getters/setters by examining the methods by itself. If it did, things would have been easier, it would be possible to write just
@scala.reflect.BeanInfo
case class Name {
var first: String;
var last: String;
}