How to Store JSON Data Using JPA and Hibernate
This tutorial shows how to store, query, and manipulate JSON data in PostgreSQL using JPA and Hibernate, covering native JSON/JSONB types, the Hypersistence JsonType, entity mapping, service and REST layers, WildFly configuration, and curl‑based testing.
Many relational databases now provide native support for JSON, including storage, indexing, querying, and manipulation. PostgreSQL, MySQL, SQL Server, and Oracle all offer JSON data types, with PostgreSQL supporting both json and jsonb since version 9.2.
PostgreSQL JSON/JSONB Example
Using PostgreSQL, create a temporary table with a jsonb column, insert a JSON document, and select it back:
create temp table test (data jsonb);
INSERT INTO test (data) VALUES ('{"name": "John", "age": 30, "email": "[email protected]"}');
SELECT * FROM test;The result shows the stored JSON object. The article recommends preferring jsonb for better storage and index efficiency, especially on PostgreSQL 9.4+.
Mapping JSON Types in Hibernate/JPA
Hibernate and JPA lack a built‑in JSON type, but a custom type can be bound using org.hibernate.annotations.Type. The Hypersistence library provides io.hypersistence.utils.hibernate.type.json.JsonType for this purpose.
import io.hypersistence.utils.hibernate.type.json.JsonType;
import org.hibernate.annotations.Type;
@Type(JsonType.class)
@Column(columnDefinition = "jsonb")
private MyClass;Alternatively, a Map<String, String> can be mapped:
@Type(JsonType.class)
@Column(columnDefinition = "jsonb")
private Map<String, String> properties = new HashMap<>();Entity Class
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Type(JsonType.class)
@Column(columnDefinition = "jsonb")
private Map<String, String> properties = new HashMap<>();
private String name;
private String surname;
// getters/setters omitted
}Service and REST Controller
The service class provides methods to insert an employee and to query employees by a JSON key using a PostgreSQL native query:
@ApplicationScoped
public class EmployeeService {
@PersistenceContext
private EntityManager em;
@Transactional
public void insertEmployee(Employee employee) {
em.persist(employee);
}
public List<Employee> findByRole(String role) {
return em.createNativeQuery(
"SELECT * FROM Employee WHERE properties ->> 'role' = :role", Employee.class)
.setParameter("role", role)
.getResultList();
}
public List<Employee> findAllEmployees() {
return em.createQuery("SELECT e FROM Employee e", Employee.class)
.getResultList();
}
}The REST resource exposes the service:
@Path("/employees")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class EmployeeResource {
@Inject
private EmployeeService employeeService;
@GET
public Response getAllEmployees() {
List<Employee> employees = employeeService.findAllEmployees();
return Response.ok(employees).build();
}
@POST
public Response createEmployee(Employee employee) {
employeeService.insertEmployee(employee);
return Response.ok("Employee created").build();
}
@GET
@Path("/byrole")
public List<Employee> findByRole(@QueryParam("role") String role) {
return employeeService.findByRole(role);
}
}Configuration for WildFly
Maven dependencies needed are Jakarta EE 10 API, Hypersistence Utils, and Hibernate Core:
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-63</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.1.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>Enable the org.hibernate.commons-annotations module in WEB-INF/jboss-deployment-structure.xml:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.hibernate.commons-annotations"/>
</dependencies>
</deployment>
</jboss-deployment-structure>Define a persistence unit in resources/META-INF/persistence.xml pointing to the WildFly datasource:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.1"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="my-persistence-unit">
<description>Sample Hibernate PostgreSQL Dialect</description>
<jta-data-source>java:/PostGreDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>Testing the Application
Use curl to create an employee:
curl -X POST -H "Content-Type: application/json" -d '{
"name": "Alice",
"surname": "Smith",
"properties": {
"department": "HR",
"role": "Manager"
}
}' http://localhost:8080/postgres-json/employeesThe response confirms creation. Then retrieve employees with role "Manager":
curl http://localhost:8080/postgres-json/employees/byrole?role=ManagerBoth commands succeed, demonstrating that JSON keys can be used to filter rows.
Conclusion
PostgreSQL’s native json and jsonb types enable efficient storage and querying of JSON data. Combined with JPA’s entity mapping and native query capabilities—augmented by Hypersistence’s JsonType —developers can achieve seamless integration between Java objects and JSON documents in a relational database.
JakartaEE China Community
JakartaEE China Community, official website: jakarta.ee/zh/community/china; gitee.com/jakarta-ee-china; space.bilibili.com/518946941; reply "Join group" to get QR code
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
