DEV Community

Thomas
Thomas

Posted on • Originally published at bootify.io

Persisting JSON with Spring Data

Basically every modern database system has its own data type to persist JSON. Using this type ensures at least the correct formatting - mostly there are also other advantages such as faster I/O.

As Spring Boot developers we want to access the JSON field without manually handling the mapping between the Java entity and the database. In the best case we work exclusively with the Java classes that represent the JSON - the mapping with Jackson and Hibernate is happening transparently.

Technical backgrounds

Spring Data / Hibernate does not support JSON fields out-of-the-box, but there is a library that provides custom types for the most common database systems: hibernate-types. This is a fantastic open source library, please support it!

Let's assume we want to extend our microservice example and add a PartDetails field to the CarPart table. The JSON should have the following structure.

{
    "countryCode": "DE",
    "dimensions": {
        "width": 1500,
        "height": 744,
        "depth": 45
    },
    "weight": 3200
}
Enter fullscreen mode Exit fullscreen mode

  Example JSON we want to add to the car_part table

First we're adding the required dependency to our pom.xml. We're using Maven as in our initial example - Gradle would be no different.

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.16.2</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

  Adding the required depencency

Next we need the model classes representing our JSON. They're containing some validation constraints as well - that's optional but a good thing to ensure before persisting.

public class PartDetails {

    @NotNull
    @Size(max = 2)
    private String countryCode;

    @Valid
    private PartDetailsDimensions dimensions;

    private Long weight;

}

public class PartDetailsDimensions {

    @NotNull
    private Long width;

    @NotNull
    private Long height;

    @NotNull
    private Long depth;

}
Enter fullscreen mode Exit fullscreen mode

  Our new model classes, skipping the getters and setters

With this setup we can extend our CarPart entity in the following way.

@Entity
@TypeDefs({
    @TypeDef(name = "json", typeClass = JsonStringType.class)
})
public class CarPart {

    // ...

    @Column(columnDefinition = "json")
    @Type(type = "json")
    private PartDetails partDetails;

}
Enter fullscreen mode Exit fullscreen mode

  CarPart class with annotations for supporting JSON

A custom type definition @TypeDef(name = "json", ...) is registered at the class, which becomes active for the field by annotating it with @Type(type = "json"). In our case (MySQL) the class JsonStringType takes over the transformation of PartDetails to JSON. The value for columnDefinition must be "json".

Now we can directly work with the model classes in our code! The JSON is persisted by the custom type, using ObjectMapper in the background.

Creating the custom type in Bootify

Bootify's Free plan also supports JSON fields - just create your custom model in the Data Objects tab and select your model as a field type at the entity. Depending on the database a certain type and column definition is necessary - this is automatically preselected by Bootify together with all the setup around it.

We begin by clicking Start Project - no registration required. Then we go to the Data Objects tab and first create the object "PartDetailsDimensions" with its three fields.


  Adding the PartDetailsDimensions data object

Now we create the object "PartDetails". Since "PartDetailsDimensions" already exists, we can select it directly as a custom type.


  Adding the PartDetails

Finally we go back to the "Entities" tab and create the CarPart entity if not already existing. Here we can now add the field "partDetails" with its corresponding type PartDetails.


  Adding the new field to our entity

That's it! Reading and writing the partDetails now works like a charm without having to worry about any mappings. Bootify creates proper field types and annotations based on the selected database, and the runnable source code can be downloaded right away!

» Start Project on Bootify.io
 

Further readings

Map JSON objects with generic Hibernate types

Top comments (2)

Collapse
 
shailendra profile image
donkey sama

How do we query data within PartDetails here, using Spring Data? Can you support the artickles with some examples please?

Collapse
 
tleipzig profile image
Thomas

You can just access the partDetails field of the CartPart - for example if you have a query:
CarPart carPart = carPartRepository.findFirstByTypeCode("xyz");
The JSON will be loaded and deserialized and can be accessed with:
System.out.println(carPart.partDetails.countryCode);
Querying for JSON (find by partDetails.countryCode) is not directly supported by Spring Data. You would need to create a native query, using functionality of the underlying database (like json_contains).