1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.type;
17
18 import java.sql.CallableStatement;
19 import java.sql.PreparedStatement;
20 import java.sql.ResultSet;
21 import java.sql.ResultSetMetaData;
22 import java.sql.SQLException;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.function.Supplier;
26
27 import org.apache.ibatis.io.Resources;
28 import org.apache.ibatis.session.Configuration;
29
30
31
32
33 public class UnknownTypeHandler extends BaseTypeHandler<Object> {
34
35 private static final ObjectTypeHandler OBJECT_TYPE_HANDLER = new ObjectTypeHandler();
36
37 private final Configuration config;
38 private final Supplier<TypeHandlerRegistry> typeHandlerRegistrySupplier;
39
40
41
42
43
44
45
46
47
48 public UnknownTypeHandler(Configuration configuration) {
49 this.config = configuration;
50 this.typeHandlerRegistrySupplier = configuration::getTypeHandlerRegistry;
51 }
52
53
54
55
56
57
58
59
60
61 @Deprecated
62 public UnknownTypeHandler(TypeHandlerRegistry typeHandlerRegistry) {
63 this.config = new Configuration();
64 this.typeHandlerRegistrySupplier = () -> typeHandlerRegistry;
65 }
66
67 @Override
68 public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
69 throws SQLException {
70 TypeHandler handler = resolveTypeHandler(parameter, jdbcType);
71 handler.setParameter(ps, i, parameter, jdbcType);
72 }
73
74 @Override
75 public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
76 TypeHandler<?> handler = resolveTypeHandler(rs, columnName);
77 return handler.getResult(rs, columnName);
78 }
79
80 @Override
81 public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
82 TypeHandler<?> handler = resolveTypeHandler(rs.getMetaData(), columnIndex);
83 if (handler == null || handler instanceof UnknownTypeHandler) {
84 handler = OBJECT_TYPE_HANDLER;
85 }
86 return handler.getResult(rs, columnIndex);
87 }
88
89 @Override
90 public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
91 return cs.getObject(columnIndex);
92 }
93
94 private TypeHandler<?> resolveTypeHandler(Object parameter, JdbcType jdbcType) {
95 TypeHandler<?> handler;
96 if (parameter == null) {
97 handler = OBJECT_TYPE_HANDLER;
98 } else {
99 handler = typeHandlerRegistrySupplier.get().getTypeHandler(parameter.getClass(), jdbcType);
100
101 if (handler == null || handler instanceof UnknownTypeHandler) {
102 handler = OBJECT_TYPE_HANDLER;
103 }
104 }
105 return handler;
106 }
107
108 private TypeHandler<?> resolveTypeHandler(ResultSet rs, String column) {
109 try {
110 Map<String, Integer> columnIndexLookup;
111 columnIndexLookup = new HashMap<>();
112 ResultSetMetaData rsmd = rs.getMetaData();
113 int count = rsmd.getColumnCount();
114 boolean useColumnLabel = config.isUseColumnLabel();
115 for (int i = 1; i <= count; i++) {
116 String name = useColumnLabel ? rsmd.getColumnLabel(i) : rsmd.getColumnName(i);
117 columnIndexLookup.put(name, i);
118 }
119 Integer columnIndex = columnIndexLookup.get(column);
120 TypeHandler<?> handler = null;
121 if (columnIndex != null) {
122 handler = resolveTypeHandler(rsmd, columnIndex);
123 }
124 if (handler == null || handler instanceof UnknownTypeHandler) {
125 handler = OBJECT_TYPE_HANDLER;
126 }
127 return handler;
128 } catch (SQLException e) {
129 throw new TypeException("Error determining JDBC type for column " + column + ". Cause: " + e, e);
130 }
131 }
132
133 private TypeHandler<?> resolveTypeHandler(ResultSetMetaData rsmd, Integer columnIndex) {
134 TypeHandler<?> handler = null;
135 JdbcType jdbcType = safeGetJdbcTypeForColumn(rsmd, columnIndex);
136 Class<?> javaType = safeGetClassForColumn(rsmd, columnIndex);
137 if (javaType != null && jdbcType != null) {
138 handler = typeHandlerRegistrySupplier.get().getTypeHandler(javaType, jdbcType);
139 } else if (javaType != null) {
140 handler = typeHandlerRegistrySupplier.get().getTypeHandler(javaType);
141 } else if (jdbcType != null) {
142 handler = typeHandlerRegistrySupplier.get().getTypeHandler(jdbcType);
143 }
144 return handler;
145 }
146
147 private JdbcType safeGetJdbcTypeForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
148 try {
149 return JdbcType.forCode(rsmd.getColumnType(columnIndex));
150 } catch (Exception e) {
151 return null;
152 }
153 }
154
155 private Class<?> safeGetClassForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
156 try {
157 return Resources.classForName(rsmd.getColumnClassName(columnIndex));
158 } catch (Exception e) {
159 return null;
160 }
161 }
162 }