Toward a polyglot James server…
Java is convenient, everyone knows it, but for some tasks, Java is really annoying. Serializing stuff in JSON is one of them. Especially if you do not want to pollute your APIs with some JSON related annotations.
We are currently working in the Apache James email server on implementing a distributed event system, so serializing events is our burning topic! For the sake of this article, let’s serialize the following events…
Our common solution, until today, was to introduce a Data Transfer Objects:
Now that we have these DTOs, we can serialize them with Jackson.
Verbose, right? Of course, as we do want to invest in a better solution, we started looking in the Scala direction.
Scala has a very convenient feature: case classes. This ease modelling of immutable data: you don’t need to implement getter, equals, hash-code, etc… With this our DTOs become:
Notice the sealed trait: we can not define DTOs out of this file (this will be useful later for automatic derivation).
Now we need of course to serialize our DTOs. We chose the Play JSON library. First, let’s tell how to handle the fields that we get….
Looking in the Scala libraries, we found a very nice library doing “automatic derivation” for us… The following line will add a level in the JSON hierarchy for identifying the type of DTO, and automatically do derivation for our EventDTO sealed trait.
Automatic derivation leverages the fact that we are using a sealed trait for Event. This means that all Event subclasses are known in this file, and then the library will be able to de-serialize each one of them, inferring their type with a specific field.
Case class serialization can also be done automatically.
Now that this is done, we get our JSON serialization for free.
We just need some logic for transferring ourselves between the Scala world and the Java world, and call our serializers…
As we saw, Scala case classes and automatic derivation made our work way simpler. In our simple example, we replaced 127 lines of java code with 46 lines of Scala code. Not to mention that our JSON models are now defined at compile time while it is defined at run-time through reflection using Jackson.
The experiment being conclusive, we will, in the future, continue introducing in James components written in other JVM languages, where it makes sense and ease our job!