package com.lizard.fastdb.persistence;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.lizard.fastdb.annotation.Column;
import com.lizard.fastdb.annotation.ColumnType;
import com.lizard.fastdb.annotation.GeneratorType;
import com.lizard.fastdb.annotation.Table;
/**
* 数据库对象注解持久化处理类
*
* @author SHEN.GANG
*/
public final class PersistenceUtil
{
/**
* 获取注解对象的数据库表名
*
* @param obj 注解对象
* @return
*/
public static String getTableName( Class<?> clazz )
{
String table_name = null;
boolean isTableExist = true;
// 解析Table注解
Table _table = null;
do
{
_table = clazz.getAnnotation( Table.class );
if( null != _table )
{
table_name = _table.name();
isTableExist = true;
}
else
{
isTableExist = false;
clazz = clazz.getSuperclass();
// 父类不存在,则结束下次递归操作
if( null == clazz || "java.lang.Object".equals(clazz.getName()) )
{
isTableExist = true;
}
}
} while( !isTableExist );
// 获取注解中定义的表名,表名不允许为空
if( null == table_name )
{
throw new IllegalArgumentException("Error: The fastDB Annotation[@Table(name='...')] can not find in your JavaBean!");
}
_table = null;
return table_name;
}
/**
* 将首字母变成小写
*
* @param name
* @return 首字母变成小写后的字符串
*/
public static String lowerFirst(String name)
{
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
/**
* 解析符合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;
}
/**
* 分析注解对象
*
* @param obj 注解对象
* @return Persistence对象
*/
/*@Deprecated
public static Persistence parsePersistence( Object obj, boolean isPersistenced )
{
Class<?> cls = obj.getClass();
// 获取声明的属性
//Field[] fields = cls.getDeclaredFields();
Field[] fields = cls.getFields();
if( fields == null || fields.length <= 0 )
{
return null;
}
Field f = null;
Column col = null;
// 主键字段
PrimaryField p_field = null;
// 普通字段
ColumnField n_field = null;
String col_name = null;
Object col_val = null;
Persistence persistence = new Persistence();
persistence.setTableName( getTableName( cls ) );
// 遍历对象字段
for( int i = 0; i < fields.length; i++ )
{
f = fields[i];
// 判断属性是否是基本数据类型,对于非基本数据类型直接跳过,因为 jdk annotation 只支持基本数据类型
if( !ColumnType.isPrimitiveClass( f.getType() ) )
{
continue;
}
// 获取列注解名称
col = f.getAnnotation( Column.class );
// 只获取含有注解的属性
if( col != null )
{
// 列名
col_name = col.name();
// 列名 @Column(name='') 为空,则使用属性名替代
if( col_name == null || "".equals(col_name.trim()) )
{
col_name = f.getName();
}
// 如果是主键
if( col.isPrimaryKey() )
{
// 获取主键值
col_val = ReflectUtils.getProperty( obj, f.getName() );
// 如果对象未被持久化 并且是 SEQUENCE 生成方式
if( !isPersistenced && col.generatorType() == GeneratorType.SEQUENCE )
{
// 对于SEQUENCE 生成方式的主键,必须指定 SEQUENCE 名称
if( col.sequence() == null || "".equals(col.sequence().trim()) )
{
throw new IllegalArgumentException("The "+cls.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";
}
// 创建主键字段
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 );
}
// 普通属性
else
{
// 列值
col_val = ReflectUtils.getProperty( obj, f.getName() );
// 创建普通字段
n_field = new ColumnField();
n_field.setName( col_name );
n_field.setValue( col_val );
n_field.setType( f.getType() );
persistence.addColumnField( n_field );
}
col_name = null;
col_val = null;
p_field = null;
n_field = null;
col = null;
f = 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;
}
/**
* 根据未持久化的注解对象创建 Insert SQL 语句
*
* @param bean 注解对象
*
* @return object[0] -- 带占位符 ? 的 Insert SQL; <br/>
* object[1] -- 占位符对应的参数值
*/
public static Object[] createInsertSQL( Object bean )
{
if( bean == null )
{
return null;
}
// 采用新的解析方式,用于支持注解继承
Persistence p = parsePersistence( bean, false );
if( null == p || null == p.getTableName() )
{
return null;
}
Object[] oo = new Object[2];
StringBuilder sql_buf_1 = new StringBuilder();
StringBuilder sql_buf_2 = new StringBuilder();
sql_buf_1.append( "INSERT INTO ");
sql_buf_1.append( p.getTableName());
sql_buf_1.append( "(");
sql_buf_2.append( " VALUES(" );
List<Object> valList = new LinkedList<Object>();
List<ColumnField> col_fields = p.getColumnFields();
// 主键列
for( ColumnField pf : col_fields )
{
if( !pf.isPrimaryKey() )
{
continue;
}
if( pf.getGeneratorType() == GeneratorType.SEQUENCE )
{
sql_buf_1.append(pf.getName());
sql_buf_1.append(", ");
sql_buf_2.append(pf.getValue());
sql_buf_2.append(", ");
}
else if( pf.getGeneratorType() == GeneratorType.ASSIGN )
{
sql_buf_1.append(pf.getName());
sql_buf_1.append(", ");
sql_buf_2.append( "?, " );
valList.add( pf.getValue() );
}
}
// 普通列
for( ColumnField cf : col_fields )
{
if( cf.isPrimaryKey() )
{
continue;
}
sql_buf_1.append(cf.getName());
sql_buf_1.append(", ");
sql_buf_2.append( "?, " );
valList.add( cf.getValue() );
}
String sql1 = sql_buf_1.toString();
String sql2 = sql_buf_2.toString();
if( sql1.lastIndexOf(",") != -1 )
{
sql1 = sql1.substring(0, sql1.lastIndexOf(",")) +")";
}
if( sql2.lastIndexOf(",") != -1 )
{
sql2 = sql2.substring(0, sql2.lastIndexOf(",")) +")";
}
oo[0] = sql1 + sql2;
oo[1] = valList.toArray();
sql_buf_1 = null;
sql_buf_2 = null;
valList.clear();
valList = null;
p.clear();
p = null;
return oo;
}
/**
* 根据已经持久化的注解对象创建 Update SQL 语句
*
* @param bean 已经持久化的注解对象
* @param updateFields 给定待更新的字段集合,如果为null,则更新全部
*
* @return object[0] -- 带占位符 ? 的Update SQL;<br/>
* object[1] -- 占位符对应的参数值
*/
public static Object[] createUpdateSQL( Object bean, String[] updateFields )
{
if( null == bean )
{
return null;
}
// 采用新的解析方式,用于支持注解继承
Persistence p = parsePersistence( bean, true );
Map<String, String> mapping = getFieldAnnotationMapping(bean.getClass());
if( null == p || null == p.getTableName() )
{
return null;
}
Object[] oo = new Object[2];
StringBuilder sql_buf_1 = new StringBuilder();
StringBuilder sql_buf_2 = new StringBuilder();
sql_buf_1.append( "UPDATE ");
sql_buf_1.append(p.getTableName());
sql_buf_1.append(" SET ");
sql_buf_2.append( " WHERE " );
List<Object> valList = new LinkedList<Object>();
List<ColumnField> col_fields = p.getColumnFields();
// 普通列
for( ColumnField cf : col_fields )
{
/*if( cf.isPrimaryKey() )
{
continue;
}*/
// 判断Bean的属性,而不是@Column对应的数据表列名
if( withinUpdateFields(mapping.get(cf.getName()), updateFields) )
{
sql_buf_1.append(cf.getName());
sql_buf_1.append(" = ?, ");
valList.add( cf.getValue() );
}
}
// 主键列
for( ColumnField pf : col_fields )
{
if( !pf.isPrimaryKey() )
{
continue;
}
sql_buf_2.append(pf.getName());
sql_buf_2.append(" = ? AND ");
valList.add( pf.getValue() );
}
String sql1 = sql_buf_1.toString();
String sql2 = sql_buf_2.toString();
if( sql1.lastIndexOf(",") != -1 )
{
sql1 = sql1.substring(0, sql1.lastIndexOf(","));
}
if( sql2.lastIndexOf("AND") != -1 )
{
sql2 = sql2.substring(0, sql2.lastIndexOf("AND"));
}
oo[0] = sql1 + sql2;
oo[1] = valList.toArray();
sql_buf_1 = null;
sql_buf_2 = null;
valList.clear();
valList = null;
p.clear();
p = null;
return oo;
}
/**
* 根据已经持久化的注解对象创建 Update SQL 语句
*
* @param bean 已经持久化的注解对象
*
* @return object[0] -- 带占位符 ? 的Update SQL;<br/>
* object[1] -- 占位符对应的参数值
*/
public static Object[] createUpdateSQL( Object bean )
{
return createUpdateSQL(bean, null);
}
/**
* 判断一个字段名称是否在一个给定的待更新字段集合中
*
* @param fname 待判断的字段名称
* @param updateFields 给定的待更新字段集合
* @return
*/
private static boolean withinUpdateFields( String fname, String[] updateFields )
{
if(null == updateFields || updateFields.length == 0)
{
return true;
}
for( String f : updateFields )
{
if( fname.equalsIgnoreCase(f) )
{
return true;
}
}
return false;
}
}