# How to map a dynamic JSON object with Jackson

By Atta Ur Rehman Shah (https://attacomsian.com/about). Published Nov 17, 2019, updated Oct 14, 2022. Topics: Java, JSON, Jackson.
Canonical URL: https://attacomsian.com/blog/jackson-map-dynamic-json-object

> A short tutorial to learn how to map a dynamic JSON object to a Java class using Jackson API.

In this article, you'll learn how to map a dynamic JSON object to a Java class using [Jackson](https://attacomsian.com/blog/jackson-read-write-json). It is easier to work with predefined JSON structures while using Jackson. 

However, the parser will fail when the JSON data contains unknown properties. You can either choose to [ignore these properties](https://attacomsian.com/blog/jackson-ignore-unknown-json-properties) or map them directly to the Java class.

Jackson provides multiple ways to handle the mapping of dynamic JSON objects into Java classes. 

Let us say we have the following JSON object:

```json
{
  "name": "John Doe",
  "email": "john.doe@example.com",
  "roles": [
    "Member",
    "Admin"
  ],
  "admin": true,
  "address": {
    "city": "New York City",
    "state": "New York",
    "zipCode": 66123,
    "country": "US"
  }
}
```

Now we want to map the above JSON object to the following Java class called `User`:

```java
public class User {

    public String name;
    public String email;
    private String[] roles;
    private boolean admin;

    public User() {
    }

    public User(String name, String email, String[] roles, boolean admin) {
        this.name = name;
        this.email = email;
        this.roles = roles;
        this.admin = admin;
    }

    // getters and setters, toString() .... (omitted for brevity)
}
```

As you can see above, the `User` class contains nearly all common JSON properties except `address`. We want to find an appropriate way to map this `address` property to a `User` object.

## Mapping dynamic properties using `JsonNode`

The most straightforward way of mapping dynamic JSON properties is to use the `JsonNode` class provided by Jackson. This class is capable of handling dynamic properties.

To use `JsonNode`, we need to specify it as a field in our `User` class, as shown below:

```java
public class User {

    public String name;
    public String email;
    private String[] roles;
    private boolean admin;
    private JsonNode address;
        
    // ...
}
```

Finally, [parse the above JSON object](https://attacomsian.com/blog/jackson-convert-java-object-to-from-json) to verify that it works:

```java
try {
    // JSON string
    String json = "{\"name\":\"John Doe\",\"email\":\"john.doe@example.com\"," +
            "\"roles\":[\"Member\",\"Admin\"],\"admin\":true,\"address\":{\"city\"" +
            ":\"New York City\",\"state\":\"New York\",\"zipCode\":66123," +
            "\"country\":\"US\"}}";

    // create object mapper instance
    ObjectMapper mapper = new ObjectMapper();

    // convert JSON string to Java Object
    User user = mapper.readValue(json, User.class);

    // print user object
    System.out.println(user);

    // get properties from the address
    System.out.println(user.getAddress().path("city").asText());
    System.out.println(user.getAddress().path("state").asText());

} catch (Exception ex) {
    ex.printStackTrace();
}
```

You should see the following output printed on the console:

```bash
User{name='John Doe', email='john.doe@example.com', roles=[Member, Admin], admin=true, 
address={"city":"New York City","state":"New York","zipCode":66123,"country":"US"}}
New York City
New York
```

The above solution works fine, but now we are dependent on the Jackson library as we have a `JsonNode` field.

## Mapping dynamic properties using `Map`

Another way of storing the dynamic JSON property like `address` is to use the Java `Map` collection. This will also remove the extra Jackson dependency.

Just change the `address` field data type to `Map<String, Object>` in the `User` class:

```java
public class User {

    public String name;
    public String email;
    private String[] roles;
    private boolean admin;
    private Map<String, Object> address;
    
        // ...
}
```

Let us now parse the above JSON object to see how it works:

```java
try {
    // JSON string
    String json = "{\"name\":\"John Doe\",\"email\":\"john.doe@example.com\"," +
            "\"roles\":[\"Member\",\"Admin\"],\"admin\":true,\"address\":{\"city\"" +
            ":\"New York City\",\"state\":\"New York\",\"zipCode\":66123," +
            "\"country\":\"US\"}}";

    // create object mapper instance
    ObjectMapper mapper = new ObjectMapper();

    // convert JSON string to Java Object
    User user = mapper.readValue(json, User.class);

    // print user object
    System.out.println(user);

    // get properties from the address
    System.out.println(user.getAddress().get("city"));
    System.out.println(user.getAddress().get("country"));

} catch (Exception ex) {
    ex.printStackTrace();
}
```

The above example will print the following on the console:

```bash
User{name='John Doe', email='john.doe@example.com', roles=[Member, Admin], admin=true, 
address={city=New York City, state=New York, zipCode=66123, country=US}}
New York City
US
```

## Mapping dynamic properties using `@JsonAnySetter`

The previous solutions are when the JSON object or the nested object only contains dynamic properties. However, sometimes we have a more complex situation where the JSON object contains dynamic and fixed properties.

Consider the following JSON object with two top-level unknown properties, `city` and `country`:

```json
{
  "name": "John Doe",
  "email": "john.doe@example.com",
  "roles": [
    "Member",
    "Admin"
  ],
  "admin": true,
  "city": "New York City",
  "country": "United States"
}
```

We can easily handle this kind of JSON structure as a dynamic JSON object. But it means that we cannot define known properties like `name`, `email`, etc. &mdash; we have to treat them as dynamic properties too.

For such use cases, Jackson provides the `@JsonAnySetter` annotation to specify a method for handling all unknown properties. This method accepts two parameters: the name and the value of the property:

```java
public class User {

    public String name;
    public String email;
    private String[] roles;
    private boolean admin;
    private Map<String, Object> address = new HashMap<>();

    @JsonAnySetter
    public void setAddress(String key, Object value) {
        address.put(key, value);
    }

    // ...
}
```

Since we are using a `Map` to store dynamic properties, the JSON parsing code is the same as the above:

```java
try {
    // JSON string
    String json = "{\"name\":\"John Doe\",\"email\":\"john.doe@example.com\"," +
            "\"roles\":[\"Member\",\"Admin\"],\"admin\":true,\"city\"" +
            ":\"New York City\",\"country\":\"United States\"}";

    // create object mapper instance
    ObjectMapper mapper = new ObjectMapper();

    // convert JSON string to Java Object
    User user = mapper.readValue(json, User.class);

    // print user object
    System.out.println(user);

    // get properties from the address
    System.out.println(user.getAddress().get("city"));
    System.out.println(user.getAddress().get("country"));

} catch (Exception ex) {
    ex.printStackTrace();
}
```

You should see the following output:

```bash
User{name='John Doe', email='john.doe@example.com', roles=[Member, Admin], admin=true,
address={country=United States, city=New York City}}
New York City
United States
```

For more Jackson examples, check out the [How to read and write JSON using Jackson in Java](https://attacomsian.com/blog/jackson-read-write-json) tutorial.
