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 public UnknownTypeHandler(Configuration configuration) {
47 this.config = configuration;
48 this.typeHandlerRegistrySupplier = configuration::getTypeHandlerRegistry;
49 }
50
51
52
53
54
55
56
57 @Deprecated
58 public UnknownTypeHandler(TypeHandlerRegistry typeHandlerRegistry) {
59 this.config = new Configuration();
60 this.typeHandlerRegistrySupplier = () -> typeHandlerRegistry;
61 }
62
63 @Override
64 public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
65 throws SQLException {
66 TypeHandler handler = resolveTypeHandler(parameter, jdbcType);
67 handler.setParameter(ps, i, parameter, jdbcType);
68 }
69
70 @Override
71 public Object getNullableResult(ResultSet rs, String columnName)
72 throws SQLException {
73 TypeHandler<?> handler = resolveTypeHandler(rs, columnName);
74 return handler.getResult(rs, columnName);
75 }
76
77 @Override
78 public Object getNullableResult(ResultSet rs, int columnIndex)
79 throws SQLException {
80 TypeHandler<?> handler = resolveTypeHandler(rs.getMetaData(), columnIndex);
81 if (handler == null || handler instanceof UnknownTypeHandler) {
82 handler = OBJECT_TYPE_HANDLER;
83 }
84 return handler.getResult(rs, columnIndex);
85 }
86
87 @Override
88 public Object getNullableResult(CallableStatement cs, int columnIndex)
89 throws SQLException {
90 return cs.getObject(columnIndex);
91 }
92
93 private TypeHandler<?> resolveTypeHandler(Object parameter, JdbcType jdbcType) {
94 TypeHandler<?> handler;
95 if (parameter == null) {
96 handler = OBJECT_TYPE_HANDLER;
97 } else {
98 handler = typeHandlerRegistrySupplier.get().getTypeHandler(parameter.getClass(), jdbcType);
99
100 if (handler == null || handler instanceof UnknownTypeHandler) {
101 handler = OBJECT_TYPE_HANDLER;
102 }
103 }
104 return handler;
105 }
106
107 private TypeHandler<?> resolveTypeHandler(ResultSet rs, String column) {
108 try {
109 Map<String,Integer> columnIndexLookup;
110 columnIndexLookup = new HashMap<>();
111 ResultSetMetaData rsmd = rs.getMetaData();
112 int count = rsmd.getColumnCount();
113 boolean useColumnLabel = config.isUseColumnLabel();
114 for (int i = 1; i <= count; i++) {
115 String name = useColumnLabel ? rsmd.getColumnLabel(i) : rsmd.getColumnName(i);
116 columnIndexLookup.put(name,i);
117 }
118 Integer columnIndex = columnIndexLookup.get(column);
119 TypeHandler<?> handler = null;
120 if (columnIndex != null) {
121 handler = resolveTypeHandler(rsmd, columnIndex);
122 }
123 if (handler == null || handler instanceof UnknownTypeHandler) {
124 handler = OBJECT_TYPE_HANDLER;
125 }
126 return handler;
127 } catch (SQLException e) {
128 throw new TypeException("Error determining JDBC type for column " + column + ". Cause: " + e, e);
129 }
130 }
131
132 private TypeHandler<?> resolveTypeHandler(ResultSetMetaData rsmd, Integer columnIndex) {
133 TypeHandler<?> handler = null;
134 JdbcType jdbcType = safeGetJdbcTypeForColumn(rsmd, columnIndex);
135 Class<?> javaType = safeGetClassForColumn(rsmd, columnIndex);
136 if (javaType != null && jdbcType != null) {
137 handler = typeHandlerRegistrySupplier.get().getTypeHandler(javaType, jdbcType);
138 } else if (javaType != null) {
139 handler = typeHandlerRegistrySupplier.get().getTypeHandler(javaType);
140 } else if (jdbcType != null) {
141 handler = typeHandlerRegistrySupplier.get().getTypeHandler(jdbcType);
142 }
143 return handler;
144 }
145
146 private JdbcType safeGetJdbcTypeForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
147 try {
148 return JdbcType.forCode(rsmd.getColumnType(columnIndex));
149 } catch (Exception e) {
150 return null;
151 }
152 }
153
154 private Class<?> safeGetClassForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
155 try {
156 return Resources.classForName(rsmd.getColumnClassName(columnIndex));
157 } catch (Exception e) {
158 return null;
159 }
160 }
161 }