1
votes

I am coming from Java background and trying to understand how to model Domain classes/POJOs in Scala.

I am trying to Deserialize JSON response from a RestAPI and my Java POJOs are as follows:

@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;
    ...
}

Now I have created following Case Classes

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


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

I am trying to use https://sttp.readthedocs.io/en/latest/json.html#json4s library for HTTP communication and json4s for deserialization.

Questions:

1) In the DataSetGetResponse case class, field "columns" is a List.By default this is an immutable list. How the Deserialization library add new DataColumnGetResponse objects to this immutable list? Do I have to declare this as mutable ?

2) There is a field called 'type' field in the ColumnResponse POJO. In Scala 'type' is a reserved keyword.How to handle this case?

2
No need to make the list mutable. When adding an element to immutable list a new list is created with the added element. Regarding type field just surround it with backtics. - Mario Galic

2 Answers

4
votes

Answer the first one:

An immutable object can be mutated with the copy function:

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

For more complex tasks you can use Lenses see for example here: enter link description here

Answer the second one:

If it is a reserved word you can do it like

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

This answer addresses the following aspect of the question:

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

Let us consider a simplified version of the problem:

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

How does json4s deserialise [1,2,3] into immutable List[Int]? First it parses the raw string into an intermediary AST (abstract syntax tree) data structure where it represents the list like so

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

We see here that arr is an immutable list. The key line that builds it up after parse executes is in JsonParser

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

Note how the operator :: in v :: a.arr adds an element at the beginning of this list and returns a new list with v added in. This means since there are three elements in [1,2,3] the following three lists are created by json4s in the process of deserialisation

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

Again note these are three separate lists.

Next, after internal AST is created, actual 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
    ...
    }

Note how we simply map over AST arr built up during parsing step and convert each element to the model of type typeArg, which in our simple case is Int but in your case would be DataColumnGetResponse.