如何避免为 JSON 宏初始阶段的子 类 定义隐式 reads/writes(将嵌套的 JSON 结构转换为 Scala)

How to avoid definition of implicit reads/writes for the sub-classes for JSON Macro Inception (to convert nested JSON structure to Scala)

我有一个要求,其中传入的 JSON 对象很复杂并且大部分是嵌套的 ex:

"users": {
  "utype": "PERSON",
  "language":"en_FR",
  "credentials": [
    {          
      "handle": "xyz@abc.com",
      "password": "123456",
      "handle_type": "EMAIL"
    }
  ],
  "person_details": {
    "primary": "true",
    "names": [
      {
      "name_type": "OFFICIAL",
      "title": "MR",
      "given": "abc",
      "family": "zat",
      "middle": "pqs",
      "suffix":"anathan"
     }
    ],
    "addresses": [
      {
        "ad_type": "HOME",
        "line1": "Residential 2211 North 1st Street",
        "line2": "Bldg 17",
        "city": "test",
        "county": "Shefield",
        "state" : "NY",
        "country_code": "xx",
        "postal_code": "95131"
      }
    ]
  }
}

为了解析这个结构,我使用下面的案例 类

case class PersonUser (
    user_type:String,
    language_code:String,
    credentials:List[Credential],
    person_details:PersonDetails
)

case class Credential(handle:String, password:String,handle_type:String)

case class PersonDetails(
    primary_user:Boolean,
    names: List[Name],
    addresses:List[Address]
)

case class Name(
    name_type: String,
    title: String,
    given: String,
    family: String,
    middle: String,
    suffix:String
)

case class Address(
    address_type: String,
    line1: String,
    line2: String,
    city: String,
    county: String,
    state : String,
    country_code: String,
    postal_code: String
)

为了将 JSON 结构转换为 Scala,我使用了 JSON Inception:

 implicit val testReads = Json.reads[PersonUser]

我还必须在子 类 - Credential、PersonDetails、Name 和 Address 中指定类似的 reads implicits。下面给出了这样的例子:

case class Credential(handle:String, password:String,handle_type:String)
object Credential{
   implicit val reads = Json.reads[Credential]
}

现在问题来了,如果我的 JSON 结构真的很大,有很多子结构,那么我需要定义很多 Scala case 类。为每个 case 类 定义伴随对象和隐式读取真的很麻烦(例如:如果我有 8 个 case 类 来完全表示 JSON 结构,我将不得不再定义 8 个伴生对象)。有什么办法可以避免这种额外的工作吗?

不,无法避免为每个要(反)序列化的 class 定义一个 Format 实例。

你也可以看看其他库,至少 Genson 不需要你定义大量的隐式。您上面显示的代码默认情况下应该与 Genson 一起使用。

import com.owlike.genson.defaultGenson_

val personUser: PersonUser = fromJson[PersonUser](json)
val json = toJson(personUser)

Genson还有很多其他的功能,我让你自己判断。

这个问题已经回答了,但我想我会解释为什么会这样。

  1. 如果宏为嵌套案例 classes 生成了必要的读取,这将无法为那些嵌套的 classes 定义您自己的自定义读取。结果,宏只对最微不足道的情况有用,需要切换到手动实现整个层次结构的读取,只是为了为一个深度嵌套的情况定义自定义行为 class。现在宏的实现方式,你可以随意随意更改其中的任何部分。
  2. 是的,头顶上有一个小样板文件。但从好的方面来说,编译器会告诉你你的结构是否可以被反序列化,这意味着你可以及早捕获错误,使重构更安全,也意味着没有那么隐含的魔法,你知道它是如何工作的唯一方法是阅读文档。通过强类型化一切,没有魔法,没有惊喜,没有隐含的知识,这导致改进的可维护性。