在反序列化期间使用不可变列表将 POJO 映射到基础 类

Mapping POJOs to case classes with immutable lists during deserialisation

我来自 Java 背景并试图了解如何在 Scala 中对域 classes/POJOs 建模。

我正在尝试反序列化来自 RestAPI 的 JSON 响应,我的 Java POJO 如下:

@Data
public class ColumnResponse {
    private String id;
    private String name;
    private String type;
    ...
}

k

@Data
public class DataSetGetResponse {
    private String id;
    private List<ColumnResponse> columns;
    ...
}

现在我已经创建了以下案例类

case class DataSetGetResponse (id: String,
                               columns: List[ColumnResponse]
                              .... )


case class ColumnResponse (id: String,name: String ...)

我正在尝试使用 https://sttp.readthedocs.io/en/latest/json.html#json4s 库进行 HTTP 通信,使用 json4s 进行反序列化。

问题:

1) 在 DataSetGetResponse 案例 class 中,字段 "columns" 是一个 List.By 默认值,这是一个不可变列表。反序列化库如何将新的 DataColumnGetResponse 对象添加到这个不可变列表中?我必须将其声明为可变的吗?

2) ColumnResponse POJO中有一个字段叫做'type'字段。在 Scala 中 'type' 是一个保留的 keyword.How 来处理这种情况?

回答第一个:

可以使用 copy 函数改变不可变对象:

dataSet.copy(columns = newResp :: dataSet.columns)

对于更复杂的任务,您可以使用 Lenses 请参见此处的示例:enter link description here

回答第二个:

如果它是一个保留字你可以像

那样做
case class ColumnResponse (id: String, name: String, `type`: String)

这个答案解决了问题的以下方面:

How the Deserialization library add new DataColumnGetResponse objects to this immutable list?

让我们考虑问题的简化版本:

JsonMethods.parse("""[1,2,3]""").extract[List[Int]]

json4s如何将[1,2,3]反序列化为不可变的List[Int]?首先,它 parses 将原始字符串转换成一个中间 AST(抽象语法树)数据结构,它代表列表,就像这样

case class JArray(arr: List[JValue]) extends JValue

我们在这里看到 arr 是一个不可变的列表。在 parse 执行后构建它的关键行在 JsonParser

    def newValue(v: JValue): Unit = {
      ...
        case a: JArray => vals.replace(JArray(v :: a.arr))
      ...
    }

注意 v :: a.arr 中的运算符 :: 如何在此列表的开头添加一个元素,returns 一个 new 列表 v 加入。这意味着由于 [1,2,3] 中有三个元素,因此以下三个列表是 json4s 在反序列化过程中创建的

JArray(List(JInt(1))
JArray(List(JInt(2), JInt(1)))
JArray(List(JInt(3), JInt(2), JInt(1)))

再次注意,这是三个 独立的 列表。

接下来,创建内部AST后,实际deserialisation to List[Int] takes place by calling extract[List[Int]]. The key component that does this for lists is CollectionBuilder

  private class CollectionBuilder(json: JValue, tpe: ScalaType)(implicit formats: Formats) {
    ...
      val array: Array[_] = json match {
        case JArray(arr)      => arr.map(extractDetectingNonTerminal(_, typeArg)).toArray
    ...
    }

注意我们如何简单地映射在解析步骤中建立的 AST arr 并将每个元素转换为类型 typeArg 的模型,在我们的简单情况下是 Int 但在你的情况是 DataColumnGetResponse.