In this article, you'll learn how to map a dynamic JSON object to a Java class using Jackson. 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 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:
{
"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
:
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:
public class User {
public String name;
public String email;
private String[] roles;
private boolean admin;
private JsonNode address;
// ...
}
Finally, parse the above JSON object to verify that it works:
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:
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:
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:
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:
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
:
{
"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. — 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:
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:
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:
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 tutorial.
✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.