package com.github.walker.easydb.dao; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; import com.github.walker.easydb.assistant.LogFactory; import com.github.walker.easydb.exception.BaseException; import com.github.walker.easydb.exception.IllegalEntityException; /** * 抽象实体类, 所有实体类的基类, 其子类与数据库的元数据形成映射。 <br> * <p/> * This class reflects the meta data in database. The definition of its subclass * must observe following items. <br> * <br> * <br> * <p/> * 1. 类名与表名(或视图名)必须有明确的对应关系;除表名中的第一个字母、以及紧跟在下化线"_"后的字母在类名中必须大写外, * 其它字母在类名中必须小写;且表名中各字母前的下化线"_"在类名中要被删除。举例如下: <br> * 表名为 "COMPANY", 则对应的类名只能为"Company"; 表名为 "COMPANY_INFO", * 则对应的类名只能为"CompanyInfo"; 表名为 "NET_INFO3", 则对应的类名只能为"NetInfo3"; 表名为 * "NET_INFO_3", 则对应的类名只能为"NetInfo_3"。 <br> * <br> * <p/> * The relation of Class name and table name is one to one, except for the first * character and the character behind the underline('_') must be uppercase, all * other character must be lowercase in class name. <br> * <br> * <br> * <p/> * <p/> * 2. 在某实体类中,属性名与列名(或列的别名)也必须有明确的对应关系;除紧跟在下化线”_”后的字母在列名中必须大写外, * 其它字母在列名中必须小写;且列名中各字母前的下化线"_"在属性名中要被删除。举例如下: <br> * 列名为 “NAME”, 则对应的类名只能为“name”; 列名为 “COMPANY_NAME”, 则对应的类名只能为“companyName”; 列名为 * “NET_TYPE2”, 则对应的类名只能为“NetType2”; 列名为 “NET_TYPE_2”, 则对应的类名只能为“NetType_2”。 * <br> * <br> * <p/> * In one Entity Class, The relation of field name and column name is one to * one, except for the character behind the underline('_') must be uppercase, * all other character must be lowercase in class name. <br> * <br> * <br> * <p/> * <p/> * 3. 属性类型必须与下表中的对应关系一致。 如:<br> * 对于Oracle数据库, 如果某列被定义为 CHAR, 则其在对应实体类中必须被声明为 walker.easydb.datatype.EString; * 如果某列被定义为BLOB,则其在对应实体类中必须被声明为walker.easydb.datatype.EBinFile类型。 如下表所示: <br> * <br> * <p/> * The field types of entity class cann't be primitive, and must correspond with * the column data type, as follows: <br> * <br> * <p/> * <p/> * <table width=90% border=1 cellspacing=0 cellpadding=0> * <p/> * <tr> * <td align=center height=20>数据库类型</td> * <td align=center>数据库中列的数据类型</td> * <td align=center>实体类中属性的数据类型</td> * </tr> * <tr> * <td align=center rowspan=5 valign="middle">Oracle</td> * <td align=left > CHAR <br> *  VARCHAR <br> *  VARCHAR2</td> * <td align=left valign=middle> walker.easydb.datatype.EString</td> * </tr> * <tr> * <td align=left valign=middle> NUMBER</td> * <td align=left valign=middle> walker.easydb.datatype.EInteger <br> *  walker.easydb.datatype.ELong <br> *  walker.easydb.datatype.EFloat <br> *  walker.easydb.datatype.EDouble <br> * </td> * </tr> * <tr> * <td align=left valign=middle> DATE</td> * <td align=left valign=middle> walker.easydb.datatype.Timestamp</td> * </tr> * <tr> * <td align=left valign=middle> CLOB</td> * <td align=left valign=middle> walker.easydb.datatype.ETxtFile</td> * </tr> * <tr> * <td align=left valign=middle> BLOB</td> * <td align=left valign=middle> walker.easydb.datatype.EBinFile</td> * </tr> * <p/> * <tr> * <td align=center rowspan=10 valign="middle">mysql</td> * <td align=left > CHAR <br> *  VARCHAR <br> *  SET</td> * <td align=left valign=middle> walker.easydb.datatype.EString</td> * </tr> * <tr> * <td align=left valign=middle> SMALLINT</td> * <td align=left valign=middle> walker.easydb.datatype.EInteger <br> *  walker.easydb.datatype.ELong</td> * </tr> * <tr> * <td align=left valign=middle> INT</td> * <td align=left valign=middle> walker.easydb.datatype.EInteger <br> *  walker.easydb.datatype.ELong</td> * </tr> * <tr> * <td align=left valign=middle> BIGINT</td> * <td align=left valign=middle> walker.easydb.datatype.ELong</td> * </tr> * <tr> * <td align=left valign=middle> FLOAT</td> * <td align=left valign=middle> walker.easydb.datatype.EFloat <br> *  walker.easydb.datatype.EDouble</td> * </tr> * <tr> * <td align=left valign=middle> DOUBLE</td> * <td align=left valign=middle> walker.easydb.datatype.EDouble</td> * </tr> * <tr> * <td align=left valign=middle> DATE <br> *  DATETIME</td> * <td align=left valign=middle> walker.easydb.datatype.Timestamp</td> * </tr> * <tr> * <td align=left > TINYTEXT <br> * <td align=left valign=middle> walker.easydb.datatype.EString <br> *  walker.easydb.datatype.ETxtFile</td> * </tr> * <tr> * <td align=left > TEXT <br> *  MEDIUMTEXT <br> *  LONGTEXT <br> * <td align=left valign=middle> walker.easydb.datatype.ETxtFile</td> * </tr> * <tr> * <td align=left valign=middle> TINYBLOB <br> *  BLOB <br> *  MEDIUMBLOB <br> *  LONGBLOB</td> * <td align=left valign=middle> walker.easydb.datatype.EBinFile</td> * </tr> * </table> * <br> * <p/> * <p/> * 4. 子类必须实现方法: public abstract String[] pk(), 该方法用来指定主键属性. * <br> * <br> * * @author HuQingmiao */ //* =====================================================================<br> //* | 数据库类型 | 数据库中列的数据类型 | 实体类中属性的数据类型 |<br> //* |-------------------------------------------------------------------|<br> //* | | CHAR | |<br> //* | | VARCHAR |walker.easydb.datatype.EString |<br> //* | | VARCHAR2 | |<br> //* | |------------------------------------------------------|<br> //* | | | walker.easydb.datatype.EInteger |<br> //* | | NUMBER | walker.easydb.datatype.ELong |<br> //* | Oracle | | walker.easydb.datatype.EFloat |<br> //* | | | walker.easydb.datatype.EDouble |<br> //* | |------------------------------------------------------|<br> //* | | DATE |walker.easydb.datatype.ETimestamp|<br> //* | |------------------------------------------------------|<br> //* | | CLOB |walker.easydb.datatype.ETxtFile |<br> //* | |------------------------------------------------------|<br> //* | | BLOB |walker.easydb.datatype.EBinFile |<br> //* |-------------------------------------------------------------------|<br> //* | | CHAR | |<br> //* | | VARCHAR |walker.easydb.datatype.EString |<br> //* | | SET | |<br> //* | |------------------------------------------------------|<br> //* | | SMALLINT |walker.easydb.datatype.EInteger |<br> //* | |------------------------------------------------------|<br> //* | | INT |walker.easydb.datatype.EInteger |<br> //* | | |walker.easydb.datatype.ELong |<br> //* | |------------------------------------------------------|<br> //* | | BIGINT |walker.easydb.datatype.ELong |<br> //* | |------------------------------------------------------|<br> //* | mysql | FLOAT |walker.easydb.datatype.EFloat |<br> //* | | |walker.easydb.datatype.EDouble |<br> //* | |------------------------------------------------------|<br> //* | | DOUBLE |walker.easydb.datatype.EDouble |<br> //* | |------------------------------------------------------|<br> //* | | DATE | |<br> //* | | DATETIME |walker.easydb.datatype.ETimestamp|<br> //* | |------------------------------------------------------|<br> //* | | |walker.easydb.datatype.EString |<br> //* | | TINYTEXT |walker.easydb.datatype.ETxtFile |<br> //* | |------------------------------------------------------|<br> //* | | TEXT | |<br> //* | | MEDIUMTEXT | |<br> //* | | LONGTEXT |walker.easydb.datatype.ETxtFile |<br> //* | |------------------------------------------------------|<br> //* | | TINYBLOB | |<br> //* | | BLOB | |<br> //* | | MEDIUMBLOB | |<br> //* | | LONGBLOB |walker.easydb.datatype.EBinFile |<br> //* |-------------------------------------------------------------------|<br> @SuppressWarnings("serial") public abstract class BaseEntity implements Serializable { private static Logger log = LogFactory.getLogger(BaseEntity.class); //存放当前实体类的属性及类型 private HashMap<String, Class<?>> fieldNameTypeMap = new HashMap<String, Class<?>>(10); // public EString rowid;//行版本号. 必须为public,否则反射不可见. public BaseEntity() { //将属性及其类型存入map(fieldName,fieldType) Field[] fields = this.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fieldNameTypeMap.put(fields[i].getName(), fields[i].getType()); } } /** * 取得代表主键的属性组 * * @return 代表主键的属性组 */ public abstract String[] pk(); /** * 根据属性名取值 * * @param propertyName 属性名 * @return 属性值 * @throws BaseException */ public Object get(String propertyName) throws BaseException { String firstChar = propertyName.substring(0, 1).toUpperCase(); if (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) { firstChar = firstChar.toLowerCase(); } String methodName = "get" + firstChar + propertyName.substring(1); try { //builds the method name, such as: "getXX" Method method = this.getClass().getMethod(methodName, new Class[]{}); //Getting value of the field by the method. Object fieldValue = method.invoke(this, new Object[]{}); return fieldValue; } catch (NoSuchMethodException e) { log.error("", e); throw new IllegalEntityException( IllegalEntityException.PROPERTY_NOTEXIST_OR_GET, propertyName); } catch (IllegalArgumentException e) { log.error("", e); throw new IllegalEntityException(e.getMessage()); } catch (IllegalAccessException e) { log.error("", e); throw new IllegalEntityException(e.getMessage()); } catch (InvocationTargetException e) { log.error("", e); throw new IllegalEntityException(e.getMessage()); } } /** * 对指定属性设置值 * * @param propertyName * @param value * @throws BaseException */ public void set(String propertyName, Object value) throws BaseException { String firstChar = propertyName.substring(0, 1).toUpperCase(); if (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) { firstChar = firstChar.toLowerCase(); } String methodName = "set" + firstChar + propertyName.substring(1); try { Method method = this.getClass().getMethod(methodName, new Class[]{(Class<?>) fieldNameTypeMap.get(propertyName)}); //Setting value of the field by the method. method.invoke(this, new Object[]{value}); } catch (NoSuchMethodException e) { log.error("", e); throw new IllegalEntityException( IllegalEntityException.PROPERTY_NOTEXIST_OR_SET, propertyName); } catch (IllegalArgumentException e) { log.error("", e); throw new IllegalEntityException(e.getMessage()); } catch (IllegalAccessException e) { log.error("", e); throw new IllegalEntityException(e.getMessage()); } catch (InvocationTargetException e) { log.error("", e); throw new IllegalEntityException(e.getMessage()); } } public HashMap<String, Class<?>> fieldNameTypeMap() { return this.fieldNameTypeMap; } @Override public int hashCode() { int hashCode = 1; Map<String, Object> keyObjectMap = new HashMap<String, Object>(); try { for (Iterator<String> it = fieldNameTypeMap.keySet().iterator(); it.hasNext(); ) { String filedName = it.next(); Object obj = this.get(filedName); hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); } } catch (Exception e) { e.printStackTrace(); } keyObjectMap.clear(); return hashCode; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof BaseEntity)) { return false; } BaseEntity vo2 = ((BaseEntity) o); HashMap<String, Class<?>> ftMap2 = vo2.fieldNameTypeMap(); if (fieldNameTypeMap.size() != ftMap2.size()) { return false; } try { for (Iterator<String> it = fieldNameTypeMap.keySet().iterator(); it.hasNext(); ) { String filedName = it.next(); Object obj1 = this.get(filedName); Object obj2 = vo2.get(filedName); if (!(obj1 == null ? obj2 == null : obj1.equals(obj2))) { return false; } } } catch (Exception e) { e.printStackTrace(); } return true; } }