├── .gitignore
├── PostgresJSONB
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── org
│ │ │ └── thoughts
│ │ │ └── on
│ │ │ └── java
│ │ │ └── model
│ │ │ ├── MyEntity.java
│ │ │ ├── MyJson.java
│ │ │ ├── MyJsonType.java
│ │ │ ├── MyPostgreSQL94Dialect.java
│ │ │ └── package-info.java
│ └── resources
│ │ └── META-INF
│ │ └── persistence.xml
│ └── test
│ ├── java
│ └── org
│ │ └── thoughts
│ │ └── on
│ │ └── java
│ │ └── date
│ │ └── TestJsonbSupport.java
│ └── resources
│ ├── data.sql
│ └── log4j.properties
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | pom.xml.tag
3 | pom.xml.releaseBackup
4 | pom.xml.versionsBackup
5 | pom.xml.next
6 | release.properties
7 | dependency-reduced-pom.xml
8 | buildNumber.properties
9 | .mvn/timing.properties
10 |
--------------------------------------------------------------------------------
/PostgresJSONB/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | org.thoughts.on.java
6 | PostgresJSONB
7 | 1.0.0-SNAPSHOT
8 | jar
9 |
10 |
11 | 1.8
12 | 1.8
13 | UTF-8
14 | 5.1.0.Final
15 |
16 |
17 |
18 |
19 | org.hibernate
20 | hibernate-core
21 | ${hibernate.version}
22 |
23 |
24 | org.hibernate
25 | hibernate-entitymanager
26 | ${hibernate.version}
27 |
28 |
29 | org.hibernate.javax.persistence
30 | hibernate-jpa-2.1-api
31 | 1.0.0.Final
32 |
33 |
34 | junit
35 | junit
36 | 4.11
37 | test
38 |
39 |
40 | org.postgresql
41 | postgresql
42 | 9.4.1208
43 | test
44 |
45 |
46 | log4j
47 | log4j
48 | 1.2.17
49 | test
50 |
51 |
52 | org.slf4j
53 | slf4j-log4j12
54 | 1.7.16
55 | test
56 |
57 |
58 | com.fasterxml.jackson.core
59 | jackson-databind
60 | 2.7.4
61 |
62 |
63 |
--------------------------------------------------------------------------------
/PostgresJSONB/src/main/java/org/thoughts/on/java/model/MyEntity.java:
--------------------------------------------------------------------------------
1 | package org.thoughts.on.java.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | import javax.persistence.CascadeType;
8 | import javax.persistence.Column;
9 | import javax.persistence.Entity;
10 | import javax.persistence.GeneratedValue;
11 | import javax.persistence.GenerationType;
12 | import javax.persistence.Id;
13 | import javax.persistence.JoinColumn;
14 | import javax.persistence.JoinTable;
15 | import javax.persistence.ManyToMany;
16 | import javax.persistence.OneToMany;
17 | import javax.persistence.Version;
18 |
19 | import org.hibernate.annotations.Type;
20 |
21 | @Entity
22 | public class MyEntity {
23 |
24 | @Id
25 | @GeneratedValue(strategy = GenerationType.AUTO)
26 | @Column(name = "id", updatable = false, nullable = false)
27 | private Long id;
28 |
29 | @Column
30 | @Type(type = "MyJsonType")
31 | private MyJson jsonProperty;
32 |
33 | public Long getId() {
34 | return this.id;
35 | }
36 |
37 | public void setId(final Long id) {
38 | this.id = id;
39 | }
40 |
41 | public MyJson getJsonProperty() {
42 | return jsonProperty;
43 | }
44 |
45 | public void setJsonProperty(MyJson jsonProperty) {
46 | this.jsonProperty = jsonProperty;
47 | }
48 |
49 | @Override
50 | public boolean equals(Object obj) {
51 | if (this == obj) {
52 | return true;
53 | }
54 | if (!(obj instanceof MyEntity)) {
55 | return false;
56 | }
57 | MyEntity other = (MyEntity) obj;
58 | if (id != null) {
59 | if (!id.equals(other.id)) {
60 | return false;
61 | }
62 | }
63 | return true;
64 | }
65 |
66 | @Override
67 | public int hashCode() {
68 | final int prime = 31;
69 | int result = 1;
70 | result = prime * result + ((id == null) ? 0 : id.hashCode());
71 | return result;
72 | }
73 |
74 | @Override
75 | public String toString() {
76 | String result = getClass().getSimpleName() + " ";
77 | if (jsonProperty != null)
78 | result += "jsonProperty: " + jsonProperty.toString();
79 | return result;
80 | }
81 | }
--------------------------------------------------------------------------------
/PostgresJSONB/src/main/java/org/thoughts/on/java/model/MyJson.java:
--------------------------------------------------------------------------------
1 | package org.thoughts.on.java.model;
2 |
3 | import java.io.Serializable;
4 |
5 | public class MyJson implements Serializable {
6 |
7 | private String stringProp;
8 |
9 | private Long longProp;
10 |
11 | public String getStringProp() {
12 | return stringProp;
13 | }
14 |
15 | public void setStringProp(String stringProp) {
16 | this.stringProp = stringProp;
17 | }
18 |
19 | public Long getLongProp() {
20 | return longProp;
21 | }
22 |
23 | public void setLongProp(Long longProp) {
24 | this.longProp = longProp;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/PostgresJSONB/src/main/java/org/thoughts/on/java/model/MyJsonType.java:
--------------------------------------------------------------------------------
1 | package org.thoughts.on.java.model;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.IOException;
6 | import java.io.ObjectInputStream;
7 | import java.io.ObjectOutputStream;
8 | import java.io.Serializable;
9 | import java.io.StringWriter;
10 | import java.sql.PreparedStatement;
11 | import java.sql.ResultSet;
12 | import java.sql.SQLException;
13 | import java.sql.Types;
14 |
15 | import org.hibernate.HibernateException;
16 | import org.hibernate.engine.spi.SessionImplementor;
17 | import org.hibernate.usertype.UserType;
18 |
19 | import com.fasterxml.jackson.databind.ObjectMapper;
20 |
21 | public class MyJsonType implements UserType {
22 |
23 | @Override
24 | public int[] sqlTypes() {
25 | return new int[]{Types.JAVA_OBJECT};
26 | }
27 |
28 | @Override
29 | public Class returnedClass() {
30 | return MyJson.class;
31 | }
32 |
33 | @Override
34 | public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session,
35 | final Object owner) throws HibernateException, SQLException {
36 | final String cellContent = rs.getString(names[0]);
37 | if (cellContent == null) {
38 | return null;
39 | }
40 | try {
41 | final ObjectMapper mapper = new ObjectMapper();
42 | return mapper.readValue(cellContent.getBytes("UTF-8"), returnedClass());
43 | } catch (final Exception ex) {
44 | throw new RuntimeException("Failed to convert String to Invoice: " + ex.getMessage(), ex);
45 | }
46 | }
47 |
48 | @Override
49 | public void nullSafeSet(final PreparedStatement ps, final Object value, final int idx,
50 | final SessionImplementor session) throws HibernateException, SQLException {
51 | if (value == null) {
52 | ps.setNull(idx, Types.OTHER);
53 | return;
54 | }
55 | try {
56 | final ObjectMapper mapper = new ObjectMapper();
57 | final StringWriter w = new StringWriter();
58 | mapper.writeValue(w, value);
59 | w.flush();
60 | ps.setObject(idx, w.toString(), Types.OTHER);
61 | } catch (final Exception ex) {
62 | throw new RuntimeException("Failed to convert Invoice to String: " + ex.getMessage(), ex);
63 | }
64 | }
65 |
66 | @Override
67 | public Object deepCopy(final Object value) throws HibernateException {
68 | try {
69 | // use serialization to create a deep copy
70 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
71 | ObjectOutputStream oos = new ObjectOutputStream(bos);
72 | oos.writeObject(value);
73 | oos.flush();
74 | oos.close();
75 | bos.close();
76 |
77 | ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
78 | return new ObjectInputStream(bais).readObject();
79 | } catch (ClassNotFoundException | IOException ex) {
80 | throw new HibernateException(ex);
81 | }
82 | }
83 |
84 | @Override
85 | public boolean isMutable() {
86 | return true;
87 | }
88 |
89 | @Override
90 | public Serializable disassemble(final Object value) throws HibernateException {
91 | return (Serializable) this.deepCopy(value);
92 | }
93 |
94 | @Override
95 | public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
96 | return this.deepCopy(cached);
97 | }
98 |
99 | @Override
100 | public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
101 | return this.deepCopy(original);
102 | }
103 |
104 | @Override
105 | public boolean equals(final Object obj1, final Object obj2) throws HibernateException {
106 | if (obj1 == null) {
107 | return obj2 == null;
108 | }
109 | return obj1.equals(obj2);
110 | }
111 |
112 | @Override
113 | public int hashCode(final Object obj) throws HibernateException {
114 | return obj.hashCode();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/PostgresJSONB/src/main/java/org/thoughts/on/java/model/MyPostgreSQL94Dialect.java:
--------------------------------------------------------------------------------
1 | package org.thoughts.on.java.model;
2 |
3 | import java.sql.Types;
4 |
5 | import org.hibernate.dialect.PostgreSQL94Dialect;
6 |
7 | public class MyPostgreSQL94Dialect extends PostgreSQL94Dialect {
8 |
9 | public MyPostgreSQL94Dialect() {
10 | this.registerColumnType(Types.JAVA_OBJECT, "jsonb");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/PostgresJSONB/src/main/java/org/thoughts/on/java/model/package-info.java:
--------------------------------------------------------------------------------
1 | @org.hibernate.annotations.TypeDef(name = "MyJsonType", typeClass = MyJsonType.class)
2 |
3 | package org.thoughts.on.java.model;
--------------------------------------------------------------------------------
/PostgresJSONB/src/main/resources/META-INF/persistence.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Thougths on Java
5 | org.hibernate.jpa.HibernatePersistenceProvider
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/PostgresJSONB/src/test/java/org/thoughts/on/java/date/TestJsonbSupport.java:
--------------------------------------------------------------------------------
1 | package org.thoughts.on.java.date;
2 |
3 | import javax.persistence.EntityManager;
4 | import javax.persistence.EntityManagerFactory;
5 | import javax.persistence.Persistence;
6 |
7 | import org.apache.log4j.Logger;
8 | import org.junit.After;
9 | import org.junit.Assert;
10 | import org.junit.Before;
11 | import org.junit.Test;
12 | import org.thoughts.on.java.model.MyEntity;
13 | import org.thoughts.on.java.model.MyJson;
14 |
15 | import com.fasterxml.jackson.core.JsonProcessingException;
16 | import com.fasterxml.jackson.databind.ObjectMapper;
17 |
18 | public class TestJsonbSupport {
19 |
20 | Logger log = Logger.getLogger(this.getClass().getName());
21 |
22 | private EntityManagerFactory emf;
23 |
24 | @Before
25 | public void init() {
26 | emf = Persistence.createEntityManagerFactory("my-persistence-unit");
27 | }
28 |
29 | @After
30 | public void close() {
31 | emf.close();
32 | }
33 |
34 | @Test
35 | public void testJsonMapping() throws JsonProcessingException {
36 | log.info("... testJsonMapping ...");
37 |
38 | MyJson j = new MyJson();
39 | j.setLongProp(123L);
40 | j.setStringProp("abc");
41 |
42 | ObjectMapper mapper = new ObjectMapper();
43 | System.out.println(mapper.writeValueAsString(j));
44 | }
45 |
46 | @Test
47 | public void testCreateJsonbEntity() {
48 | log.info("... testCreateJsonbEntity ...");
49 |
50 | EntityManager em = emf.createEntityManager();
51 | em.getTransaction().begin();
52 |
53 | MyJson j = new MyJson();
54 | j.setLongProp(123L);
55 | j.setStringProp("abc");
56 |
57 | MyEntity e = new MyEntity();
58 | e.setJsonProperty(j);
59 | em.persist(e);
60 |
61 | em.getTransaction().commit();
62 | em.close();
63 | }
64 |
65 | @Test
66 | public void testUpdateJsonbEntity() {
67 | log.info("... testUpdateJsonbEntity ...");
68 |
69 | EntityManager em = emf.createEntityManager();
70 | em.getTransaction().begin();
71 |
72 | MyEntity e = em.find(MyEntity.class, 10000L);
73 |
74 | e.getJsonProperty().setStringProp("changed");
75 | e.getJsonProperty().setLongProp(789L);
76 |
77 | em.getTransaction().commit();
78 | em.close();
79 | }
80 |
81 | @Test
82 | public void testSelectJsonbEntity() {
83 | log.info("... testSelectJsonbEntity ...");
84 |
85 | EntityManager em = emf.createEntityManager();
86 | em.getTransaction().begin();
87 |
88 | MyEntity e = (MyEntity) em.createNativeQuery("SELECT * FROM myentity e WHERE e.jsonproperty->'longProp' = '456'", MyEntity.class).getSingleResult();
89 |
90 | Assert.assertNotNull(e.getJsonProperty());
91 | System.out.println("JSON: stringProp = "+e.getJsonProperty().getStringProp()+" longProp = "+e.getJsonProperty().getLongProp());
92 |
93 | em.getTransaction().commit();
94 | em.close();
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/PostgresJSONB/src/test/resources/data.sql:
--------------------------------------------------------------------------------
1 | INSERT INTO myentity (id, jsonproperty) VALUES (10000, '{"longProp": 456, "stringProp": "xyz"}');
--------------------------------------------------------------------------------
/PostgresJSONB/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
2 | log4j.appender.stdout.Target=System.out
3 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
4 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n
5 |
6 | #
7 | # Development
8 | #
9 | log4j.rootLogger=info, stdout
10 | # basic log level for all messages
11 | log4j.logger.org.hibernate=info
12 |
13 | # SQL statements and parameters
14 | log4j.logger.org.hibernate.SQL=debug
15 | #log4j.logger.org.hibernate.type.descriptor.sql=trace
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HibernateJSONBSupport
--------------------------------------------------------------------------------