反序列化期间将POJO映射到具有不可变列表的案例类

时间:2019-07-19 07:59:01

标签: java scala immutability case-class json4s

我来自Java背景,试图了解如何在Scala中为Domain类/ POJO建模。

我正在尝试从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案例类中,字段“ columns”是一个List。默认情况下,这是一个不可变的列表。反序列化库如何将新的DataColumnGetResponse对象添加到此不可变列表?我必须宣布这是可变的吗?

2)ColumnResponse POJO中有一个称为“类型”的字段。在Scala中,“ type”是保留关键字。如何处理这种情况?

2 个答案:

答案 0 :(得分:4)

回答第一个:

可以使用copy函数对不可变的对象进行突变:

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

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

回答第二个问题:

如果是保留字,您可以像

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

答案 1 :(得分:1)

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

  

反序列化库如何添加新的DataColumnGetResponse对象   到这个不可变的清单?

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

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中的运算符::在此列表的开头添加元素,并返回添加了v new 列表。这意味着由于[1,2,3]中包含三个元素,因此以下三个列表是由json4s在反序列化过程中创建的

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

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

接下来,在创建内部AST之后,实际的deserialisationList[Int]通过调用extract[List[Int]]进行。对列表执行此操作的关键组件是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