1 package com.vladmihalcea.hibernate.type.json.internal;
2
3 import com.vladmihalcea.hibernate.type.util.ParameterTypeUtils;
4 import com.vladmihalcea.hibernate.util.StringUtils;
5 import org.hibernate.dialect.*;
6 import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver;
7 import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
8 import org.hibernate.type.descriptor.ValueBinder;
9 import org.hibernate.type.descriptor.WrapperOptions;
10 import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
11 import org.hibernate.type.descriptor.sql.BasicBinder;
12 import org.hibernate.usertype.DynamicParameterizedType;
13 import org.hibernate.usertype.ParameterizedType;
14
15 import java.sql.*;
16 import java.util.Properties;
17
18
21 public class JsonSqlTypeDescriptor extends AbstractJsonSqlTypeDescriptor implements ParameterizedType {
22
23 private volatile Dialect dialect;
24 private volatile AbstractJsonSqlTypeDescriptor sqlTypeDescriptor;
25
26 private volatile Properties properties;
27
28 public JsonSqlTypeDescriptor() {
29 }
30
31 public JsonSqlTypeDescriptor(Properties properties) {
32 this.properties = properties;
33 }
34
35 @Override
36 public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
37 return new BasicBinder<X>(javaTypeDescriptor, this) {
38 @Override
39 protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
40 sqlTypeDescriptor(st.getConnection()).getBinder(javaTypeDescriptor).bind(
41 st, value, index, options
42 );
43 }
44
45 @Override
46 protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
47 throws SQLException {
48 sqlTypeDescriptor(st.getConnection()).getBinder(javaTypeDescriptor).bind(
49 st, value, name, options
50 );
51 }
52 };
53 }
54
55 @Override
56 protected Object extractJson(ResultSet rs, String name) throws SQLException {
57 return sqlTypeDescriptor(rs.getStatement().getConnection()).extractJson(rs, name);
58 }
59
60 @Override
61 protected Object extractJson(CallableStatement statement, int index) throws SQLException {
62 return sqlTypeDescriptor(statement.getConnection()).extractJson(statement, index);
63 }
64
65 @Override
66 protected Object extractJson(CallableStatement statement, String name) throws SQLException {
67 return sqlTypeDescriptor(statement.getConnection()).extractJson(statement, name);
68 }
69
70 private AbstractJsonSqlTypeDescriptor sqlTypeDescriptor(Connection connection) {
71 if (sqlTypeDescriptor == null) {
72 sqlTypeDescriptor = resolveSqlTypeDescriptor(connection);
73 }
74 return sqlTypeDescriptor;
75 }
76
77 private AbstractJsonSqlTypeDescriptor resolveSqlTypeDescriptor(Connection connection) {
78 try {
79 StandardDialectResolver dialectResolver = new StandardDialectResolver();
80 DatabaseMetaDataDialectResolutionInfoAdapter metaDataInfo = new DatabaseMetaDataDialectResolutionInfoAdapter(connection.getMetaData());
81 dialect = dialectResolver.resolveDialect(metaDataInfo);
82 if (dialect instanceof PostgreSQL81Dialect) {
83 return JsonBinarySqlTypeDescriptor.INSTANCE;
84 } else if (dialect instanceof H2Dialect) {
85 return JsonBytesSqlTypeDescriptor.INSTANCE;
86 } else if (dialect instanceof Oracle8iDialect) {
87 if (properties != null) {
88 DynamicParameterizedType.ParameterType parameterType = ParameterTypeUtils.resolve(properties);
89 if (parameterType != null) {
90 String columnType = ParameterTypeUtils.getColumnType(parameterType);
91 if (!StringUtils.isBlank(columnType)) {
92 switch (columnType) {
93 case "json":
94 return JsonBytesSqlTypeDescriptor.of(Database.ORACLE);
95 case "blob":
96 case "clob":
97 return JsonBlobSqlTypeDescriptor.INSTANCE;
98 case "varchar2":
99 case "nvarchar2":
100 return JsonStringSqlTypeDescriptor.INSTANCE;
101 }
102 }
103 }
104 }
105 if (metaDataInfo.getDatabaseMajorVersion() >= 21) {
106 return JsonBytesSqlTypeDescriptor.of(Database.ORACLE);
107 }
108 }
109 return JsonStringSqlTypeDescriptor.INSTANCE;
110 } catch (SQLException e) {
111 throw new IllegalStateException(e);
112 }
113 }
114
115 @Override
116 public int getSqlType() {
117 return sqlTypeDescriptor != null ?
118 sqlTypeDescriptor.getSqlType() :
119 super.getSqlType();
120 }
121
122 @Override
123 public void setParameterValues(Properties parameters) {
124 if (properties == null) {
125 properties = parameters;
126 } else {
127 properties.putAll(parameters);
128 }
129 }
130 }
131