com.pugwoo.dbhelper.utils.DOInfoReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nimble-orm Show documentation
Show all versions of nimble-orm Show documentation
nimble-orm an ORM based on Spring jdbcTemplate.
package com.pugwoo.dbhelper.utils;
import com.pugwoo.dbhelper.annotation.*;
import com.pugwoo.dbhelper.cache.ClassInfoCache;
import com.pugwoo.dbhelper.exception.*;
import com.pugwoo.dbhelper.json.NimbleOrmJSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 2015年1月12日 16:42:26 读取DO的注解信息:
* 1. 继承的类的信息读取,父类先读取,请保证@Column注解没有重复的字段。
*/
public class DOInfoReader {
private static final Logger LOGGER = LoggerFactory.getLogger(DOInfoReader.class);
/**
* 获取DO的@Table信息,如果子类没有,会往父类查找
*
* @throws NoTableAnnotationException 当clazz没有@Table注解时抛出NoTableAnnotationException
*/
public static Table getTable(Class> clazz) throws NoTableAnnotationException {
Table table = ClassInfoCache.getTable(clazz);
if (table != null) {
if (table.sameTableNameAs() != void.class) {
if (InnerCommonUtils.isNotBlank(table.value())) {
LOGGER.warn("class:{} @Table annotation value:{} is ignored because @Table.sameTableNameAs is not void.class, it is {}",
clazz, table.value(), table.sameTableNameAs());
}
return getTable(table.sameTableNameAs());
}
return table;
}
throw new NoTableAnnotationException("class: "
+ (clazz == null ? "null" : clazz.getName())
+ " does not have @Table annotation.");
}
/**
* 获得clazz上注解的JoinTable,如果没有则返回null
* @return 如果没有则返回null
*/
public static JoinTable getJoinTable(Class> clazz) {
return getAnnotationClass(clazz, JoinTable.class);
}
/**
* 判断一个Table是否是虚拟表
*/
public static boolean isVirtualTable(Class> clazz) {
JoinTable joinTable = DOInfoReader.getJoinTable(clazz);
if (joinTable != null) {
return false;
}
Table table = DOInfoReader.getTable(clazz);
return InnerCommonUtils.isNotBlank(table.virtualTableSQL())
|| InnerCommonUtils.isNotBlank(table.virtualTablePath());
}
public static class RelatedField {
public Field field;
/**0=普通field; 1=leftJoinTable; 2=rightJoinTable*/
public int fieldType;
/**当fieldType==1或2时,存放表的别名前缀*/
public String fieldPrefix;
public RelatedField(Field field, int fieldType, String fieldPrefix) {
this.field = field;
this.fieldType = fieldType;
this.fieldPrefix = fieldPrefix;
}
}
/**
* 从db字段名拿字段对象。
* 新增支持@JoinTable的支持,可以获得JoinTable类中的对象的Field
* @param clazz DO类
* @param dbFieldName 数据库字段名称,多个用逗号隔开;支持joinTable的字段,必须用别名表示,例如t1.id
* @return 如果不存在返回空数组,返回的Field的顺序和dbFieldName保持一致;只要有一个dbFieldName找不到,则返回空数组
*/
public static List getFieldByDBField(Class> clazz, String dbFieldName, Field relatedColumnField) {
List dbFieldNameList = InnerCommonUtils.split(dbFieldName, ",");
List fields = new ArrayList<>();
JoinTable joinTable = DOInfoReader.getJoinTable(clazz);
Field joinLeftTableFiled;
Field joinRightTableFiled;
String leftTablePrefix = "";
String rightTablePrefix = "";
if (joinTable == null) {
List fs = getColumns(clazz);
for (Field f : fs) {
fields.add(new RelatedField(f, 0, ""));
}
} else {
joinLeftTableFiled = DOInfoReader.getJoinLeftTable(clazz);
joinRightTableFiled = DOInfoReader.getJoinRightTable(clazz);
leftTablePrefix = joinLeftTableFiled.getAnnotation(JoinLeftTable.class).alias() + ".";
rightTablePrefix = joinRightTableFiled.getAnnotation(JoinRightTable.class).alias() + ".";
List leftFs = getColumns(joinLeftTableFiled.getType());
List rightFs = getColumns(joinRightTableFiled.getType());
for (Field f : leftFs) {
fields.add(new RelatedField(f, 1, leftTablePrefix));
}
for (Field f : rightFs) {
fields.add(new RelatedField(f, 2, rightTablePrefix));
}
}
List result = new ArrayList<>();
for (String dbField : dbFieldNameList) {
boolean isFound = false;
for(RelatedField field : fields) {
if (joinTable == null) {
Column column = field.field.getAnnotation(Column.class);
if(column.value().trim().equalsIgnoreCase(dbField)) {
result.add(field);
isFound = true;
break;
}
} else {
if (dbField.startsWith(leftTablePrefix)) {
if (field.fieldType == 1) {
Column column = field.field.getAnnotation(Column.class);
if(column.value().trim().equalsIgnoreCase(dbField.substring(leftTablePrefix.length()))) {
result.add(field);
isFound = true;
break;
}
}
} else if (dbField.startsWith(rightTablePrefix)) {
if (field.fieldType == 2) {
Column column = field.field.getAnnotation(Column.class);
if(column.value().trim().equalsIgnoreCase(dbField.substring(rightTablePrefix.length()))) {
result.add(field);
isFound = true;
break;
}
}
} else {
throw new RelatedColumnFieldNotFoundException(relatedColumnField.getDeclaringClass().getName()
+ " @RelatedColumn field:"
+ relatedColumnField.getName() +
", column: " + dbField + " should start with "
+ leftTablePrefix + " or " + rightTablePrefix);
}
}
}
if (!isFound) {
throw new RelatedColumnFieldNotFoundException(relatedColumnField.getDeclaringClass().getName()
+ " @RelatedColumn field:"
+ relatedColumnField.getName() +
", column: " + dbField + " not found in class " + clazz.getName());
}
}
return result;
}
/**
* 获得泛型的class
*/
public static Class> getGenericFieldType(Field field) {
ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
return (Class>) stringListType.getActualTypeArguments()[0];
}
/**
* 获得所有有@Column注解的列,包括继承的父类中的,顺序父类先
*
* @throws NoColumnAnnotationException 当没有一个@Column注解时抛出
* @return 不会返回null
*/
public static List getColumns(Class> clazz)
throws NoColumnAnnotationException {
if(clazz == null) {
throw new NoColumnAnnotationException("class is null");
}
List result = ClassInfoCache.getColumnFields(clazz);
if (InnerCommonUtils.isEmpty(result)) {
throw new NoColumnAnnotationException("class " + clazz.getName()
+ " does not have any @Column fields");
}
return result;
}
/**
* 获得所有有@Column注解的列,包括继承的父类中的,顺序父类先。
* 该方法只用于select读操作。
* @param selectOnlyKey 是否只select主键
* @throws NoColumnAnnotationException 当没有一个@Column注解时抛出
* @return 不会返回null
*/
public static List getColumnsForSelect(Class> clazz, boolean selectOnlyKey) {
List result = getColumns(clazz);
if(selectOnlyKey) {
result = InnerCommonUtils.filter(result, o -> o.getAnnotation(Column.class).isKey());
}
if (result.isEmpty()) {
throw new NoColumnAnnotationException("class " + clazz.getName() + " does not have any @Column fields");
}
return result;
}
/**
* 获得注解了@JoinLeftTable的字段,如果没有注解,抛出NoJoinTableMemberException
*/
public static Field getJoinLeftTable(Class> clazz) {
return getJoinTableField(clazz, JoinLeftTable.class);
}
/**
* 获得注解了@JoinRightTable的字段,如果没有注解,抛出NoJoinTableMemberException
*/
public static Field getJoinRightTable(Class> clazz) {
return getJoinTableField(clazz, JoinRightTable.class);
}
/**
* 用于获取@JoinLeftTable和@JoinRightTable注解的属性Field
*/
private static Field getJoinTableField(Class> clazz,
Class extends Annotation> annotationClass) {
if (clazz == null) {
throw new NoJoinTableMemberException("clazz is null");
}
List result = _getAnnotationColumns(clazz, annotationClass);
if (result.isEmpty()) {
throw new NoJoinTableMemberException("class " + clazz.getName()
+ " does not have @" + annotationClass.getSimpleName() + " field");
}
if (result.size() > 1) {
LOGGER.error("class {} has more than one @{} fields, use first one",
clazz.getName(), annotationClass.getSimpleName());
}
return result.get(0);
}
/**
* 获得字段里面的key字段
* @throws NoKeyColumnAnnotationException 如果没有key Column,抛出该异常。
*/
public static List getKeyColumns(Class> clazz) throws NoKeyColumnAnnotationException {
List keyFields = getKeyColumnsNoThrowsException(clazz);
if(keyFields.isEmpty()) {
throw new NoKeyColumnAnnotationException();
}
return keyFields;
}
/**
* 获得字段里面的key字段
*/
public static List getKeyColumnsNoThrowsException(Class> clazz) {
List fields = getColumns(clazz);
List keyFields = new ArrayList<>();
for(Field field : fields) {
Column column = field.getAnnotation(Column.class);
if(column.isKey()) {
keyFields.add(field);
}
}
return keyFields;
}
/**
* 获得一个DO类注解的casVersion字段
* @return 当没有column字段时返回null
* @throws CasVersionNotMatchException 当有2个及2个以上的casVersion字段时抛出该异常
*/
public static Field getCasVersionColumn(Class> clazz) throws CasVersionNotMatchException {
List fields = getColumns(clazz);
Field casVersionField = null;
for(Field field : fields) {
Column column = field.getAnnotation(Column.class);
if(column.casVersion()) {
if(casVersionField != null) {
throw new CasVersionNotMatchException("there are more than one casVersion column in a DO class");
}
casVersionField = field;
}
}
return casVersionField;
}
public static Field getAutoIncrementField(Class> clazz) {
List fields = getColumns(clazz);
for(Field field : fields) {
Column column = field.getAnnotation(Column.class);
if(column.isAutoIncrement()) {
return field;
}
}
return null;
}
/**
* 获得软删除标记字段,最多只能返回1个。
* @return 如果没有则返回null
*/
public static Field getSoftDeleteColumn(Class> clazz) {
List fields = getColumns(clazz);
for(Field field : fields) {
Column column = field.getAnnotation(Column.class);
if(column.softDelete().length == 2
&& InnerCommonUtils.isNotBlank(column.softDelete()[0])
&& InnerCommonUtils.isNotBlank(column.softDelete()[1])) {
return field;
}
}
return null;
}
/**
* 获得字段里面的非key字段
*/
public static List getNotKeyColumns(Class> clazz) {
List fields = getColumns(clazz);
List keyFields = new ArrayList<>();
for(Field field : fields) {
Column column = field.getAnnotation(Column.class);
if(!column.isKey()) {
keyFields.add(field);
}
}
return keyFields;
}
/**
* 获得所有有@RelatedColumn注解的列,包括继承的父类中的,顺序父类先
*
* @return 不会返回null
*/
public static List getRelatedColumns(Class> clazz) {
return ClassInfoCache.getRelatedColumns(clazz);
}
/**
* 优先通过getter获得值,如果没有getter,则直接获取
*/
public static Object getValue(Field field, Object object) {
Method method = ClassInfoCache.getFieldGetMethod(field);
if(method != null) {
try {
method.setAccessible(true);
return method.invoke(object);
} catch (Exception e) {
LOGGER.error("get method:{} invoke fail", method, e);
}
}
field.setAccessible(true);
try {
return field.get(object);
} catch (Exception e) {
LOGGER.error("field:{} get fail", field, e);
return null;
}
}
/**
* 为relatedColumn获得字段的值。这里有特别的逻辑。
* 当fields只有一个时,返回的是对象本身;否则是一个List,里面是按顺序的fields的多个值
* @return 当fields为空,返回null
*/
public static Object getValueForRelatedColumn(List fields, Object object) {
if (fields == null || fields.isEmpty()) {
return null;
}
List