Suppose I asked you to take a cup from the multiple choices in the header photo, certainly you'll ask which one to choose as there is many cups and you need something precise and maybe unique by cup to decide.
All the choices are cups, they share some common points (color, weight, ...) but maybe each one has something that the other cups don't have. This is polymorphism.
This post has a working code example available here.
What's polymorphism ?
Polymorphism is the ability to have different implementations represented by a single interface or abstract class.
This post is about how to deserialize objects by their abstract. Same idea presented below can be used to serialize objects.
Let's consider the following abstraction :
Suppose you have an POST endpoint which supports creation of multiple objects by abstraction. Something like : you POST /players when PLAYER can be FootballPlayer, TennisPlayer or BasketPlayer.
If we go directly invoking the /players endpoint, we'll face the
InvalidDefinitionException as Jackson can't define to which class instance the PLAYER request body should be deserialized.
What's Jackson ?
As claimed by it's creators :
Jackson has been known as "the Java JSON library" or "the best JSON parser for Java". Or simply as "JSON for Java".
Simply, Jackson is a Java library to serialize and deserialize objects to/from JSON.
I'll use Spring Boot in this post but if you want to go without it, just grab the latest dependency of Jackson Databind on Maven Central.
The deserialization part will have to determine which concrete class the JSON represents, and instantiate an instance of it.
Deserialization using annotation
Using annotation is probably the most used technique because of it's simplicity and time-saving, but sometimes it's impossible to go with it.
Deserialization with no annotation
Not every project gives the possibility to add annotations on your domain classes.
Sometimes, your domain classes (Player, FootballPlayer, ...) are hidden behind an imported jar dependency and you can't access them for annotating
you are using DDD and hexagonal architecture where purists say :
No framework or libraries inside the domain
simply because of some technical constraints in your company/project.
First thing to do is to create a custom Jackson deserializer and implement the logic of deserialization.
To implement a custom deserializer, we need to create an implementation of
StdDeserializer which is an abstract type and the base class for common Jackson deserializers.
Few lines above, we exposed our abstraction of Player. Let's create an enum to distinguish the different Player instances.
As now we defined our
SportType enum, based on that we can implement in details our
deserialize method. Here we can take the benefit of this
sportType field inside our abstract class PLAYER.
The last step to do before going ready for deserialization is to indicate that our
PlayerDeserializer is a part of Jackson serializers/deserializers. Two possibilities available here :
- Register the
PlayerDeserializermanually while adding it to the ObjectMapper (Example in the source code).
- As we use Spring Boot, we can use the
@JsonComponentwhich do the same behavior but with less lines of code.
Maybe you're asking why we have this annotation as the title indicates "FREE ANNOTATIONS"? .
@JsonComponent is a Spring Boot annotation and not a part of Jackson and it lives in our newly created deserializer.
Another question can be :
What if we don't have this kind of "type" in our abstract class (e.g
In this case, we can change a little bit our
deserialize method to inspect fields of each PLAYER instance (looking for something unique by each instance).
In this post, we learned how to handle, in the same endpoint, variable requests (polymorphism) in Jackson by using custom deserializer and without polluting our domain classes with annotations and external libraries.