package haotian.core.orm; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Timestamp; import java.util.*; import org.apache.commons.dbutils.RowProcessor; import org.apache.ddlutils.model.Column; import org.apache.ddlutils.model.Table; /** * * @author 湖北黄石 朱大志 * 扩展Apache Dbutils做的简易ORM,支持JPA Annotation * */ public class AnnotationRowProcessor implements RowProcessor { protected static final int PROPERTY_NOT_FOUND = -1; private static final Map<Class<?>, Object> primitiveDefaults = new HashMap<Class<?>, Object>(); static { primitiveDefaults.put(Integer.TYPE, 0); primitiveDefaults.put(Short.TYPE, (Short) ((short) 0)); primitiveDefaults.put(Byte.TYPE, (Byte) ((byte) 0)); primitiveDefaults.put(Float.TYPE, (Float) (float) (0)); primitiveDefaults.put(Double.TYPE, (Double) (double) (0)); primitiveDefaults.put(Long.TYPE, (Long) (0L)); primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE); primitiveDefaults.put(Character.TYPE, '\u0000'); } public AnnotationRowProcessor() { super(); } /** * 映射记录为对象 */ public <T> T toBean(ResultSet rs, Class<T> clazz) throws SQLException { T bean = this.newInstance(clazz); Table table = EntityFactory.getTable(clazz); ResultSetMetaData rsmd = rs.getMetaData(); int cols = rsmd.getColumnCount(); for (int col = 1; col <= cols; col++) { String columnName = rsmd.getColumnLabel(col); if (null == columnName || 0 == columnName.length()) { columnName = rsmd.getColumnName(col); } Column column = mapColumnToFiled(table, columnName); if (column == null) { continue; } PropertyDescriptor prop; try { prop = new PropertyDescriptor(column.getJavaName(), clazz); } catch (IntrospectionException e) { e.printStackTrace(); throw new SQLException(e.getMessage()); } Class<?> propType = prop.getPropertyType(); Object value = this.processColumn(rs, col, propType); if (propType != null && value == null && propType.isPrimitive()) { value = primitiveDefaults.get(propType); } this.callSetter(bean, prop, value); } return bean; } /** * 映射记录集为对象列表 */ public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException { List<T> results = new ArrayList<T>(); if (!rs.next()) { return results; } do { results.add(this.toBean(rs, type)); } while (rs.next()); return results; } /** *返过来,根据column求field */ private Column mapColumnToFiled(Table table, String columnName) { Column column = null; for (int i = 0; i < table.getColumnCount(); i++) { column = table.getColumn(i); if (columnName.equalsIgnoreCase(column.getName())) { return column; } } return null; } private void callSetter(Object target, PropertyDescriptor prop, Object value) throws SQLException { Method setter = prop.getWriteMethod(); if (setter == null) { return; } Class<?>[] params = setter.getParameterTypes(); try { // convert types for some popular ones if (value != null) { if (value instanceof java.util.Date) { if (params[0].getName().equals("java.sql.Date")) { value = new java.sql.Date(((java.util.Date) value) .getTime()); } else if (params[0].getName().equals("java.sql.Time")) { value = new java.sql.Time(((java.util.Date) value) .getTime()); } else if (params[0].getName().equals("java.sql.Timestamp")) { value = new java.sql.Timestamp(((java.util.Date) value) .getTime()); } } } // Don't call setter if the value object isn't the right type if (this.isCompatibleType(value, params[0])) { setter.invoke(target, new Object[] { value }); } else { throw new SQLException("Cannot set " + prop.getName() + ": incompatible types."); } } catch (IllegalArgumentException e) { throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage()); } catch (IllegalAccessException e) { throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage()); } catch (InvocationTargetException e) { throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage()); } } private boolean isCompatibleType(Object value, Class<?> type) { // Do object check first, then primitives if (value == null || type.isInstance(value)) { return true; } else if (type.equals(Integer.TYPE) && Integer.class.isInstance(value)) { return true; } else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) { return true; } else if (type.equals(Double.TYPE) && Double.class.isInstance(value)) { return true; } else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) { return true; } else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) { return true; } else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) { return true; } else if (type.equals(Character.TYPE) && Character.class.isInstance(value)) { return true; } else if (type.equals(Boolean.TYPE) && Boolean.class.isInstance(value)) { return true; } else { return false; } } protected <T> T newInstance(Class<T> c) throws SQLException { try { return c.newInstance(); } catch (InstantiationException e) { throw new SQLException("Cannot create " + c.getName() + ": " + e.getMessage()); } catch (IllegalAccessException e) { throw new SQLException("Cannot create " + c.getName() + ": " + e.getMessage()); } } protected Object processColumn(ResultSet rs, int index, Class<?> propType) throws SQLException { if (propType.equals(String.class)) { return rs.getString(index); } else if (propType.equals(Integer.TYPE) || propType.equals(Integer.class)) { return (rs.getInt(index)); } else if (propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) { return (rs.getBoolean(index)); } else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) { return (rs.getLong(index)); } else if (propType.equals(Double.TYPE) || propType.equals(Double.class)) { return (rs.getDouble(index)); } else if (propType.equals(Float.TYPE) || propType.equals(Float.class)) { return (rs.getFloat(index)); } else if (propType.equals(Short.TYPE) || propType.equals(Short.class)) { return (rs.getShort(index)); } else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) { return (rs.getByte(index)); } else if (propType.equals(Timestamp.class)) { return rs.getTimestamp(index); } else if (propType.isAnnotationPresent(javax.persistence.Entity.class) && EntityFactory.getTable(propType) != null) { BeanProxy bean = new BeanProxy(); bean.setKey((java.io.Serializable) rs.getObject(index)); return bean.getBean(propType); } else { return rs.getObject(index); } } public Object[] toArray(ResultSet rs) throws SQLException { ResultSetMetaData meta = rs.getMetaData(); int cols = meta.getColumnCount(); Object[] result = new Object[cols]; for (int i = 0; i < cols; i++) { result[i] = rs.getObject(i + 1); } return result; } public Map<String, Object> toMap(ResultSet rs) throws SQLException { Map<String, Object> result = new HashMap<String, Object>(); ResultSetMetaData rsmd = rs.getMetaData(); int cols = rsmd.getColumnCount(); for (int i = 1; i <= cols; i++) { result.put(rsmd.getColumnName(i), rs.getObject(i)); } return result; } }