如何使用*非case *类从Scala反序列化JSON?

时间:2012-12-18 03:01:56

标签: json scala

我正在编写一个需要序列化到JSON并从中反序列化的Scala应用程序。一些JSON对象有超过22个字段,所以我不能使用case类(我也不能改变格式)。我能够找到的所有Scala JSON库只能(很容易)使用case类,而不是普通的类。

鉴于此,将大型JSON对象(具有超过22个字段)反序列化为Scala非案例类的最简单方法是什么?它不一定是完全自动的,但理想情况下我正在寻找比反序列化为Map [String,Any]并手动完成所有操作更少痛苦的事情。

3 个答案:

答案 0 :(得分:4)

更新:幸运的是,现在可以使用Json4s和Jackson使用字段序列化器执行我想要的操作,如下所示:

implicit val formats = DefaultFormats + FieldSerializer[MyNonCaseClass]()

val myNonCaseClassObject = Serialization.read[MyNonCaseClass](jsonString)

如下所述,这是一个更完整的例子:

import org.json4s.jackson.Serialization
import org.json4s._
import scala.util.Try

object JSONUtil {

implicit val formats = DefaultFormats + FieldSerializer[MyNonCaseClass]() + FieldSerializer[MyOtherNonCaseClass](ignore("someUnwantedFieldName") orElse ignore("anotherFieldToIgnore")) + ...

def toJSON(objectToWrite: AnyRef): String = Serialization.write(objectToWrite)

def fromJSONOption[T](jsonString: String)(implicit mf: Manifest[T]): Option[T] = Try(Serialization.read(jsonString)).toOption

}

然后用法是:

val jsonString = JSONUtil.toJSON(myObject)
val myNewObject: Option[MyClass] = JSONUtil.fromJSONOption[MyClass](aJsonString)

您需要为要序列化的每个非案例类使用FieldSerializer。此外,在定义类时,JSON中可能缺少的所有内容都需要定义为选项。

SBT:

"org.json4s" %% "json4s-jackson" % "3.2.6"

答案 1 :(得分:3)

使用The Play JSON library with generics

可以在没有案例类的情况下完成

因为我正在喝点咖啡而什么都不做。我冒昧地为你编写了一个例子。完整的解决方案如下:

首先,这是你的班级:

import play.api.libs.json._
import play.api.libs.json.Json._


    class TestJSON(
      val field1: String,
      val field2: String,
      val field3: String,
      val field4: String,
      val field5: String,
      val field6: String,
      val field7: String,
      val field8: String,
      val field9: String,
      val field10: String,
      val field11: String,
      val field12: String,
      val field13: String,
      val field14: String,
      val field15: String,
      val field16: String,
      val field17: String,
      val field18: String,
      val field19: String,
      val field20: String,
      val field21: String,
      val field22: String,
      val field23: String) {

    }

    object TestJSON {
      //
      // JSON BINDING/UNBINDING
      //

      implicit def modalityReads: Reads[TestJSON] = new Reads[TestJSON] {
        def reads(json: JsValue): TestJSON =
          new TestJSON(
            field1 = (json \ "field1").as[String],
            field2 = (json \ "field2").as[String],
            field3 = (json \ "field3").as[String],
            field4 = (json \ "field4").as[String],
            field5 = (json \ "field5").as[String],
            field6 = (json \ "field6").as[String],
            field7 = (json \ "field7").as[String],
            field8 = (json \ "field8").as[String],
            field9 = (json \ "field9").as[String],
            field10 = (json \ "field10").as[String],
            field11 = (json \ "field11").as[String],
            field12 = (json \ "field12").as[String],
            field13 = (json \ "field13").as[String],
            field14 = (json \ "field14").as[String],
            field15 = (json \ "field15").as[String],
            field16 = (json \ "field16").as[String],
            field17 = (json \ "field17").as[String],
            field18 = (json \ "field18").as[String],
            field19 = (json \ "field19").as[String],
            field20 = (json \ "field20").as[String],
            field21 = (json \ "field21").as[String],
            field22 = (json \ "field22").as[String],
            field23 = (json \ "field22").as[String])
      }

      implicit def modalityWrites: Writes[TestJSON] = new Writes[TestJSON] {
        def writes(ts: TestJSON) = JsObject(Seq(
          "field1" -> JsString(ts.field1),
          "field2" -> JsString(ts.field2),
          "field3" -> JsString(ts.field3),
          "field4" -> JsString(ts.field4),
          "field5" -> JsString(ts.field5),
          "field6" -> JsString(ts.field6),
          "field7" -> JsString(ts.field7),
          "field8" -> JsString(ts.field8),
          "field9" -> JsString(ts.field9),
          "field10" -> JsString(ts.field10),
          "field11" -> JsString(ts.field11),
          "field12" -> JsString(ts.field12),
          "field13" -> JsString(ts.field13),
          "field14" -> JsString(ts.field14),
          "field15" -> JsString(ts.field15),
          "field16" -> JsString(ts.field16),
          "field17" -> JsString(ts.field17),
          "field18" -> JsString(ts.field18),
          "field19" -> JsString(ts.field19),
          "field20" -> JsString(ts.field20),
          "field21" -> JsString(ts.field21),
          "field22" -> JsString(ts.field22),
          "field23" -> JsString(ts.field23)))
      }
    }

您的控制器应如下所示:

import play.api._
import play.api.mvc._
import play.api.libs.json.Json._
import play.api.Play.current
import models.TestJSON

object Application extends Controller  {

  def getJson = Action {
    implicit request =>
      Ok(
        toJson(
          Seq(
            toJson(
              new TestJSON(
                "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
                "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23")),
              toJson(new TestJSON(
                "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
                "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23")))))
  }

}

你的路线档案(只是路由行动):

GET     /getJson                             controllers.Application.getJson

现在,真相的时刻......

curl localhost:9000/getJson
[{"field1":"1","field2":"2","field3":"3","field4":"4","field5":"5","field6":"6",
"field7":"7","field8":"8","field9":"9","field10":"10","field11":"11","field12":"
12","field13":"13","field14":"14","field15":"15","field16":"16","field17":"17","
field18":"18","field19":"19","field20":"20","field21":"21","field22":"22","field
23":"23"},{"field1":"1","field2":"2","field3":"3","field4":"4","field5":"5","fie
ld6":"6","field7":"7","field8":"8","field9":"9","field10":"10","field11":"11","f
ield12":"12","field13":"13","field14":"14","field15":"15","field16":"16","field1
7":"17","field18":"18","field19":"19","field20":"20","field21":"21","field22":"2
2","field23":"23"}]

它也应该相反。我目前正在一个项目中使用它来组装和拆卸大树,所以它应该适合你。让我知道。

干杯!

PS:别担心,我花了大约10分钟来生成代码。我只是映射了一个List.range(1,24)和“foreached”它来打印代码。

答案 2 :(得分:1)

查看Lift JSON API

关键是所有被解析的东西都会作为JValue的子类返回。像

这样的对象
{
  "a": [1, 2],
  "b": "hello"
}

将被解析为

JObject(List(
  JField("a", JArray(List(JInt(1), JInt(2)))),
  JField("b", JString("hello"))
))

Lift API提供了一些有用的方法,例如\,可让您访问Map之类的内容。还有一个extractOpt[A]方法会尽力将解析后的JSON转换为您想要的任何A。和他们一起玩,感受它。