How to customize the JSON Serializer used by Hibernate-Types

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.

So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!

Introduction

As already explained, the hibernate-types open-source project allows you to map JSON, ARRAY, PostgreSQL ENUM types and provides a simple way of adding immutable Hibernate Types.

After adding support for customizing the Jackson ObjectMapper, the next most-wanted issue was to provide a way to customize the JSON serializing mechanism.

In this article, you are going to see how you can customize the JSON serializer using hibernate-types.

Declarative configuration

The easiest way to achieve this goal is to set the hibernate.types.json.serializer configuration property in the hibernate.properties file:

hibernate.types.json.serializer=com.vladmihalcea.hibernate.type.json.configuration.CustomJsonSerializerSupplier

This property takes the fully-qualified class name of an implementation of the CustomJsonSerializerSupplier interface:

What’s nice about customizing the hibernate-types project is that you can use either the Hibernate-specific hibernate.properties or you can provide a hibernate-types.properties file if you cannot alter hibernate.properties.

You can even supply a different Java properties file via the hibernate-types.properties.path System property,

The CustomJsonSerializerSupplier can look as follows:

public class CustomJsonSerializerSupplier 
    implements JsonSerializerSupplier {

    @Override
    public JsonSerializer get() {
        return new CustomJsonSerializer();
    }
}

Here, for testing sake, we are using a custom CustomJsonSerializer that implements the JsonSerializer interface:

public class CustomJsonSerializer 
    implements JsonSerializer {

    private static boolean called;

    public static boolean isCalled() {
        return called;
    }

    public static void reset() {
        called = false;
    }

    @Override
    public <T> T clone(T value) {
        called = true;
        return JacksonUtil.clone(value);
    }
}

We are going to use the called static variable to check in our unit test if this method is called by hibernate-types.

assertFalse(CustomJsonSerializer.isCalled());

doInJPA(entityManager -> {
    Location location = new Location();
    location.setCountry("Romania");
    location.setCity("Cluj-Napoca");
    location.setReference(
        BigDecimal.valueOf(2.25262562526626D)
    );

    Event event = new Event();
    event.setId(1L);
    event.setLocation(location);
    entityManager.persist(event);
});

assertTrue(CustomJsonSerializer.isCalled());
CustomJsonSerializer.reset();
assertFalse(CustomJsonSerializer.isCalled());

doInJPA(entityManager -> {
    Event event = entityManager.find(Event.class, 1L);
    assertEquals(
        "2.25262562526626", 
        event.getLocation().getReference().toString()
    );
});

assertTrue(CustomJsonSerializer.isCalled());

As you can see, the CustomJsonSerializer is being used, so you can easily customize the way a given JSON object is serialized by hibernate-types.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

Because of the configuration mechanism, I introduced for customizing the ObjectMapper, it is very easy to add new configuration options, like this one which allows you to change the way a given JSON object is serialized by hibernate-types.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.