Lesson 3
Mapping and Handling JSON Data with Classes
Introduction to Handling JSON Arrays in Scala

Welcome to another step in your journey to mastering JSON handling in Scala. In this lesson, you'll expand your knowledge of JSON handling by focusing on mapping JSON data to Scala case classes. Building on the foundation from the previous lesson, where you accessed individual JSON values using the os-lib and ujson libraries, we now also delve into handling JSON arrays. By learning to map these arrays to Scala case classes, you'll be able to efficiently iterate through JSON data structures and extract meaningful information. This skill is essential for manipulating complex data often encountered in modern applications and plays a crucial role in converting JSON data into structured Scala objects for further processing.

JSON Structure Example

Let's examine the JSON structure that we'll use. It represents a company named "Tech Innovations Inc." which has a headquarters with a city and state, and several departments, each containing a list of employees.

Here's how the JSON structure looks:

JSON
1{ 2 "company": "Tech Innovations Inc.", 3 "headquarters": { 4 "city": "San Francisco", 5 "state": "CA" 6 }, 7 "departments": [ 8 { 9 "name": "Research and Development", 10 "head": "Alice Johnson", 11 "employees": [ 12 {"name": "John Doe", "position": "Engineer", "experience": 5}, 13 ... 14 ] 15 }, 16 ... 17 ] 18}
Scala Case Class Mapping

To effectively parse this JSON data into Scala, we utilize case classes. These case classes correspond directly to the JSON entities, and their attributes are mapped to the fields within the JSON for seamless data conversion.

We'll start by defining the Employee case class, representing each employee within a department and tracking their name, position, and years of experience:

Scala
1case class Employee(name: String, position: String, experience: Int)

Next, we have the Department case class, which encapsulates details of each department, including its name, head, and a list of employees. This is essential for processing JSON arrays in Scala:

Scala
1case class Department(name: String, head: String, employees: Seq[Employee])

Each of these case classes accurately represents the corresponding JSON structure, enabling seamless conversion between JSON data and Scala objects with the help of ujson.

Reading and Parsing JSON Data

First, we'll read the JSON file content and parse it using the ujson library:

Scala
1// Read and parse the JSON file 2val filePath = os.pwd / "data.json" 3val data = os.read(filePath) 4val parsedJson = ujson.read(data)

The os.read(filePath) function is used to read the contents of a JSON file located at the specified path, while the ujson.read(data) function parses the JSON string into a JSON object that can be navigated and manipulated in Scala.

Transforming JSON to Scala Objects

Next, we map the parsed JSON data to our predefined Scala case classes:

Scala
1// Extract and process department data with employees 2val departments = parsedJson("departments").arr.map { departmentJson => 3 val deptName = departmentJson("name").str 4 val deptHead = departmentJson("head").str 5 val employees = departmentJson("employees").arr.map { employeeJson => 6 Employee( 7 name = employeeJson("name").str, 8 position = employeeJson("position").str, 9 experience = employeeJson("experience").num.toInt 10 ) 11 }.toSeq 12 Department(deptName, deptHead, employees) 13}.toSeq

Here's a detailed breakdown of how we do this:

  • Access the JSON Array:

    • We use parsedJson("departments").arr to obtain an array of department JSON objects.
  • Map to Scala Objects:

    • We utilize arr.map to iterate over each department JSON object and transform them into Department instances.
  • Extract and Convert Values:

    • We use .str to extract string values for "name" and "head", ensuring the data is treated as a String type.
    • For each employee, we extract "name" and "position" with .str, and we access "experience" as a number using .num, followed by .toInt conversion to an integer for proper usage in Scala.
  • Assemble into Sequences:

    • We convert arrays of employee JSON objects into sequences of Employee objects using arr.map.
    • We gather these results into a sequence of Department objects using .toSeq, facilitating further processing in Scala.

By following these steps, we efficiently transform the JSON data into Scala objects that match the original JSON structure.

Processing the Data

Once our JSON data is mapped into Scala objects, the next step involves iterating through arrays. JSON arrays, represented as Seq[T] in Scala, can be traversed using idiomatic methods like map and foreach to access elements for data processing. For our example, this means iterating through each department and its employees to compute the average experience of employees.

Here's how you can process the JSON arrays:

Scala
1// Initialize variables to calculate total experience and count of employees 2var totalExperience = 0 3var employeeCount = 0 4 5// Loop through each department 6departments.foreach { department => 7 // Loop through each employee in the department 8 department.employees.foreach { employee => 9 totalExperience += employee.experience 10 employeeCount += 1 11 } 12} 13 14// Calculate and display the average experience if employees are found 15if (employeeCount > 0) { 16 val averageExperience = totalExperience.toDouble / employeeCount 17 println(s"Average Employees' Experience: $averageExperience years") 18} else { 19 println("No employees were found.") 20}

This Scala code efficiently processes the JSON array of departments by iterating over each employee, summing up their experiences, and computing the average.

Summary and Preparation for Practice Exercises

In this lesson, you learned how to transform JSON arrays into usable Scala objects, enabling efficient iteration and data extraction. We covered the conversion of JSON structures into Scala case classes and demonstrated how to process these objects to perform tasks such as computing aggregated results. As you move on to the practice exercises, you'll apply these concepts to further develop your ability to handle JSON data in Scala, enhancing your skills in managing complex data tasks efficiently. Good luck, and happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.