Core Java

Casting Maps into Complex Objects in Java

In Java, there is often a need to convert a Map to a complex object (POJO – Plain Old Java Object). This can arise in various scenarios, such as when working with JSON data or other forms of structured data. Direct casting from a Map to a POJO doesn’t work due to type incompatibility and the structure of data representation.

However, libraries like Jackson and Gson provide mechanisms to facilitate this conversion. This article will explore various methods to achieve this conversion using these libraries.

1. Understanding the Challenge: Why Direct Casting Fails

Direct casting fails because a Map is a collection of key-value pairs, where the keys are typically strings and the values are objects. A POJO, on the other hand, has a defined structure with fields of specific types. Casting directly from a Map to a POJO doesn’t provide the mechanism to match the keys of the Map to the fields of the POJO and doesn’t account for data type conversions.

public class MapToPojoWithJackson {
    // Creating the employee map
    private static final Map<String, Object> employeemap = Map.of(
            "department", new Department("Engineering", "Building A"),
            "name", "Omos",
            "projects", List.of(
                    new Project("Project A", "Developing new feature"),
                    new Project("Paris", "Bug fixing and maintenance")
            )
    );

    public static void main(String[] args) {
        // Attempting direct cast (will cause an error)
        Employee employee = (Employee) employeemap;
        System.out.println(employee);
       }
    }

In the above code, if we attempt to cast the Map<String, Object> directly to an Employee object will result in a ClassCastException. The output will look something like this:

Exception in thread "main" java.lang.ClassCastException:

This is not possible because a Map is fundamentally different from a POJO in terms of how data is structured and accessed. Java does not provide any built-in mechanism to automatically convert a Map to a POJO. This conversion typically requires a library like Jackson or Gson to handle the deserialization process.

2. Defining the Domain Class

Here’s an example of three domain classes: Employee, Department, and Project, demonstrating a scenario where an Employee belongs to one Department and can work on multiple Project objects.

Employee.java

public class Employee {

    private String name;
    private Department department;
    private List<Project> projects;

    // Constructors, getters, and setters
}

Department.java

public class Department {

    private String name;
    private String location;

    // Constructors, getters, and setters
}

Project.java

public class Project {
    
    private String name;
    private String description;

    // Constructors, getters, and setters

    
}

3. Cast Map to POJO with Jackson

Jackson is a popular library for processing JSON in Java. It can be used to convert a Map to a POJO using its ObjectMapper class.

Add Jackson Dependency

pom.xml

Add the following dependency to the project’s pom.xml:

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.1</version>
        </dependency>

Jackson Code Example

MapToPojoWithJackson.java

public class MapToPojoWithJackson {

    private static final Map<String, Object> employeemap = Map.of(
            "department", new Department("Engineering", "Building A"),
            "name", "Omos",
            "projects", List.of(
                    new Project("Project A", "Developing new feature"),
                    new Project("Paris", "Bug fixing and maintenance")
            )
    );

    public static void main(String[] args) { 

        ObjectMapper objectMapper = new ObjectMapper();
        Employee employee = objectMapper.convertValue(employeemap, Employee.class);

        System.out.println(employee);

    }
}

The code above initializes a Map named employeemap using the Map.of method. The map contains:

  • A key "department" with a value of a Department object.
  • A key "name" with a value of a String.
  • A key "projects" with a value of a List of Project objects.

ObjectMapper Initialization and Conversion:

  • ObjectMapper objectMapper = new ObjectMapper(); – Creates an instance of ObjectMapper.
  • Employee employee = objectMapper.convertValue(employeemap, Employee.class); – Converts the employeemap to an Employee object using the convertValue method of ObjectMapper.

In summary, the code initializes a map with values representing an employee’s details and uses Jackson’s ObjectMapper to convert this map into an Employee POJO.

Output:

Employee{name=Omos, department=Department{name=Engineering, location=Building A}, projects=[Project{name=Project A, description=Developing new feature}, Project{name=Paris, description=Bug fixing and maintenance}]}

Ignore Unknown Properties

To configure Jackson to ignore unknown properties during deserialization, we can use the @JsonIgnoreProperties annotation on our POJO classes or configure the ObjectMapper directly. This is useful when a Map may contain additional fields that are not present in the Java classes.

The @JsonIgnoreProperties annotation can be used on a class level to specify that unknown properties should be ignored during deserialization by adding the @JsonIgnoreProperties(ignoreUnknown = true) annotation to our domain classes.

@JsonIgnoreProperties(ignoreUnknown = true)
class Department {
    private String name;
    private String location;
}

We can also configure the ObjectMapper to globally ignore unknown properties.

        ObjectMapper objectMapper = new ObjectMapper();
        // Configure the mapper to ignore unknown properties
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        Employee employee = objectMapper.convertValue(employeemap, Employee.class);

Setting DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES to false configures Jackson to ignore unknown properties globally.

4. Cast Map to POJO with Gson

Gson is a Java library that can be used to convert Java Objects into their JSON representation and vice versa.

Add Gson Dependency

Add the following dependency to the project’s pom.xml:

pom.xml

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
</dependency>

Gson Code Example

Now, we can use Gson to map a Map to a domain object.

GsonMappingExample.java

public class GsonMappingExample {

    public static void main(String[] args) {
        
        Map<String, Object> employeeMap = new HashMap<>();
        employeeMap.put("name", "Alice Booker");

        Map<String, Object> departmentMap = new HashMap<>();
        departmentMap.put("name", "Sales");
        departmentMap.put("location", "Building C");

        Map<String, Object> project1Map = new HashMap<>();
        project1Map.put("name", "Project Epsilon");
        project1Map.put("description", "Write functional requirements");

        Map<String, Object> project2Map = new HashMap<>();
        project2Map.put("name", "Project Zeta");
        project2Map.put("description", "Write non-functional requirements");

        employeeMap.put("department", departmentMap);
        employeeMap.put("projects", List.of(project1Map, project2Map));

        Gson gson = new Gson();
        String jsonMap = gson.toJson(employeeMap);
        Employee employee = gson.fromJson(jsonMap, Employee.class);

        System.out.println(employee);
    }
}

In this example:

  • A Gson object is created to handle the JSON serialization and deserialization.
  • gson.toJson(employeeMap) serializes the employeeMap into a JSON string.
  • gson.fromJson(jsonMap, Employee.class) deserializes the JSON string back into an Employee object.

Output:

5. Conclusion

Direct casting from a Map to a POJO without using a library like Jackson or Gson does not work because of fundamental differences in data structure. To correctly perform such a conversion, we need to use a library that can handle the deserialization process, mapping the key-value pairs in a Map to the corresponding fields in the POJO.

This article explored various techniques for casting nested maps to POJOs in Java. We began by defining our domain classes—Employee, Department, and Project and then demonstrated how to use the Gson and Jackson library to convert a map into a POJO.

6. Download the Source Code

This was an example of how to cast a Map to a POJO (Plain Old Java Object) in Java.

Download
You can download the full source code of this example here: Java Cast Map to POJO

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button