How to customize the Jackson Object Mapper used by Hibernate-Types

How to customize the Jackson Object Mapper used by Hibernate-Types
Techiio-author
Written by Sagar RabidasMarch 1, 2022
10 min read
Hibernate
1 VIEWS 0 LIKES 0 DISLIKES SHARE
0 LIKES 0 DISLIKES 1 VIEWS SHARE
Techiio-author
Sagar Rabidas

Software Developer

In this blog, we will discuss How to customize the Jackson ObjectMapper used by Hibernate-Types

Introduction of Jackson Object Mapper:-

Object mapper is the principal actor elegance of Jackson library. Object mapper magnificence object mapper gives functionality for analyzing and writing JSON, either to and from fundamental POJOs (simple antique java items) or to and from a trendy-cause JSON tree model (JsonNode), as well as related functionality for acting conversions. It is also fairly customizable to paintings both with distinctive sorts of JSON content material and to help more superior item standards inclusive of polymorphism and object identity. Object mapper also acts as a factory for extra superior object reader and object writer lessons.

Declarative configuration:-

The easiest way to achieve this goal is to set the hibernate.types.Jackson.object.mapper configuration property in the hibernate.properties file:

hibernate.types.jackson.object.mapper=com.vladmihalcea.hibernate.type.json.loader.CustomObjectMapperSupplier

What’s high-quality about customizing the hibernate-types project is that you may use both the hibernate-precise hibernate.Properties or you could provide a hibernate-types.properties report in case you can not alter hibernate.properties.

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

The CustomObjectMapperSupplier can look as follows:

public class CustomObjectMapperSupplier
    implements ObjectMapperSupplier {
 
    @Override
    public ObjectMapper get() {
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
         
        objectMapper.setTimeZone(
            TimeZone.getTimeZone("GMT")
        );
        SimpleModule simpleModule = new SimpleModule(
            "SimpleModule",
            new Version(1, 0, 0, null, null, null)
        );
        simpleModule.addSerializer(new MoneySerializer());
        objectMapper.registerModule(simpleModule);
         
        return objectMapper;
    }
}

Here, we are the usage of a custom ObjectMapper that uses our MoneySerializer for managing BigDecimal java item types:

public class MoneySerializer
    extends JsonSerializer<BigDecimal> {
 
    @Override
    public void serialize(
                BigDecimal value,
                JsonGenerator jsonGenerator,
                SerializerProvider provider)
            throws IOException {
        jsonGenerator.writeString(
            value.setScale(2, BigDecimal.ROUND_HALF_UP).toString()
        );
    }
 
    @Override
    public Class<BigDecimal> handledType() {
        return BigDecimal.class;
    }
}

So, if you are persisting the following Book entity which has a JSON properties attribute:

Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
    JacksonUtil.toJsonNode(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.991234567" +
        "}"
    )
);
 
entityManager.persist(book);

When fetching the Book entity, we can see that the BigDecimal takes only two decimals:

Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
 
assertEquals(
    "44.99",
    book.getProperties().get("price").asText()
);

Programmatic configuration:-

For even more flexibility, you can use the programmatic configuration.

Assuming we have the following Object type that we want to serialize as JSON:

public class Location
    implements Serializable {
 
    private String country;
 
    private String city;
 
    private BigDecimal reference;
 
    //Getters and setters omitted for brevity
}

And, we have an Event entity that maps the Location Java Object to a JSON PostgreSQL column type:

@Entity(name = "Event")
@Table(name = "event")
public class Event {
 
    @Id
    private Long id;
 
    @Type(type = "location")
    @Column(columnDefinition = "jsonb")
    private Location location;
 
    //Getters and setters omitted for brevity
}

We can use a custom ObjectMapper as follows:

JsonType jsonType = new JsonType(
    new CustomObjectMapperSupplier().get(),
    Location.class
);
 
properties.put("hibernate.type_contributors",
    (TypeContributorList) () -> Collections.singletonList(
        (typeContributions, serviceRegistry) ->
            typeContributions.contributeType(
                jsonType, "location"
            )
    )
);

The hibernate.type_contributors configuration property allows you to register custom Hibernate Types, and we can use this feature to provide our custom ObjectMapper to the JsonType provided by the hibernate-types project.

So, if we persist the following Event entity:

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);

When fetching the Event entity, we can see that the BigDecimal takes only two decimals:

Event event = entityManager.find(Event.class, 1L);
 
assertEquals("2.25", event.getLocation().getReference().toString());

Hibernate
Jackson object
Object Mapper
JSON
JavaScript
1 VIEWS 0 LIKES 0 DISLIKES SHARE
0 LIKES 0 DISLIKES 1 VIEWS SHARE
Was this blog helpful?
techiio-price-plantechiio-price-plantechiio-price-plantechiio-price-plantechiio-price-plan
You must be Logged in to comment
Code Block
Techiio-author
Sagar Rabidas
Software Developer
Techiio-followerTechiio-followerTechiio-followerTechiio-followerTechiio-follower
+8 more
300 Blog Posts
14 Discussion Threads
Trending Technologies
15
Software40
DevOps46
Frontend Development24
Backend Development20
Server Administration17
Linux Administration26
Data Center24
Sentry24
Terraform23
Ansible83
Docker70
Penetration Testing16
Kubernetes21
NGINX20
JenkinsX17
Techiio-logo

Techiio is on the journey to build an ocean of technical knowledge, scouring the emerging stars in process and proffering them to the corporate world.

Follow us on:

Subscribe to get latest updates

You can unsubscribe anytime from getting updates from us
Developed and maintained by Wikiance
Developed and maintained by Wikiance