/** * 解析符合fastDB的 Annotation 注解对象 注:该方法是升级版,支持继承注解属性获取;采用的是 getMethods 获取继承的所有公共方法,然后解析 getter * 方法获得字段属性(这就要求getter方法和字段属性必须是严格的生成关系)。 * * @param obj 注解对象 * @param isPersistenced 对象是否已经被持久化了, false -- 用在 insert 时; true -- 用在 update 时 * @return Persistence对象 */ public static Persistence parsePersistence(Object obj, boolean isPersistenced) { Class<?> clz = obj.getClass(); // 只有通过 getMethods 方法才能获取到继承自父类的私有字段属性 Method[] methods = clz.getMethods(); // 字段是否存在,用来递归解析注解字段 boolean isFieldExist = true; // 用于内部强制异常时,中断catch;此处用在下面的 sequence 判断 boolean isBreak = false; // 主键字段 // PrimaryField p_field = null; // 普通字段 ColumnField n_field = null; String col_name = null; Object col_val = null; Persistence persistence = new Persistence(); persistence.setTableName(getTableName(clz)); for (Method m : methods) { /* 每次字段查找都要从当前类开始,然后再递归父类。 因为 getMethods()返回的数组中的元素没有排序,也没有任何特定的顺序,有可能当前类的某(些)字段被放置到了父类属性的后面, 而后面的递归父类操作改变了 clz 的对象,这样一来会造成这些字段被丢弃; 所以每次查找开始都要将 clz 对象重置为当前对象。 */ clz = obj.getClass(); String m_name = m.getName(); // 只解析getter方法,对于Boolean类型,其getter方法可能是 isAbc if (!m_name.startsWith("get") && !m_name.startsWith("is")) { continue; } // getter 方法无参数 if (m.getParameterTypes().length > 0) { continue; } // Java注解只支持基本数据类型 if (!ColumnType.isPrimitiveClass(m.getReturnType())) { continue; } m_name = lowerFirst(m_name.startsWith("get") ? m_name.substring(3) : m_name.substring(2)); // 如果当前类找不到Field定义,则递归到其父类中寻找,以此进行下去 Field f; Column col; do { try { // 这里会产生后面的异常:如果字段是父类中继承过来的,则在当前类getDeclaredField会产生异常 f = clz.getDeclaredField(m_name); col = f.getAnnotation(Column.class); // 如果该字段定义了注解,则解析;如果没有定义注解,则也不会到父类中查找 if (null != col) { col_name = col.name(); col_val = m.invoke(obj, new Object[] {}); // 列名 @Column(name='') 为空,则使用属性名替代 if (null == col_name || col_name.trim().length() == 0) { col_name = f.getName(); } // 如果是主键 if (col.primaryKey()) { // 如果对象未被持久化 并且是 SEQUENCE 生成方式 if (!isPersistenced && col.generatorType() == GeneratorType.SEQUENCE) { // 对于SEQUENCE 生成方式的主键,必须指定 SEQUENCE 名称 if (null == col.sequence() || col.sequence().trim().length() == 0) { isBreak = true; throw new IllegalArgumentException( "The " + clz.getName() + "[" + f.getName() + "] Annotation @Column(isPrimaryKey=true, generatorType=GeneratorType.SEQUENCE, sequence='...'), but the sequence name is empty!"); } // sequence 方式主键的值是 seqname.NEXTVAL col_val = col.sequence() + ".NEXTVAL"; } // 创建主键字段 // 扩充了ColumnField,使用 ColumnField替代 /*p_field = new PrimaryField(); p_field.setName( col_name ); p_field.setValue( col_val ); p_field.setGeneratorType( col.generatorType() ); p_field.setType(f.getType()); persistence.addPrimaryField( p_field );*/ } // 创建字段 n_field = new ColumnField(); n_field.setName(col_name); n_field.setValue(col_val); n_field.setType(f.getType()); n_field.setPrimaryKey(col.primaryKey()); n_field.setGeneratorType(col.generatorType()); persistence.addColumnField(n_field); } isFieldExist = true; } catch (Exception e) { // 内部强制抛出异常 if (isBreak) { e.printStackTrace(); return null; } isFieldExist = false; // 如果当前类没有找到,则到其父类中查找 clz = clz.getSuperclass(); // 父类不存在或是Object基类,则结束下次递归操作 if (null == clz || "java.lang.Object".equals(clz.getName())) { isFieldExist = true; } } } while (!isFieldExist); n_field = null; } return persistence; }
/** * 解析一个使用了fastDB Annotation的类的注解属性映射关系 * * @param clazz 使用了fastDB Annotation的类 * @return Map: key -- 表示数据库表字段;value -- 表示JavaBean对应的注解属性名称 */ public static Map<String, String> getFieldAnnotationMapping(Class<?> clazz) { // 只有通过 getMethods 方法才能获取到继承自父类的私有字段属性 Method[] methods = clazz.getMethods(); // 存放注解映射关系信息 // 使用大小写不区分HashMap存放,因为oracle数据库默认返回的列名都是大写的 Map<String, String> field_mapping = new CaseInsensitiveHashMap<String>(); // 字段是否存在,用来递归解析注解字段 boolean isFieldExist = true; Class<?> clz = clazz; String col_name = null; for (Method m : methods) { /* 每次字段查找都要从当前类开始,然后再递归父类。 因为 getMethods()返回的数组中的元素没有排序,也没有任何特定的顺序,有可能当前类的某(些)字段被放置到了父类属性的后面, 而后面的递归父类操作改变了 clz 的对象,这样一来会造成这些字段被丢弃; 所以每次查找开始都要将 clz 对象重置为当前对象。 */ clz = clazz; String m_name = m.getName(); if (!m_name.startsWith("get") && !m_name.startsWith("is")) { continue; } // getter 方法无参数 if (m.getParameterTypes().length > 0) { continue; } // Java注解只支持基本数据类型 if (!ColumnType.isPrimitiveClass(m.getReturnType())) { continue; } m_name = lowerFirst(m_name.startsWith("get") ? m_name.substring(3) : m_name.substring(2)); // 如果当前类找不到Field定义,则递归到其父类中寻找,以此进行下去 Field f; Column col; do { try { // 这里会产生后面的异常:如果字段是父类中继承过来的,则在当前类getDeclaredField会产生异常 f = clz.getDeclaredField(m_name); col = f.getAnnotation(Column.class); // 如果该字段定义了注解,则解析;如果没有定义注解,则也不会到父类中查找 if (null != col) { col_name = col.name(); // 列名 @Column(name='') 为空,则使用属性名替代 if (null == col_name || col_name.trim().length() == 0) { col_name = f.getName(); } // key:数据库对应的列名, value:JavaBean被注解的属性名称 field_mapping.put(col_name, f.getName()); } isFieldExist = true; } catch (Exception e) { isFieldExist = false; // 如果当前类没有找到,则到其父类中查找 clz = clz.getSuperclass(); // 父类不存在 或是 Object,则结束下次递归操作 if (null == clz || "java.lang.Object".equals(clz.getName())) { isFieldExist = true; } } } while (!isFieldExist); } return field_mapping; }