Scala: Parse JSON directly into a case class

2019-02-01 17:56发布

问题:

Given a string of JSON, and a case class that corresponds to it, what's a simple way to parse the JSON into the case class? There are many libraries available, but it seems that Scala might now do this out of the box.

What about if the JSON should be parsed into a list of the case class?

UPDATE:

Jerkson seems to be abandoned, and I don't want to install the full Play or Lift framework or anything else heavy.

回答1:

There are several frameworks which can exactly do that.

JSON4s

JSON4s is quite mature and supports jackson or a native JSON-Parser. Used it in many projects to replace jerkson.

https://github.com/json4s/json4s

play-json

Can be used without the full play stack. Great support as part of the play project at typesafe.

http://www.playframework.com/documentation/2.0/ScalaJson

Scala-Pickling

A serialization Framework. There is an option to serialize/ and deserialize to JSON.

https://github.com/scala/pickling

Spray JSON

Can searialize and deserialize. Need to know number of arguments for deserialization tough.

https://github.com/spray/spray-json



回答2:

I've used https://github.com/json4s/json4s , only gripe so far is https://github.com/json4s/json4s/issues/137

import org.json4s._
import org.json4s.native.JsonMethods._

implicit val formats = DefaultFormats

case class ParsedPage(crawlDate: String, domain:String, url:String, text: String)

val js = """ {
"crawlDate": "20150226",
"domain": "0x20.be",
"url": "http://0x20.be/smw/index.php?title=99_Bottles_of_Beer&oldid=6214",
"text": "99 Bottles of Beer From Whitespace (Hackerspace Gent) Revision as of 14:43, 8 August 2012 by Hans ( Talk | contribs ) 99 Bottles of Beer Where: Loading map... Just me, with 99 bottles of beer and some friends. Subpages"
}"""


parse(js).extract[ParsedPage]


回答3:

Use spray-json as it is small.

import spray.json._
import DefaultJsonProtocol._


val json = """{"one" : "1", "two" : "2", "three" : "3"}""".parseJson

case class Numbers(one: String, two: String, three: String)

object MyJsonProtocol extends DefaultJsonProtocol {
  implicit val numbersFormat = jsonFormat3(Numbers)

}

import MyJsonProtocol._

val converted = json.convertTo[Numbers]

Download spray-json into sbt using this build.sbt:

lazy val root = (project in file(".")). settings( name := "jsonExample", libraryDependencies += "io.spray" %% "spray-json" % "1.3.2" )



回答4:

Spray Json is pretty light weight and does exactly what you need. It's a toolkit instead of a full on framework and you can just import the Spray-json project instead of the entire project.

https://github.com/spray/spray-json

The examples can get you set up very quickly. Most of the time your code to translate to/from JSON ends up being one liners, but you have the ability to explicitly handle it in case you have some weird requirements.



回答5:

Use net.liftweb

import net.liftweb.json._
case class Detail(username:String, password:String)
implicit val formats = DefaultFormats
val input = parse(jsonString).extract[Detail]
println(input.username)

Make sure the Scala version matches the lift-json jar. For ex. for Scala 2.10 use lift-json_2.10.



回答6:

I second the JSON conversion in the Play Framework.

Also take a look at Jackson which is mature. Note you will need to use Jackson Scala Module : https://github.com/FasterXML/jackson-module-scala.

A decent article providing an intro - then some code to add implicit conversions : https://coderwall.com/p/o--apg/easy-json-un-marshalling-in-scala-with-jackson



回答7:

For anyone bumping into this for the first time, circe is also a good option

val customerJson = s"""{"id" : "1", "name" : "John Doe"}"""
case class Customer(id: String, name: String)
val customer = decode[Customer](customerJson)