diff --git a/persistence-modules/spring-data-jpa-repo-4/pom.xml b/persistence-modules/spring-data-jpa-repo-4/pom.xml
index c823391d9f..9b03f7fdfb 100644
--- a/persistence-modules/spring-data-jpa-repo-4/pom.xml
+++ b/persistence-modules/spring-data-jpa-repo-4/pom.xml
@@ -30,6 +30,11 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
+ io.hypersistence
+ hypersistence-utils-hibernate-55
+ ${hypersistance-utils-hibernate-55.version}
+
com.h2database
h2
@@ -47,6 +52,30 @@
guava
${guava.version}
+
+ org.projectlombok
+ lombok
+
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+
+
+ org.slf4j
+ slf4j-api
+ ${org.slf4j.version}
+
+
+ ch.qos.logback
+ logback-core
+ ${logback.version}
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
@@ -98,4 +127,9 @@
+
+ 3.7.0
+ 42.7.1
+
+
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/Address.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/Address.java
new file mode 100644
index 0000000000..976a232082
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/Address.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.data.persistence.json;
+
+import lombok.*;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode
+public class Address {
+
+ private String postCode;
+
+ private String city;
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/AddressAttributeConverter.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/AddressAttributeConverter.java
new file mode 100644
index 0000000000..736f5e8ec2
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/AddressAttributeConverter.java
@@ -0,0 +1,36 @@
+package com.baeldung.spring.data.persistence.json;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+
+@Converter
+@Slf4j
+public class AddressAttributeConverter implements AttributeConverter
{
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ @Override
+ public String convertToDatabaseColumn(Address address) {
+ try {
+ return objectMapper.writeValueAsString(address);
+ } catch (JsonProcessingException jpe) {
+ log.warn("Cannot convert Address into JSON");
+ return null;
+ }
+ }
+
+ @Override
+ public Address convertToEntityAttribute(String value) {
+ try {
+ return objectMapper.readValue(value, Address.class);
+ } catch (JsonProcessingException e) {
+ log.warn("Cannot convert JSON into Address");
+ return null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/JsonAttributeApplication.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/JsonAttributeApplication.java
new file mode 100644
index 0000000000..708b43a534
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/JsonAttributeApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.data.persistence.json;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class JsonAttributeApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(JsonAttributeApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentEntity.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentEntity.java
new file mode 100644
index 0000000000..c5fd31ddd3
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentEntity.java
@@ -0,0 +1,31 @@
+package com.baeldung.spring.data.persistence.json;
+
+import javax.persistence.*;
+
+import io.hypersistence.utils.hibernate.type.json.JsonBinaryType;
+import lombok.*;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+
+@Entity
+@Table(name = "student")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(of = {"id"})
+@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
+public class StudentEntity {
+
+ @Id
+ @Column(name = "student_id", length = 8)
+ private String id;
+
+ @Column(name = "admit_year", length = 4)
+ private String admitYear;
+
+ @Type(type = "jsonb")
+ @Column(name = "address", columnDefinition = "jsonb")
+ private Address address;
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentRepository.java
new file mode 100644
index 0000000000..bae8ab6ad9
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentRepository.java
@@ -0,0 +1,16 @@
+package com.baeldung.spring.data.persistence.json;
+
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface StudentRepository extends CrudRepository {
+
+ @Query(value = "SELECT * FROM student WHERE address->>'postCode' = :postCode", nativeQuery = true)
+ List findByAddressPostCode(@Param("postCode") String postCode);
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentStrEntity.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentStrEntity.java
new file mode 100644
index 0000000000..552cdeaed6
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentStrEntity.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.data.persistence.json;
+
+import javax.persistence.*;
+
+import lombok.*;
+
+@Entity
+@Table(name = "student_str")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(of = {"id"})
+public class StudentStrEntity {
+
+ @Id
+ @Column(name = "student_id", length = 8)
+ private String id;
+
+ @Column(name = "admit_year", length = 4)
+ private String admitYear;
+
+ @Convert(converter = AddressAttributeConverter.class)
+ @Column(name = "address", length = 500)
+ private Address address;
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentStrRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentStrRepository.java
new file mode 100644
index 0000000000..ce40166b22
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/json/StudentStrRepository.java
@@ -0,0 +1,16 @@
+package com.baeldung.spring.data.persistence.json;
+
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface StudentStrRepository extends CrudRepository {
+
+ @Query(value = "SELECT * FROM student WHERE address->>'postCode' = :postCode", nativeQuery = true)
+ List findByAddressPostCode(@Param("postCode") String postCode);
+
+}
diff --git a/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/json/JsonAttributeLiveTest.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/json/JsonAttributeLiveTest.java
new file mode 100644
index 0000000000..1242b3f2f4
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/json/JsonAttributeLiveTest.java
@@ -0,0 +1,76 @@
+package com.baeldung.spring.data.persistence.json;
+
+import org.junit.jupiter.api.*;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest(classes = JsonAttributeApplication.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class JsonAttributeLiveTest {
+
+ @Inject
+ private StudentStrRepository studentStrRepository;
+
+ @Inject
+ private StudentRepository studentRepository;
+
+ @Test
+ @Order(10)
+ void whenSaveAnStudentStrEntityAndFindById_thenTheRecordPresentsInDb() {
+ String studentId = "23876371";
+ String postCode = "KT6 7BB";
+
+ Address address = new Address(postCode, "London");
+ StudentStrEntity studentStrEntity = StudentStrEntity.builder()
+ .id(studentId)
+ .admitYear("2023")
+ .address(address)
+ .build();
+
+ StudentStrEntity savedStudentStrEntity = studentStrRepository.save(studentStrEntity);
+
+ Optional studentEntityOptional = studentStrRepository.findById(studentId);
+ assertThat(studentEntityOptional.isPresent()).isTrue();
+
+ studentStrEntity = studentEntityOptional.get();
+ assertThat(studentStrEntity.getId()).isEqualTo(studentId);
+ assertThat(studentStrEntity.getAddress().getPostCode()).isEqualTo(postCode);
+ }
+
+ @Test
+ @Order(20)
+ void whenSaveAnStudentEntityAndFindById_thenTheRecordPresentsInDb() {
+ String studentId = "23876371";
+ String postCode = "KT6 7BB";
+
+ Address address = new Address(postCode, "London");
+ StudentEntity studentEntity = StudentEntity.builder()
+ .id(studentId)
+ .admitYear("2023")
+ .address(address)
+ .build();
+
+ StudentEntity savedStudentEntity = studentRepository.save(studentEntity);
+
+ Optional studentEntityOptional = studentRepository.findById(studentId);
+ assertThat(studentEntityOptional.isPresent()).isTrue();
+
+ studentEntity = studentEntityOptional.get();
+ assertThat(studentEntity.getId()).isEqualTo(studentId);
+ assertThat(studentEntity.getAddress().getPostCode()).isEqualTo(postCode);
+ }
+
+ @Test
+ @Order(50)
+ void whenFindByAddressPostCode_thenReturnListIsNotEmpty() {
+ String postCode = "KT6 7BB";
+ List studentStrEntityList = studentStrRepository.findByAddressPostCode(postCode);
+ assertThat(studentStrEntityList).isNotEmpty();
+ }
+
+}
\ No newline at end of file