Jackson: using @JsonSerialize (or @JsonDeserialize) annotation to register a custom serializer (or deserializer)

In a previous post we saw how to create a custom JSON serializer (and also a custom deserializer) with Jackson and how to register it using the SimpleModule class. This approach, only possible starting from version 1.7, is defined by Jackson wiki page as the “recommended way to register a custom serializer”. This approach, however, assumes we do have access to the ObjectMapper object used to serialize and deserialize and we can then register with it the SimpleModule on which we added our serializer. In some cases this is not possible because the ObjectMapper, configured with the appropriate features, is centralized and not under our control and our classes are instead just entities that it expects to handle properly.
In a scenario like this we have to use an alternative method to register our serializer and to indicate that it should be used to serialize objects of a given class. This method consists in the use of @JsonSerialize annotation and its “using” property. More exactly, it is necessary to:

  • annotate with @JsonSerialize the class for which we want to define a custom serializer
  • set the “using” property of that annotation to the class that represents the custom serializer

The same approach can be used to register a custom deserializer, using the @JsonDeserialize annotation in the same way.

We can see an example, using the same classes defined in the previous article.
The class for which we defined and registered a custom JSON serializer and a deserializer was the following:

class SWEngineer {

    private long id;
    private String name;
    private String[] languages;

    public SWEngineer(long id, String name, String[] languages) {
        this.id = id;
        this.name = name;
        this.languages = languages;
    }

	// GETTERS AND SETTERS OMITTED

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("ID: ").append(this.id).append("\nNome: ")
                .append(this.name).append("\nLinguaggi:");

        for (String s: this.languages) {
            sb.append(" ").append(s);
        }
        return sb.toString();
    }
}

We then created the CustomSerializer and CustomDeserializer classes and we used them in a test class in order to serialize and deserialize a SWEngineer object, after adding them to a module and register it with the ObjectMapper in the following way:

SimpleModule mod = new SimpleModule("MyModule");
mod.addSerializer(new CustomSerializer(SWEngineer.class));
mod.addDeserializer(SWEngineer.class, new CustomDeserializer(SWEngineer.class));
mapper.registerModule(mod);

Now, as we said, we suppose we can no longer use this method for registering our custom objects on the mapper, so we modify the test class commenting the four lines of code just described. In the test class we don’t make any other change, and it finally looks like this:

public class CustomSerDeserExample {

    public static void main (String[] args) {

        SWEngineer swe1 = new SWEngineer(1, "Mark", new String[]{"Java", "Python", "C++", "Scala"});

        ObjectMapper mapper = new ObjectMapper();

//	WE DON'T USE THIS WAY ANYMORE
//      SimpleModule mod = new SimpleModule("MyModule");
//      mod.addSerializer(new CustomSerializer(SWEngineer.class));
//      mod.addDeserializer(SWEngineer.class, new CustomDeserializer(SWEngineer.class));
//      mapper.registerModule(mod);

        System.out.println("--- ORIGINAL OBJECT ---\n" + swe1);

        String s = null;

        try {
            s = mapper.writeValueAsString(swe1);
        }
        catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        System.out.println("\n--- JAVA to JSON (Custom) ---\n" + s);

        SWEngineer sweOut = null;
        try {
            sweOut = mapper.readValue(s, SWEngineer.class);

        }
        catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("\n--- JSON to JAVA ---\n" + sweOut);
    }
}

To indicate to use the custom serializer and deserializer for processing objects of SWEngineer class, as we saw at the beginning of the article, we can use @JsonSerialize and @JsonDeserialize Jackson annotations. So we are going to annotate SWEngineer class specifying, through the “using” property of both annotations, which are the classes to be used to serialize and deserialize its instances.

// HERE IS WHERE WE PUT THE ANNOTATIONS

@JsonSerialize(using=CustomSerializer.class)
@JsonDeserialize(using=CustomDeserializer.class)
class SWEngineer {

    private long id;
    private String name;
    private String[] languages;

    public SWEngineer(long id, String name, String[] languages) {
        this.id = id;
        this.name = name;
        this.languages = languages;
    }

    // GETTERS AND SETTERS OMITTED

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("ID: ").append(this.id).append("\nName: ")
                .append(this.name).append("\nLanguages:");

        for (String s: this.languages) {
            sb.append(" ").append(s);
        }
        return sb.toString();
    }
}

Getting back to the test class and trying to execute it we get the following result:

--- ORIGINAL OBJECT ---
ID: 1
Name: Mark
Languages: Java Python C++ Scala

--- JAVA to JSON (Custom) ---
{"id":1,"name":"Mark","languages":"Java;Python;C++;Scala;"}

--- JSON to JAVA ---
ID: 1
Name: Mark
Languages: Java Python C++ Scala

The result is the same that we achieved in the previous post, when we registered our custom serializer and deserializer using a SimpleModule and ObjectMapper. With this method, however, we didn’t need to perform any operation on any other object, but we just added annotations to our SWEngineer class.

The whole code of this example can be downloaded here:

One thought on “Jackson: using @JsonSerialize (or @JsonDeserialize) annotation to register a custom serializer (or deserializer)

  1. Pingback: Jackson JSON: difference between @JsonIgnore and @JsonIgnoreProperties annotations | Dede Blog

Leave a Reply

Your email address will not be published. Required fields are marked *