View Javadoc
1   /*
2    * Copyright 2004-2023 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    *    https://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 com.ibatis.sqlmap.engine.mapping.result;
17  
18  import com.ibatis.common.beans.ClassInfo;
19  import com.ibatis.common.beans.Probe;
20  import com.ibatis.common.beans.ProbeFactory;
21  import com.ibatis.sqlmap.client.SqlMapException;
22  import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
23  import com.ibatis.sqlmap.engine.scope.StatementScope;
24  import com.ibatis.sqlmap.engine.type.DomTypeMarker;
25  
26  import java.sql.ResultSet;
27  import java.sql.ResultSetMetaData;
28  import java.sql.SQLException;
29  import java.util.*;
30  
31  /**
32   * An automatic result map for simple stuff.
33   */
34  public class AutoResultMap extends ResultMap {
35  
36    /**
37     * Constructor to pass in the SqlMapExecutorDelegate.
38     *
39     * @param delegate
40     *          - the delegate
41     * @param allowRemapping
42     *          the allow remapping
43     */
44    public AutoResultMap(SqlMapExecutorDelegate delegate, boolean allowRemapping) {
45      super(delegate);
46      this.allowRemapping = allowRemapping;
47    }
48  
49    @Override
50    public synchronized Object[] getResults(StatementScope statementScope, ResultSet rs) throws SQLException {
51      if (allowRemapping || getResultMappings() == null) {
52        initialize(rs);
53      }
54      return super.getResults(statementScope, rs);
55    }
56  
57    @Override
58    public Object setResultObjectValues(StatementScope statementScope, Object resultObject, Object[] values) {
59      // synchronization is only needed when remapping is enabled
60      if (allowRemapping) {
61        synchronized (this) {
62          return super.setResultObjectValues(statementScope, resultObject, values);
63        }
64      }
65      return super.setResultObjectValues(statementScope, resultObject, values);
66    }
67  
68    /**
69     * Initialize.
70     *
71     * @param rs
72     *          the rs
73     */
74    private void initialize(ResultSet rs) {
75      if (getResultClass() == null) {
76        throw new SqlMapException(
77            "The automatic ResultMap named " + this.getId() + " had a null result class (not allowed).");
78      } else if (Map.class.isAssignableFrom(getResultClass())) {
79        initializeMapResults(rs);
80      } else if (getDelegate().getTypeHandlerFactory().getTypeHandler(getResultClass()) != null) {
81        initializePrimitiveResults(rs);
82      } else if (DomTypeMarker.class.isAssignableFrom(getResultClass())) {
83        initializeXmlResults(rs);
84      } else {
85        initializeBeanResults(rs);
86      }
87    }
88  
89    /**
90     * Initialize bean results.
91     *
92     * @param rs
93     *          the rs
94     */
95    private void initializeBeanResults(ResultSet rs) {
96      try {
97        ClassInfo classInfo = ClassInfo.getInstance(getResultClass());
98        String[] propertyNames = classInfo.getWriteablePropertyNames();
99  
100       Map propertyMap = new HashMap();
101       for (int i = 0; i < propertyNames.length; i++) {
102         propertyMap.put(propertyNames[i].toUpperCase(java.util.Locale.ENGLISH), propertyNames[i]);
103       }
104 
105       List resultMappingList = new ArrayList();
106       ResultSetMetaData rsmd = rs.getMetaData();
107       for (int i = 0, n = rsmd.getColumnCount(); i < n; i++) {
108         String columnName = getColumnIdentifier(rsmd, i + 1);
109         String upperColumnName = columnName.toUpperCase(java.util.Locale.ENGLISH);
110         String matchedProp = (String) propertyMap.get(upperColumnName);
111         Class type = null;
112         if (matchedProp == null) {
113           Probe p = ProbeFactory.getProbe(this.getResultClass());
114           try {
115             type = p.getPropertyTypeForSetter(this.getResultClass(), columnName);
116           } catch (Exception e) {
117             // TODO - add logging to this class?
118           }
119         } else {
120           type = classInfo.getSetterType(matchedProp);
121         }
122         if (type != null || matchedProp != null) {
123           ResultMapping resultMapping = new ResultMapping();
124           resultMapping.setPropertyName((matchedProp != null ? matchedProp : columnName));
125           resultMapping.setColumnName(columnName);
126           resultMapping.setColumnIndex(i + 1);
127           resultMapping.setTypeHandler(getDelegate().getTypeHandlerFactory().getTypeHandler(type)); // map
128                                                                                                     // SQL
129                                                                                                     // to
130                                                                                                     // JDBC
131                                                                                                     // type
132           resultMappingList.add(resultMapping);
133         }
134       }
135       setResultMappingList(resultMappingList);
136 
137     } catch (SQLException e) {
138       throw new RuntimeException("Error automapping columns. Cause: " + e);
139     }
140 
141   }
142 
143   /**
144    * Initialize xml results.
145    *
146    * @param rs
147    *          the rs
148    */
149   private void initializeXmlResults(ResultSet rs) {
150     try {
151       List resultMappingList = new ArrayList();
152       ResultSetMetaData rsmd = rs.getMetaData();
153       for (int i = 0, n = rsmd.getColumnCount(); i < n; i++) {
154         String columnName = getColumnIdentifier(rsmd, i + 1);
155         ResultMapping resultMapping = new ResultMapping();
156         resultMapping.setPropertyName(columnName);
157         resultMapping.setColumnName(columnName);
158         resultMapping.setColumnIndex(i + 1);
159         resultMapping.setTypeHandler(getDelegate().getTypeHandlerFactory().getTypeHandler(String.class));
160         resultMappingList.add(resultMapping);
161       }
162       setResultMappingList(resultMappingList);
163     } catch (SQLException e) {
164       throw new RuntimeException("Error automapping columns. Cause: " + e);
165     }
166   }
167 
168   /**
169    * Initialize map results.
170    *
171    * @param rs
172    *          the rs
173    */
174   private void initializeMapResults(ResultSet rs) {
175     try {
176       List resultMappingList = new ArrayList();
177       ResultSetMetaData rsmd = rs.getMetaData();
178       for (int i = 0, n = rsmd.getColumnCount(); i < n; i++) {
179         String columnName = getColumnIdentifier(rsmd, i + 1);
180         ResultMapping resultMapping = new ResultMapping();
181         resultMapping.setPropertyName(columnName);
182         resultMapping.setColumnName(columnName);
183         resultMapping.setColumnIndex(i + 1);
184         resultMapping.setTypeHandler(getDelegate().getTypeHandlerFactory().getTypeHandler(Object.class));
185         resultMappingList.add(resultMapping);
186       }
187 
188       setResultMappingList(resultMappingList);
189 
190     } catch (SQLException e) {
191       throw new RuntimeException("Error automapping columns. Cause: " + e);
192     }
193   }
194 
195   /**
196    * Initialize primitive results.
197    *
198    * @param rs
199    *          the rs
200    */
201   private void initializePrimitiveResults(ResultSet rs) {
202     try {
203       ResultSetMetaData rsmd = rs.getMetaData();
204       String columnName = getColumnIdentifier(rsmd, 1);
205       ResultMapping resultMapping = new ResultMapping();
206       resultMapping.setPropertyName(columnName);
207       resultMapping.setColumnName(columnName);
208       resultMapping.setColumnIndex(1);
209       resultMapping.setTypeHandler(getDelegate().getTypeHandlerFactory().getTypeHandler(getResultClass()));
210 
211       List resultMappingList = new ArrayList();
212       resultMappingList.add(resultMapping);
213 
214       setResultMappingList(resultMappingList);
215 
216     } catch (SQLException e) {
217       throw new RuntimeException("Error automapping columns. Cause: " + e);
218     }
219   }
220 
221   /**
222    * Gets the column identifier.
223    *
224    * @param rsmd
225    *          the rsmd
226    * @param i
227    *          the i
228    *
229    * @return the column identifier
230    *
231    * @throws SQLException
232    *           the SQL exception
233    */
234   private String getColumnIdentifier(ResultSetMetaData rsmd, int i) throws SQLException {
235     if (delegate.isUseColumnLabel()) {
236       return rsmd.getColumnLabel(i);
237     } else {
238       return rsmd.getColumnName(i);
239     }
240   }
241 
242 }