scala中json與對象的轉換


  • 遇到的問題

因為要把spark從es讀出來的json數據轉換為對象,開始想用case class定義類型,通過fastjson做轉換。如下

復制代碼
case class Book (author: String, content: String, id: String, time: Long, title: String)

  val json = "{\"author\":\"hll\",\"content\":\"ES即etamsports\",\"id\":\"693\",\"time\":1490165237200,\"title\":\"百度百科\"}"
  val mapper: ObjectMapper = new ObjectMapper()
  val book: Book = mapper.readValue(json, classOf[Book])
復制代碼

結果拋出了異常:com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class JsonTest$Book]

換成fastjson也會有相似的異常。

恍然大悟,case class沒有空參構造函數,跟fastjson這些庫不太兼容。

  • 解決辦法

然而又不想就java class,然后就找到了json4s-jackson,可以完美兼容scala的case class。

pom依賴:

<dependency>
    <groupId>org.json4s</groupId>
    <artifactId>json4s-jackson_2.10</artifactId>
    <version>3.2.10</version>
</dependency>

 

  

使用的樣例代碼:

復制代碼
//隱式轉換必須要導入
import org.json4s._ import org.json4s.jackson.JsonMethods._ class Book(val author: String,val content: String,val id: String, val time: Long, val title: String) object JsonTest { def main(args: Array[String]) { val json = "{\"author\":\"hll\",\"content\":\"ES即etamsports\",\"id\":\"693\",\"time\":1490165237200,\"title\":\"百度百科\"}"
    //導入隱式值 implicit val formats = DefaultFormats val book: Book = parse(json).extract[Book] println(book.content) } }
復制代碼
  •  實際使用與思考

spark程序中的應用:

1
2
implicit val formats = DefaultFormats
esRDD.map(_._2).map(parse(_).extract[Book]).sortBy(_.time, false).take(10).foreach(println)

spark里面解析json數據有一個經典的問題,ObjectMapper對象的創建很重。一般使用mapPartition來對一個分區復用ObjectMapper對象。

我們來看一下parse方法的源碼:

 

private[this] lazy val _defaultMapper = {
   val m = new ObjectMapper()
   m.registerModule(new Json4sScalaModule)
   m
 }
 def mapper = _defaultMapper
 
 def parse(in: JsonInput, useBigDecimalForDouble: Boolean = false): JValue = {
   mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, useBigDecimalForDouble)
   in match {
       case StringInput(s) => mapper.readValue(s, classOf[JValue])
       case ReaderInput(rdr) => mapper.readValue(rdr, classOf[JValue])
       case StreamInput(stream) => mapper.readValue(stream, classOf[JValue])
       case FileInput(file) => mapper.readValue(file, classOf[JValue])
     }
 }

 

  實際使用的ObjectMapper對象是lazy初始化的而且是復用的,避免了ObjectMapper對象的重復創建,很nice。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM