Home > Blockchain >  Transform JSON using Scala
Transform JSON using Scala

Time:01-02

I have the following JSON

{
    "record1": {
        "firstName": "John",
        "lastName": "Doe",
        "locations": {
            "29b2f2295cd74b8cbb53db4379f0d823": "New York"
        }
    },
    "record2": {
        "firstName": "Carol",
        "lastName": "Rees",
        "locations": {
            "0055bb74b4984156b821ebbea6937084": "California"
        }
    },
    "record3": {
        "firstName": "Colin",
        "lastName": "Scott",
        "locations": {
            "aba67f566fc24f8a8eb3165648ca5e4f": "Toronto",
            "b847750c565246638dbc72cb89ead227": "London"
        }
    }
}

which needs to be transformed to the following using Scala

{
    "record1": {
        "firstName": "John",
        "lastName": "Doe",
        "locations": [{
            "id" : "29b2f2295cd74b8cbb53db4379f0d823",
            "location": "New York"
        }]
    },
    "record2": {
        "firstName": "Carol",
        "lastName": "Rees",
        "locations": [{
            "id" : "0055bb74b4984156b821ebbea6937084",
            "location": "California"
        }]
    },
    "record3": {
        "firstName": "Colin",
        "lastName": "Scott",
        "locations": [{
            "id": "aba67f566fc24f8a8eb3165648ca5e4f",
            "location:" : "Toronto"
        },
            {
            "id" : "b847750c565246638dbc72cb89ead227",
            "location": "London"
        }]
    }
}

I am being new to scala, this is what I have so far

case class PersonEntry(firstName: String, lastName: String, locations: Map[String, String])

val jsonMapper = JsonMapper.builder().addModule(DefaultScalaModule).build()

val inputJson: String = "{\n    \"record1\": {\n        \"firstName\": \"John\",\n        \"lastName\": \"Doe\",\n        \"locations\": {\n            \"29b2f2295cd74b8cbb53db4379f0d823\": \"New York\"\n        }\n    },\n    \"record2\": {\n        \"firstName\": \"Carol\",\n        \"lastName\": \"Rees\",\n        \"locations\": {\n            \"0055bb74b4984156b821ebbea6937084\": \"California\"\n        }\n    },\n    \"record3\": {\n        \"firstName\": \"Colin\",\n        \"lastName\": \"Scott\",\n        \"locations\": {\n            \"aba67f566fc24f8a8eb3165648ca5e4f\": \"Toronto\",\n            \"b847750c565246638dbc72cb89ead227\": \"London\"\n        }\n    }\n}"
val parsedPerson = jsonMapper.readValue(inputJson, classOf[Map[String, Any]])
val personMap: Map[String, PersonEntry] = parsedPerson.mapValues(jsonMapper.convertValue(_, classOf[PersonEntry]))

CodePudding user response:

There are several ways to do it. As you already have written a case class representing the input data, I would:

  • create a case class representing the output data
  • parse input as input case classes
  • map input case class to output case class
  • generate JSON for output case classes

If performance matters, you could look to work without parsing to case classes and operate directly on the JSON input but I won't explain this option.

That is, something along the lines of:

case class PersonOutput(firstName: String, lastName: String, locations: Seq[Location])

case class Location(id: String, location: String)

val output: Map[String, PersonOutput] = jsonMapper
  .readValue(inputJson, classOf[Map[String, PersonEntry]])
  .map { case (key, person) => 
    val newLocations = person.locations.map { 
      case (k, v) => Location(k, v)
    }
    key -> PersonOutput(person.firstName, person.lastName, newLocations)
  }

// Then generate JSON for output
  • Related