├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── eu │ │ └── java │ │ └── pg │ │ └── jsonb │ │ ├── PgJsonApplication.java │ │ ├── dialect │ │ └── JSONBPostgreSQLDialect.java │ │ ├── domain │ │ ├── CommonPerson.java │ │ ├── Person.java │ │ ├── Professor.java │ │ ├── Student.java │ │ └── info │ │ │ ├── Info.java │ │ │ ├── ProfessorInfo.java │ │ │ └── StudentInfo.java │ │ ├── repository │ │ ├── CommonPersonRepository.java │ │ ├── ProfessorRepository.java │ │ └── StudentRepository.java │ │ └── types │ │ └── JSONBUserType.java └── resources │ └── application.properties └── test └── java └── eu └── java └── pg └── jsonb └── PgJsonDemoTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij 2 | .idea/ 3 | *.iml 4 | *.ipr 5 | *.iws 6 | 7 | # Maven 8 | target/ 9 | 10 | # Tests 11 | FORK_DIRECTORY_* 12 | 13 | # JRebel 14 | rebel.xml 15 | 16 | # Log Files 17 | *.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | spring-data-jpa usage of Postgres JSONB fields 2 | =============================================================== 3 | 4 | This simple project can be used as PoC in storing generically data in JSONB fields. 5 | In a scenario where profession specific information would be stored in joined tables, with the help of JSONB fields 6 | in Postgres we can store all the information in one table and avoid the table joins needed to retrieve all the 7 | required information about a person. 8 | 9 | What this PoC brings new is that specific entities : 10 | 11 | - Student 12 | - Professor 13 | 14 | can be handled in a type-safe manner : 15 | 16 | - Student class has a StudentInfo field 17 | - Professor class has a ProfessorInfo field 18 | 19 | On the other hand, if some batch processes need to deal with all the persons, this can be done with the help of 20 | CommonPerson class (and associated CommonPersonRepository). 21 | 22 | 23 | The table containing the persons (generated here by Hibernate) looks like this : 24 | 25 | ```sql 26 | 27 | CREATE TABLE person 28 | ( 29 | dtype character varying(31) NOT NULL, 30 | id bigint NOT NULL, 31 | email character varying(255), 32 | info jsonb, 33 | CONSTRAINT person_pkey PRIMARY KEY (id) 34 | ) 35 | WITH ( 36 | OIDS=FALSE 37 | ); 38 | ``` 39 | 40 | 41 | ## Incovenients 42 | 43 | The main inconvenient in using JSON fields seen in this project is that the json fields can not be queried 44 | (at least when using hibernate as JPA provider) via JPQL queries. 45 | The support of Postgres for JSON fields being considered specific (most of the other database engines don't deal 46 | with JSON/JSONB fields) lead to not having introduced direct support for it in JPA. 47 | 48 | This PoC there should give an idea on how to store generic data in a single table by using JSON fields, 49 | but it seems clear that, in order to query the data, native (Postgres specific) SQL should be used. 50 | 51 | 52 | 53 | ## Similar projects 54 | 55 | - https://github.com/brant-hwang/springboot-postgresql94-hibernate5-example.git 56 | - https://github.com/sasa7812/psql-cache-evict-POC.git 57 | 58 | psql-cache-evict-POC project (via eclipselink JPA provider) offers the possibility to execute queries 59 | related to JSON fields : 60 | 61 | ``` 62 | String jpql = "SELECT c FROM Course c where SQL('course_mapped ->> ''?'' = ''Second one''',c.name) "; 63 | ``` 64 | 65 | On the other hand, hibernate JPA provider doesn't support such constructs. 66 | 67 | 68 | ## Environment requirements 69 | - Java 8 70 | - Spring Boot 1.3.2.RELEASE 71 | - Hibernate 5.0.2 72 | - PostgreSQL 9.4 73 | - Maven 3 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | eu.java.pg.json 8 | postgres-jsonb-jpa 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 9.4.1207 13 | 1.3.2.RELEASE 14 | 4.2.4.RELEASE 15 | 5.0.7.Final 16 | 1.8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-jpa 23 | ${spring.boot.version} 24 | 25 | 26 | org.hibernate 27 | hibernate-entitymanager 28 | 29 | 30 | 31 | 32 | org.springframework 33 | spring-context 34 | ${spring.version} 35 | 36 | 37 | 38 | org.hibernate 39 | hibernate-entitymanager 40 | ${hibernate.version} 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | ${spring.boot.version} 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.postgresql 58 | postgresql 59 | ${postgresql.version} 60 | compile 61 | 62 | 63 | 64 | 65 | com.fasterxml.jackson.core 66 | jackson-databind 67 | 2.6.3 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-compiler-plugin 82 | 83 | 1.8 84 | 1.8 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/PgJsonApplication.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.transaction.annotation.EnableTransactionManagement; 6 | 7 | @SpringBootApplication 8 | @EnableTransactionManagement(proxyTargetClass = true) 9 | public class PgJsonApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(PgJsonApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/dialect/JSONBPostgreSQLDialect.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 3 | * use this file except in compliance with the License. You may obtain a copy of 4 | * the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | *

7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | * License for the specific language governing permissions and limitations under 11 | * the License. 12 | */ 13 | package eu.java.pg.jsonb.dialect; 14 | 15 | import eu.java.pg.jsonb.types.JSONBUserType; 16 | import org.hibernate.dialect.PostgreSQL94Dialect; 17 | 18 | import java.sql.Types; 19 | 20 | public class JSONBPostgreSQLDialect extends PostgreSQL94Dialect { 21 | 22 | public JSONBPostgreSQLDialect() { 23 | super(); 24 | registerColumnType(Types.JAVA_OBJECT, JSONBUserType.JSONB_TYPE); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/CommonPerson.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain; 2 | 3 | import eu.java.pg.jsonb.domain.info.Info; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.Inheritance; 7 | import javax.persistence.InheritanceType; 8 | import javax.persistence.Table; 9 | 10 | @Entity 11 | @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 12 | @Table(name = "person") 13 | public abstract class CommonPerson extends Person { 14 | 15 | public abstract void setInfo(T info); 16 | 17 | public abstract T getInfo(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/Person.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain; 2 | 3 | import javax.persistence.GeneratedValue; 4 | import javax.persistence.Id; 5 | import javax.persistence.MappedSuperclass; 6 | 7 | 8 | @MappedSuperclass 9 | public class Person { 10 | @Id 11 | @GeneratedValue 12 | protected Long id; 13 | 14 | protected String email; 15 | 16 | 17 | public Long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getEmail() { 26 | return email; 27 | } 28 | 29 | public void setEmail(String email) { 30 | this.email = email; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/Professor.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain; 2 | 3 | import eu.java.pg.jsonb.domain.info.ProfessorInfo; 4 | import eu.java.pg.jsonb.types.JSONBUserType; 5 | import org.hibernate.annotations.Parameter; 6 | import org.hibernate.annotations.Type; 7 | import org.hibernate.annotations.TypeDef; 8 | 9 | import javax.persistence.Column; 10 | import javax.persistence.Entity; 11 | 12 | @Entity 13 | @TypeDef(name = "professorJsonb", typeClass = JSONBUserType.class, parameters = { 14 | @Parameter(name = JSONBUserType.CLASS, value = "eu.java.pg.jsonb.domain.info.ProfessorInfo")}) 15 | public class Professor extends CommonPerson { 16 | 17 | @Type(type = "professorJsonb") 18 | @Column(name = "info") 19 | private ProfessorInfo info; 20 | 21 | public ProfessorInfo getInfo() { 22 | return info; 23 | } 24 | 25 | public void setInfo(ProfessorInfo info) { 26 | this.info = info; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "Professor{" + 32 | "id=" + id + 33 | ", email='" + email + '\'' + 34 | ", info=" + info + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/Student.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain; 2 | 3 | import eu.java.pg.jsonb.domain.info.StudentInfo; 4 | import eu.java.pg.jsonb.types.JSONBUserType; 5 | import org.hibernate.annotations.Parameter; 6 | import org.hibernate.annotations.Type; 7 | import org.hibernate.annotations.TypeDef; 8 | 9 | import javax.persistence.Column; 10 | import javax.persistence.Entity; 11 | 12 | @Entity 13 | @TypeDef(name = "studentJsonb", typeClass = JSONBUserType.class, parameters = { 14 | @Parameter(name = JSONBUserType.CLASS, value = "eu.java.pg.jsonb.domain.info.StudentInfo")}) 15 | public class Student extends CommonPerson { 16 | 17 | @Type(type = "studentJsonb") 18 | @Column(name = "info") 19 | private StudentInfo info; 20 | 21 | public StudentInfo getInfo() { 22 | return info; 23 | } 24 | 25 | public void setInfo(StudentInfo info) { 26 | this.info = info; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "Student{" + 32 | "id=" + id + 33 | ", email='" + email + '\'' + 34 | ", info=" + info + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/info/Info.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain.info; 2 | 3 | public interface Info { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/info/ProfessorInfo.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain.info; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | 6 | public class ProfessorInfo implements Info { 7 | private String firstName; 8 | private String lastName; 9 | private List courses; 10 | 11 | public String getFirstName() { 12 | return firstName; 13 | } 14 | 15 | public void setFirstName(String firstName) { 16 | this.firstName = firstName; 17 | } 18 | 19 | public String getLastName() { 20 | return lastName; 21 | } 22 | 23 | public void setLastName(String lastName) { 24 | this.lastName = lastName; 25 | } 26 | 27 | public List getCourses() { 28 | return courses; 29 | } 30 | 31 | public void setCourses(List courses) { 32 | this.courses = courses; 33 | } 34 | 35 | @Override 36 | public boolean equals(Object o) { 37 | if (this == o) return true; 38 | if (o == null || getClass() != o.getClass()) return false; 39 | ProfessorInfo that = (ProfessorInfo) o; 40 | return Objects.equals(firstName, that.firstName) && 41 | Objects.equals(lastName, that.lastName) && 42 | Objects.equals(courses, that.courses); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | return Objects.hash(firstName, lastName, courses); 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "ProfessorInfo{" + 53 | "firstName='" + firstName + '\'' + 54 | ", lastName='" + lastName + '\'' + 55 | ", courses=" + courses + 56 | '}'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/domain/info/StudentInfo.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.domain.info; 2 | 3 | import java.util.Objects; 4 | 5 | public class StudentInfo implements Info { 6 | private String firstName; 7 | private String lastName; 8 | private int age; 9 | 10 | public String getFirstName() { 11 | return firstName; 12 | } 13 | 14 | public void setFirstName(String firstName) { 15 | this.firstName = firstName; 16 | } 17 | 18 | public String getLastName() { 19 | return lastName; 20 | } 21 | 22 | public void setLastName(String lastName) { 23 | this.lastName = lastName; 24 | } 25 | 26 | public int getAge() { 27 | return age; 28 | } 29 | 30 | public void setAge(int age) { 31 | this.age = age; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object o) { 36 | if (this == o) return true; 37 | if (o == null || getClass() != o.getClass()) return false; 38 | StudentInfo that = (StudentInfo) o; 39 | return age == that.age && 40 | Objects.equals(firstName, that.firstName) && 41 | Objects.equals(lastName, that.lastName); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return Objects.hash(firstName, lastName, age); 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "StudentInfo{" + 52 | "firstName='" + firstName + '\'' + 53 | ", lastName='" + lastName + '\'' + 54 | ", age=" + age + 55 | '}'; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/repository/CommonPersonRepository.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.repository; 2 | 3 | import eu.java.pg.jsonb.domain.CommonPerson; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface CommonPersonRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/repository/ProfessorRepository.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.repository; 2 | 3 | import eu.java.pg.jsonb.domain.Professor; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ProfessorRepository extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/repository/StudentRepository.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb.repository; 2 | 3 | import eu.java.pg.jsonb.domain.Student; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface StudentRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/eu/java/pg/jsonb/types/JSONBUserType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 3 | * use this file except in compliance with the License. You may obtain a copy of 4 | * the License at 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | *

7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | * License for the specific language governing permissions and limitations under 11 | * the License. 12 | */ 13 | package eu.java.pg.jsonb.types; 14 | 15 | import com.fasterxml.jackson.core.JsonProcessingException; 16 | import com.fasterxml.jackson.databind.ObjectMapper; 17 | import org.hibernate.HibernateException; 18 | import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; 19 | import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; 20 | import org.hibernate.engine.spi.SessionImplementor; 21 | import org.hibernate.type.SerializationException; 22 | import org.hibernate.usertype.ParameterizedType; 23 | import org.hibernate.usertype.UserType; 24 | import org.postgresql.util.PGobject; 25 | 26 | import java.io.IOException; 27 | import java.io.Serializable; 28 | import java.sql.PreparedStatement; 29 | import java.sql.ResultSet; 30 | import java.sql.SQLException; 31 | import java.sql.Types; 32 | import java.util.ArrayList; 33 | import java.util.Collection; 34 | import java.util.HashSet; 35 | import java.util.List; 36 | import java.util.Properties; 37 | import java.util.Set; 38 | import java.util.stream.Collectors; 39 | 40 | public class JSONBUserType implements ParameterizedType, UserType { 41 | 42 | private static final ObjectMapper objectMapper = new ObjectMapper(); 43 | private static final ClassLoaderService classLoaderService = new ClassLoaderServiceImpl(); 44 | 45 | public static final String JSONB_TYPE = "jsonb"; 46 | public static final String CLASS = "CLASS"; 47 | 48 | private Class jsonClassType; 49 | 50 | @Override 51 | public Class returnedClass() { 52 | return Object.class; 53 | } 54 | 55 | @Override 56 | public int[] sqlTypes() { 57 | return new int[]{Types.JAVA_OBJECT}; 58 | } 59 | 60 | @Override 61 | public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws 62 | HibernateException, SQLException { 63 | try { 64 | final String json = resultSet.getString(names[0]); 65 | return json == null ? null : objectMapper.readValue(json, jsonClassType); 66 | } catch (IOException e) { 67 | throw new HibernateException(e); 68 | } 69 | } 70 | 71 | @Override 72 | public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws 73 | HibernateException, SQLException { 74 | try { 75 | final String json = value == null ? null : objectMapper.writeValueAsString(value); 76 | PGobject pgo = new PGobject(); 77 | pgo.setType(JSONB_TYPE); 78 | pgo.setValue(json); 79 | st.setObject(index, pgo); 80 | } catch (JsonProcessingException e) { 81 | throw new HibernateException(e); 82 | } 83 | } 84 | 85 | @Override 86 | public void setParameterValues(Properties parameters) { 87 | final String clazz = (String) parameters.get(CLASS); 88 | jsonClassType = classLoaderService.classForName(clazz); 89 | } 90 | 91 | @SuppressWarnings("unchecked") 92 | @Override 93 | public Object deepCopy(Object value) throws HibernateException { 94 | 95 | if (!(value instanceof Collection)) { 96 | return value; 97 | } 98 | 99 | Collection collection = (Collection) value; 100 | Collection collectionClone = CollectionFactory.newInstance(collection.getClass()); 101 | 102 | collectionClone.addAll(collection.stream().map(this::deepCopy).collect(Collectors.toList())); 103 | 104 | return collectionClone; 105 | } 106 | 107 | static final class CollectionFactory { 108 | @SuppressWarnings("unchecked") 109 | static > T newInstance(Class collectionClass) { 110 | if (List.class.isAssignableFrom(collectionClass)) { 111 | return (T) new ArrayList(); 112 | } else if (Set.class.isAssignableFrom(collectionClass)) { 113 | return (T) new HashSet(); 114 | } else { 115 | throw new IllegalArgumentException("Unsupported collection type : " + collectionClass); 116 | } 117 | } 118 | } 119 | 120 | @Override 121 | public boolean isMutable() { 122 | return true; 123 | } 124 | 125 | @Override 126 | public boolean equals(Object x, Object y) throws HibernateException { 127 | if (x == y) { 128 | return true; 129 | } 130 | 131 | if ((x == null) || (y == null)) { 132 | return false; 133 | } 134 | 135 | return x.equals(y); 136 | } 137 | 138 | @Override 139 | public int hashCode(Object x) throws HibernateException { 140 | assert (x != null); 141 | return x.hashCode(); 142 | } 143 | 144 | @Override 145 | public Object assemble(Serializable cached, Object owner) throws HibernateException { 146 | return deepCopy(cached); 147 | } 148 | 149 | @Override 150 | public Serializable disassemble(Object value) throws HibernateException { 151 | Object deepCopy = deepCopy(value); 152 | 153 | if (!(deepCopy instanceof Serializable)) { 154 | throw new SerializationException(String.format("%s is not serializable class", value), null); 155 | } 156 | 157 | return (Serializable) deepCopy; 158 | } 159 | 160 | @Override 161 | public Object replace(Object original, Object target, Object owner) throws HibernateException { 162 | return deepCopy(original); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:postgresql://localhost:5432/people 2 | spring.datasource.username=test 3 | spring.datasource.password=test 4 | spring.datasource.driver-class-name=org.postgresql.Driver 5 | 6 | spring.jpa.database-platform=eu.java.pg.jsonb.dialect.JSONBPostgreSQLDialect 7 | spring.jpa.show-sql=true 8 | spring.jpa.hibernate.ddl-auto=update -------------------------------------------------------------------------------- /src/test/java/eu/java/pg/jsonb/PgJsonDemoTest.java: -------------------------------------------------------------------------------- 1 | package eu.java.pg.jsonb; 2 | 3 | import eu.java.pg.jsonb.domain.CommonPerson; 4 | import eu.java.pg.jsonb.domain.Professor; 5 | import eu.java.pg.jsonb.domain.Student; 6 | import eu.java.pg.jsonb.domain.info.ProfessorInfo; 7 | import eu.java.pg.jsonb.domain.info.StudentInfo; 8 | import eu.java.pg.jsonb.repository.CommonPersonRepository; 9 | import eu.java.pg.jsonb.repository.ProfessorRepository; 10 | import eu.java.pg.jsonb.repository.StudentRepository; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.SpringApplicationConfiguration; 16 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 17 | 18 | import javax.persistence.EntityManager; 19 | import javax.persistence.PersistenceContext; 20 | import javax.persistence.Query; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import static org.hamcrest.MatcherAssert.assertThat; 25 | import static org.hamcrest.Matchers.equalTo; 26 | 27 | @RunWith(SpringJUnit4ClassRunner.class) 28 | @SpringApplicationConfiguration(classes = PgJsonApplication.class) 29 | public class PgJsonDemoTest { 30 | 31 | @Autowired 32 | private ProfessorRepository professorRepository; 33 | 34 | @Autowired 35 | private StudentRepository studentRepository; 36 | 37 | @Autowired 38 | private CommonPersonRepository commonPersonRepository; 39 | 40 | @PersistenceContext 41 | private EntityManager em; 42 | 43 | @Before 44 | public void setup(){ 45 | commonPersonRepository.deleteAll(); 46 | } 47 | 48 | @Test 49 | public void demoTest(){ 50 | Student student = new Student(); 51 | student.setEmail("student@pgjson.org"); 52 | StudentInfo studentInfo = new StudentInfo(); 53 | studentInfo.setAge(20); 54 | studentInfo.setFirstName("Johnny"); 55 | studentInfo.setLastName("Ventura"); 56 | student.setInfo(studentInfo); 57 | Student savedStudent = studentRepository.save(student); 58 | Student readStudent = studentRepository.findOne(savedStudent.getId()); 59 | System.out.println("************************************************************"); 60 | System.out.println(readStudent); 61 | System.out.println("************************************************************"); 62 | 63 | 64 | Professor professor = new Professor(); 65 | professor.setEmail("professor@pgjson.org"); 66 | ProfessorInfo professorInfo = new ProfessorInfo(); 67 | professorInfo.setFirstName("Archibald"); 68 | professorInfo.setLastName("Wisconsin"); 69 | List courses = new ArrayList<>(); 70 | courses.add("Physics"); 71 | courses.add("Mathematics"); 72 | professorInfo.setCourses(courses); 73 | professor.setInfo(professorInfo); 74 | Professor savedProfessor = professorRepository.save(professor); 75 | Professor readProfessor = professorRepository.findOne(savedProfessor.getId()); 76 | System.out.println("-----------------------------------------------------------"); 77 | System.out.println(readProfessor); 78 | System.out.println("-----------------------------------------------------------"); 79 | 80 | 81 | System.out.println("///////////////////////////////////////////////////////////"); 82 | List readCommonPersons = commonPersonRepository.findAll(); 83 | readCommonPersons.forEach(commonPerson -> System.out.println(commonPerson)); 84 | System.out.println("///////////////////////////////////////////////////////////"); 85 | } 86 | 87 | 88 | 89 | } 90 | --------------------------------------------------------------------------------