View Javadoc
1   /**
2    *    Copyright 2009-2015 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
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  
26  import org.apache.ibatis.io.Resources;
27  
28  /**
29   * @author Clinton Begin
30   */
31  public class UnknownTypeHandler extends BaseTypeHandler<Object> {
32  
33    private static final ObjectTypeHandler OBJECT_TYPE_HANDLER = new ObjectTypeHandler();
34  
35    private TypeHandlerRegistry typeHandlerRegistry;
36  
37    public UnknownTypeHandler(TypeHandlerRegistry typeHandlerRegistry) {
38      this.typeHandlerRegistry = typeHandlerRegistry;
39    }
40  
41    @Override
42    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
43        throws SQLException {
44      TypeHandler handler = resolveTypeHandler(parameter, jdbcType);
45      handler.setParameter(ps, i, parameter, jdbcType);
46    }
47  
48    @Override
49    public Object getNullableResult(ResultSet rs, String columnName)
50        throws SQLException {
51      TypeHandler<?> handler = resolveTypeHandler(rs, columnName);
52      return handler.getResult(rs, columnName);
53    }
54  
55    @Override
56    public Object getNullableResult(ResultSet rs, int columnIndex)
57        throws SQLException {
58      TypeHandler<?> handler = resolveTypeHandler(rs.getMetaData(), columnIndex);
59      if (handler == null || handler instanceof UnknownTypeHandler) {
60        handler = OBJECT_TYPE_HANDLER;
61      }
62      return handler.getResult(rs, columnIndex);
63    }
64  
65    @Override
66    public Object getNullableResult(CallableStatement cs, int columnIndex)
67        throws SQLException {
68      return cs.getObject(columnIndex);
69    }
70  
71    private TypeHandler<? extends Object> resolveTypeHandler(Object parameter, JdbcType jdbcType) {
72      TypeHandler<? extends Object> handler;
73      if (parameter == null) {
74        handler = OBJECT_TYPE_HANDLER;
75      } else {
76        handler = typeHandlerRegistry.getTypeHandler(parameter.getClass(), jdbcType);
77        // check if handler is null (issue #270)
78        if (handler == null || handler instanceof UnknownTypeHandler) {
79          handler = OBJECT_TYPE_HANDLER;
80        }
81      }
82      return handler;
83    }
84  
85    private TypeHandler<?> resolveTypeHandler(ResultSet rs, String column) {
86      try {
87        Map<String,Integer> columnIndexLookup;
88        columnIndexLookup = new HashMap<String,Integer>();
89        ResultSetMetaData rsmd = rs.getMetaData();
90        int count = rsmd.getColumnCount();
91        for (int i=1; i <= count; i++) {
92          String name = rsmd.getColumnName(i);
93          columnIndexLookup.put(name,i);
94        }
95        Integer columnIndex = columnIndexLookup.get(column);
96        TypeHandler<?> handler = null;
97        if (columnIndex != null) {
98          handler = resolveTypeHandler(rsmd, columnIndex);
99        }
100       if (handler == null || handler instanceof UnknownTypeHandler) {
101         handler = OBJECT_TYPE_HANDLER;
102       }
103       return handler;
104     } catch (SQLException e) {
105       throw new TypeException("Error determining JDBC type for column " + column + ".  Cause: " + e, e);
106     }
107   }
108 
109   private TypeHandler<?> resolveTypeHandler(ResultSetMetaData rsmd, Integer columnIndex) throws SQLException {
110     TypeHandler<?> handler = null;
111     JdbcType jdbcType = safeGetJdbcTypeForColumn(rsmd, columnIndex);
112     Class<?> javaType = safeGetClassForColumn(rsmd, columnIndex);
113     if (javaType != null && jdbcType != null) {
114       handler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType);
115     } else if (javaType != null) {
116       handler = typeHandlerRegistry.getTypeHandler(javaType);
117     } else if (jdbcType != null) {
118       handler = typeHandlerRegistry.getTypeHandler(jdbcType);
119     }
120     return handler;
121   }
122 
123   private JdbcType safeGetJdbcTypeForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
124     try {
125       return JdbcType.forCode(rsmd.getColumnType(columnIndex));
126     } catch (Exception e) {
127       return null;
128     }
129   }
130 
131   private Class<?> safeGetClassForColumn(ResultSetMetaData rsmd, Integer columnIndex) {
132     try {
133       return Resources.classForName(rsmd.getColumnClassName(columnIndex));
134     } catch (Exception e) {
135       return null;
136     }
137   }
138 }