Revisiting Java - intro to Jackson
Recently, I was asked to introduce some python developers to a java codebase. It was a nice opportunity to reflect(pun unintended) on java annotations, project structure and drawing comparisons/contrasts between the languages. The following is an excerpt from one such workshop
In many projects, a common task is to serialise/deserialise some inbound/outbound data from one format to another. In the context of the web, JSON is a fairly ubiquitous target.
When it comes to java, there is a no standard library support(outside EE releases) for json serialisation/deserialisation. To facilitate this, the majority of projects use a library called Jackson
Let's walk-through a simple example of parsing json from an inbound request into a domain transfer object POJO. Here we will receive a JSON object with several fields: name, age and email - and using jackson, annotate them appropriately
{
"name": "john",
"age": 20,
"email": "john@example.com"
}
And what we want is to convert this json into the corresponding java code:
@Value
public class UserDto {
String name;
int age;
String email;
}
In order to do that, we will use the @JsonProperty annotation. There are many annotations available for use - keeping things simple with @JsonPropery is appropriate for a lot of use-cases, it handles both serialisation and deserialisation.
@Value
public class UserDto {
@JsonProperty("name")
String Name;
@JsonProperty("age")
Int age;
@JsonProperty("email")
String email;
}
Finally what we need is an instance of the 'ObjectMapper' class. This is the actual object responsible for performing serialisation/deserialisation. Putting it all together, we have:
public class JsonParsingUserDtoTest {
@Test
void test_should_parse_valid_user_dto() {
String rawJson = "{\"name\": \"john\", \"age\": 20, \"email\": \"john@example.com\"}";
ObjectMapper objectMapper = new ObjectMapper();
try {
UserDto userDto = objectMapper.readValue(rawJson, UserDto.class);
assertEquals("john", userDto.getName());
assertEquals(20, userDto.getAge());
assertEquals("john@example.com", userDto.getEmail());
} catch (Exception e) {
e.printStackTrace();
}
}
}
What about polymorphism? We can manage that with @JsonTypeInfo &@JsonSubTypes
We start by defining our base class and decorating it with some annotations to indicate which properties to subtypes should be created based on that property:
@JsonTypeInfo(use= JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(name = "User", value = User.class),
@JsonSubTypes.Type (name = "Admin", value = Admin.class),
})
public abstract class UserType {
String type;
}
Followed by our actual subtype classes:
public class User extends UserType { // specific user fields }
public class Admin extends UserType {//specific admin fields}
Ok JSON is cool but what about YAML? We can simply provide a YAMLFactory:
new ObjectMapper(new YAMLFactory())