1 package com.vladmihalcea.hibernate.type.json;
2
3 import com.fasterxml.jackson.databind.ObjectMapper;
4 import com.vladmihalcea.hibernate.type.AbstractHibernateType;
5 import com.vladmihalcea.hibernate.type.json.internal.JsonSqlTypeDescriptor;
6 import com.vladmihalcea.hibernate.type.json.internal.JsonTypeDescriptor;
7 import com.vladmihalcea.hibernate.type.util.Configuration;
8 import com.vladmihalcea.hibernate.type.util.ObjectMapperWrapper;
9 import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
10 import org.hibernate.usertype.DynamicParameterizedType;
11 import org.hibernate.usertype.ParameterizedType;
12
13 import javax.persistence.Column;
14 import java.lang.reflect.Type;
15 import java.util.Properties;
16
17 /**
18  * <p>
19  * {@link JsonType} allows you to map any given JSON object (e.g., POJO, <code>Map&lt;String, Object&gt;</code>, List&lt;T&gt;, <code>JsonNode</code>) on any of the following database systems:
20  * </p>
21  * <ul>
22  * <li><strong>PostgreSQL</strong> - for both <strong><code>jsonb</code></strong> and <strong><code>json</code></strong> column types</li>
23  * <li><strong>MySQL</strong> - for the <strong><code>json</code></strong> column type</li>
24  * <li><strong>SQL Server</strong> - for the <strong><code>NVARCHAR</code></strong> column type storing JSON</li>
25  * <li><strong>Oracle</strong> - for the <strong><code>JSON</code></strong> column type if you're using Oracle 21c or the <strong><code>VARCHAR</code></strong> column type storing JSON if you're using an older Oracle version</li>
26  * <li><strong>H2</strong> - for the <strong><code>json</code></strong> column type</li>
27  * </ul>
28  * <p>
29  * If you switch to Oracle 21c from an older version, then you should also migrate your {@code JSON} columns to the native JSON type since this binary type performs better than
30  * {@code VARCHAR2} or {@code BLOB} column types.
31  * </p>
32  * <p>
33  * However, if you don't want to migrate to the new {@code JSON} data type,
34  * then you just have to provide the column type via the JPA {@link Column#columnDefinition()} attribute,
35  * like in the following example:
36  * </p>
37  * <pre>
38  * {@code @Type(}type = "com.vladmihalcea.hibernate.type.json.JsonType")
39  * {@code @Column(}columnDefinition = "VARCHAR2")
40  * </pre>
41  * <p>
42  * For more details about how to use the {@link JsonType}, check out <a href="https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/">this article</a> on <a href="https://vladmihalcea.com/">vladmihalcea.com</a>.
43  * </p>
44  * <p>
45  * If you are using <strong>Oracle</strong> and want to store JSON objects in a <code>BLOB</code> column type, then you can use the {@link JsonBlobType} instead. For more details, check out <a href="https://vladmihalcea.com/oracle-json-jpa-hibernate/">this article</a> on <a href="https://vladmihalcea.com/">vladmihalcea.com</a>.
46  * </p>
47  * <p>
48  * Or, you can use the {@link JsonType}, but you'll have to specify the underlying column type
49  * using the JPA {@link Column#columnDefinition()} attribute, like this:
50  * </p>
51  * <pre>
52  * {@code @Type(}type = "com.vladmihalcea.hibernate.type.json.JsonType")
53  * {@code @Column(}columnDefinition = "BLOB")
54  * </pre>
55  * @author Vlad Mihalcea
56  */

57 public class JsonType
58         extends AbstractHibernateType<Object> implements DynamicParameterizedType {
59
60     public static final JsonType INSTANCE = new JsonType();
61
62     public JsonType() {
63         super(
64             new JsonSqlTypeDescriptor(),
65             new JsonTypeDescriptor(Configuration.INSTANCE.getObjectMapperWrapper())
66         );
67     }
68
69     public JsonType(Type javaType) {
70         super(
71             new JsonSqlTypeDescriptor(),
72             new JsonTypeDescriptor(Configuration.INSTANCE.getObjectMapperWrapper(), javaType)
73         );
74     }
75
76     public JsonType(Configuration configuration) {
77         super(
78             new JsonSqlTypeDescriptor(configuration.getProperties()),
79             new JsonTypeDescriptor(configuration.getObjectMapperWrapper()),
80             configuration
81         );
82     }
83
84     public JsonType(ObjectMapper objectMapper) {
85         super(
86             new JsonSqlTypeDescriptor(),
87             new JsonTypeDescriptor(new ObjectMapperWrapper(objectMapper))
88         );
89     }
90
91     public JsonType(ObjectMapperWrapper objectMapperWrapper) {
92         super(
93             new JsonSqlTypeDescriptor(),
94             new JsonTypeDescriptor(objectMapperWrapper)
95         );
96     }
97
98     public JsonType(ObjectMapper objectMapper, Type javaType) {
99         super(
100             new JsonSqlTypeDescriptor(),
101             new JsonTypeDescriptor(new ObjectMapperWrapper(objectMapper), javaType)
102         );
103     }
104
105     public JsonType(ObjectMapperWrapper objectMapperWrapper, Type javaType) {
106         super(
107             new JsonSqlTypeDescriptor(),
108             new JsonTypeDescriptor(objectMapperWrapper, javaType)
109         );
110     }
111
112     public String getName() {
113         return "json";
114     }
115
116     @Override
117     public void setParameterValues(Properties parameters) {
118         ((JsonTypeDescriptor) getJavaTypeDescriptor()).setParameterValues(parameters);
119         SqlTypeDescriptor sqlTypeDescriptor = getSqlTypeDescriptor();
120         if (sqlTypeDescriptor instanceof ParameterizedType) {
121             ParameterizedType parameterizedType = (ParameterizedType) sqlTypeDescriptor;
122             parameterizedType.setParameterValues(parameters);
123         }
124     }
125 }