Skip to main content
  1. Articles/

Configure Jackson Object Mapper to Avoid Exception during Serializing a Lazy Loaded Hibernate Entity

·3 mins
Mayukh Datta
Technical Spring Boot

Ah, the timeless classic in the world of software engineering – the production issue that decides to make its grand entrance on a Friday night. 🚨 One such incident happened last week. Turns out, the bug was in one of the features that I recently worked on.

We are passing an entity to the Jackson’s Object Mapper to serialize it and return it as a JSON. The entity has some fields which are configured to lazy-load by Hibernate. Now, while serializing the entity we faced an unexpected behaviour. This was the bug that was breaking my API in production. However, I was a bit lucky here that this issue was confined to a particular scenario only. 😛

Here are the first few lines of the exception stack trace. Hibernate creates a proxy object for lazy-loaded entities and Jackson complains that it has no serializer for such a proxy object and it fails on serializing the hibernateLazyInitializer field specifically.

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception 
[Request processing failed; nested exception is java.lang.IllegalArgumentException: 
No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.project.entities.Bundle$HibernateProxy$AL8lPYBE["hibernateLazyInitializer"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor 
and no properties discovered to create BeanSerializer 
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) 
(through reference chain: com.project.entities.Bundle$HibernateProxy$AL8lPYBE["hibernateLazyInitializer"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:46)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:29)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
    at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:3389)

It appears that I easily identified the issue from the error log and plugged in the solution, but that wasn’t the case. I was actually stuck for hours. It wasn’t until last night that I finally discovered the solution. My tech lead and I were so frustrated by this bug that yesterday, we made the decision to refactor our code to prevent this issue from occuring again. We were discussing the approach of passing a DTO instead of the entity to the Object Mapper for serialization. But this would entail significant refactoring efforts and, needless to say, fixing the unit tests as well. 😵‍💫 We should consider taking the refactor way afterwards but it’s crucial now to address the production issue at the earliest.

I learned that Hibernate adds hibernateLazyInitializer and handler as extra fields to the lazily-loaded entity. We need to mark these fields as ignored for serialization. There are two ways we can do this.

  1. Annotating the entity class with
 @JsonIgnoreProperties(ignoreUnknown = true, value = {"hibernateLazyInitializer", "handler"})
  1. Configuring the object mapper to ignore these fields. Create a private interface inside the class that autowires the Object Mapper and annotate the interface with @JsonIgnoreProperties
objectMapper.addMixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
...
@JsonIgnoreProperties(ignoreUnknown = true, value = {"hibernateLazyInitializer", "handler"})
  private interface IgnoreHibernatePropertiesInJackson {}

I took the second way and configured the Object Mapper itself so that it can work with all the entity classes.

It was quite a journey going through the debugging process and resolving it. It’s amazing how software engineering can sometimes feel like an epic quest with its own set of challenges and triumphs!