【问题标题】:Creating a Json array in Scala在 Scala 中创建 Json 数组
【发布时间】:2016-03-09 02:32:36
【问题描述】:

我正在尝试像这样创建一个 Json 对象

{
  "Field1": [{}, {}, {}, {}],
  "Field2": [{}, {}, {}],
  "Field3": {}
}

通常在 Java 中,我可以通过(特别是使用 google simple json)来实现这一点

  1. 为 field1 和 field2 创建 JSON 数组,
  2. 为 Field3 创建 JSON 对象
  3. 将以上3个组合成另一个JSONObject

上面的结果来自不同的进程,我需要返回一个组合的 json 对象

我很困惑如何在 Scala 中实现相同的功能,我尝试了多个库和方法。我正在尝试的最新版本是 json4s。我以为我可以

  1. 遍历字符串列表并将它们放入“json数组”
  2. 将上述数组添加到另一个带有键的“json对象”中
  3. 返回组合的json对象

我认为这将像在 Java 中一样简单,我是否遗漏了一些明显的东西? (我是 Scala 新手)。

任何帮助将不胜感激。

【问题讨论】:

    标签: java json scala


    【解决方案1】:

    我使用scala module with jackson,JsonUtil.scala:

    package json
    
    import com.fasterxml.jackson.databind.{SerializationFeature, DeserializationFeature, ObjectMapper, PropertyNamingStrategy}
    import com.fasterxml.jackson.module.scala.DefaultScalaModule
    import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
    
    object JsonUtil {
      private val ObjectMapper = buildMapper()
    
      private def buildMapper() = {
        val mapper = new ObjectMapper() with ScalaObjectMapper
        mapper.registerModule(DefaultScalaModule)
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        mapper.enable(SerializationFeature.INDENT_OUTPUT)
        mapper
      }
    
      def fromJson[A](json: String, objectType: Class[A]): A = {
        ObjectMapper.readValue(json, objectType)
      }
    
      def toJson(data: AnyRef): String = {
        ObjectMapper.writeValueAsString(data)
      }
    }
    

    依赖关系:

    compile 'com.fasterxml.jackson.core:jackson-core:2.6.3'
    compile 'com.fasterxml.jackson.module:jackson-module-scala_2.11:2.6.3'
    

    那么,就很容易使用了:

    case class MyDto(id: Int, name: Option[String])
    ...
    val jsonString = JsonUtil.toJson(MyDto(123, Some("John Doe")))
    val dto = JsonUtil.fromJson(jsonString, classOf[MyDto])
    
    case class MyList(items: List[Int])
    ...
    val jsonList = JsonUtil.toJson(MyList(List(1,2,3,4,5)))
    

    【讨论】:

    • 感谢您的回答。我仍然无法弄清楚如何使用这种方法获得“dto”对象列表。如果它更清楚,我的应用程序“查询”给了我一个列表 json 字符串,我需要将其转换为 Object 数组,然后包装在 json 对象中
    • 您可以使用与通常使用Jackson 相同的方式。根据您的示例,它可能是下一个案例类: case class Main(field1: List[YourClassesInsideList1], field2: List[YourClassesInsideList2], filed3: YourClass3) ... val dto = Main(JsonUtil.fromJson(jsonFiled1), JsonUtil .fromJson(jsonFiled2), JsonUtil.fromJson(jsonFiled3))
    【解决方案2】:

    这是在circe 中执行此操作的一种方法:

    import io.circe.syntax._
    
    val json = Map(
      "Field1" -> List.fill(4)(()).asJson,
      "Field2" -> List.fill(3)(()).asJson,
      "Field3" -> ().asJson
    ).asJson
    

    然后:

    scala> json.noSpaces
    res0: String = {"Field1":[{},{},{},{}],"Field2":[{},{},{}],"Field3":{}}
    

    这里有几点需要注意。首先是 Scala 鼓励使用不可变集合,因此您可以使用 List.fill(n)(value) 之类的实用程序,而不是“将值放入”列表,它会创建一个重复 n 次的 value 列表。这意味着List.fill(3)(())List((), (), ()) 完全相同,我们也可以在上面使用。

    第二点更具体。 () 是 Scala 中的一个特殊值——它是 Unit 类型的唯一值,它只代表一个不携带任何信息的空事物。 ()的JSON编码是{},所以我们可以通过调用().asJson来创建一个空的JSON对象。

    circe 还知道如何从它知道如何编码的任何类型的 Scala 列表(或其他序列)中创建 JSON 数组,因此 List.fill(3)(()).asJson 是一个 JSON 值,它是由三个空 JSON 对象组成的 JSON 数组。

    最后,circe 还知道如何从 Scala Map 创建 JSON 对象,其中键是字符串,值类型是它知道如何编码的东西。这意味着我们可以创建一个Map[String, io.circe.Json] 类型的映射并在其上调用asJson 以获取一个JSON 值,它是一个包含映射所表示的字段的JSON 对象。

    根据您的具体用例,您还可以通过其他方式来执行此操作,这些方式可能会更好,包括:

    case class Fields(Field1: List[Unit], Field2: List[Unit], Field3: Unit)
    

    然后:

    scala> import io.circe.generic.auto._
    import io.circe.generic.auto._
    
    scala> Fields(List((), (), (), ()), List((), (), ()), ()).asJson.noSpaces
    res0: String = {"Field1":[{},{},{},{}],"Field2":[{},{},{}],"Field3":{}}
    

    这种方法(使用 circe 对 generic codec derivation 的支持)通常比直接使用 JSON 值更惯用。

    【讨论】:

    • 我喜欢这个,但是圆形库准备好迎接黄金时段了吗? github 自述文件表明这可能不是最终版本?
    • 这取决于——有少数公司在生产中使用 circe,以及其他几个提供互操作模块的库等。部分 API 可能会在 1.0 之前更改,但我可以保证所有这里的代码将在可预见的未来工作。
    【解决方案3】:

    虽然有点冗长,但您可以使用play framework。这样可以编写案例类对象,然后直接将它们转换为 JSON 对象。下面的例子有点松散,因为你没有说你的对象到底是什么样子。

    case class ResponseObject(a: Field1, b: Field2, c: Field3)
    case class Field1(a: Seq[Field1obj])
    case class Field2(a: Seq[Field2obj]))
    case class Field3(a: Field3obj)
    case class Field1obj(a: String, b: Int)
    ...
    

    然后您可以使用

    编写隐式写入器
    implicit val responseWrites = Json.writes[ResponseObject]
    implicit val fieldWrites = Json.writes[Field1]
    ...
    val resultToSend = ResponseObject(field1, field2, field3)
    val json = Json.toJson(resultToSend)
    

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      • 1970-01-01
      • 2018-04-28
      • 2015-04-28
      相关资源
      最近更新 更多