Files
redkale/src/main/java/org/redkale/source/EntityBuilder.java
2023-07-25 20:00:25 +08:00

398 lines
15 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*
*/
package org.redkale.source;
import java.io.Serializable;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.redkale.annotation.Nullable;
import org.redkale.convert.ConvertDisabled;
import org.redkale.persistence.*;
import org.redkale.source.EntityInfo.DataResultSetRow;
import org.redkale.util.*;
/**
* 可以是实体类也可以是查询结果的JavaBean类
*
* @author zhangjx
* @since 2.8.0
*/
public class EntityBuilder<T> {
private static final ConcurrentHashMap<Class, EntityBuilder> cacheMap = new ConcurrentHashMap<>();
//Entity构建器
private final Creator<T> creator;
//Entity构建器参数
@Nullable
private final String[] constructorParameters;
//key类字段名 value数据库字段名
//只有field.name 与 Column.name不同才存放在aliasmap里.
@Nullable
private final Map<String, String> aliasmap;
//Entity构建器参数Attribute 数组个数与constructorParameters相同
@Nullable
private final Attribute<T, Serializable>[] constructorAttributes;
//Entity构建器参数Attribute
@Nullable
private final Attribute<T, Serializable>[] unconstructorAttributes;
//key类字段名
private final Map<String, Attribute<T, Serializable>> attributeMap;
//key数据库字段名
private final Map<String, Attribute<T, Serializable>> sqlAttrMap;
//数据库中所有字段, 顺序必须与querySqlColumns、querySqlColumnSequence一致
private final Attribute<T, Serializable>[] attributes;
EntityBuilder(Creator<T> creator,
Map<String, String> aliasmap, String[] constructorParameters,
Attribute<T, Serializable>[] constructorAttributes,
Attribute<T, Serializable>[] unconstructorAttributes,
Map<String, Attribute<T, Serializable>> attributeMap,
Attribute<T, Serializable>[] queryAttributes) {
this.creator = creator;
this.aliasmap = aliasmap;
this.constructorParameters = constructorParameters;
this.constructorAttributes = constructorAttributes;
this.unconstructorAttributes = unconstructorAttributes;
this.attributeMap = attributeMap;
this.attributes = queryAttributes;
this.sqlAttrMap = new HashMap<>();
attributeMap.forEach((k, v) -> sqlAttrMap.put(getSQLColumn(null, k), v));
}
public static <T> EntityBuilder<T> load(Class<T> type) {
return cacheMap.computeIfAbsent(type, t -> create(t));
}
private static <T> EntityBuilder<T> create(Class<T> type) {
Creator<T> creator = Creator.create(type);
String[] constructorParameters = null;
try {
Method cm = creator.getClass().getMethod("create", Object[].class);
RedkaleClassLoader.putReflectionPublicMethods(creator.getClass().getName());
RedkaleClassLoader.putReflectionMethod(creator.getClass().getName(), cm);
org.redkale.annotation.ConstructorParameters cp = cm.getAnnotation(org.redkale.annotation.ConstructorParameters.class);
if (cp != null && cp.value().length > 0) {
constructorParameters = cp.value();
} else {
org.redkale.util.ConstructorParameters cp2 = cm.getAnnotation(org.redkale.util.ConstructorParameters.class);
if (cp2 != null && cp2.value().length > 0) {
constructorParameters = cp2.value();
}
}
} catch (Exception e) {
throw new SourceException(type + " cannot find ConstructorParameters Creator");
}
Class cltmp = type;
Map<String, String> aliasmap = null;
Set<String> fields = new HashSet<>();
List<Attribute<T, Serializable>> queryAttrs = new ArrayList<>();
HashMap<String, Attribute<T, Serializable>> attributeMap = new HashMap<>();
do {
RedkaleClassLoader.putReflectionDeclaredFields(cltmp.getName());
for (Field field : cltmp.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
if (Modifier.isFinal(field.getModifiers())) {
continue;
}
if (field.getAnnotation(Transient.class) != null) {
continue;
}
if (field.getAnnotation(javax.persistence.Transient.class) != null) {
continue;
}
if (fields.contains(field.getName())) {
continue;
}
final String fieldName = field.getName();
final Column col = field.getAnnotation(Column.class);
final String sqlField = col == null || col.name().isEmpty() ? fieldName : col.name();
if (!fieldName.equals(sqlField)) {
if (aliasmap == null) {
aliasmap = new HashMap<>();
}
aliasmap.put(fieldName, sqlField);
}
Attribute attr;
try {
attr = Attribute.create(type, cltmp, field);
} catch (RuntimeException e) {
continue;
}
RedkaleClassLoader.putReflectionField(cltmp.getName(), field);
queryAttrs.add(attr);
fields.add(fieldName);
attributeMap.put(fieldName, attr);
}
} while ((cltmp = cltmp.getSuperclass()) != Object.class);
Attribute<T, Serializable>[] constructorAttributes;
Attribute<T, Serializable>[] unconstructorAttributes;
if (constructorParameters == null) {
constructorAttributes = null;
unconstructorAttributes = null;
} else {
constructorAttributes = new Attribute[constructorParameters.length];
List<Attribute<T, Serializable>> unconstructorAttrs = new ArrayList<>();
List<String> newquerycols1 = new ArrayList<>();
List<String> newquerycols2 = new ArrayList<>();
for (Attribute<T, Serializable> attr : new ArrayList<>(queryAttrs)) {
int pos = -1;
for (int i = 0; i < constructorParameters.length; i++) {
if (attr.field().equals(constructorParameters[i])) {
pos = i;
break;
}
}
if (pos >= 0) {
constructorAttributes[pos] = attr;
} else {
unconstructorAttrs.add(attr);
}
}
unconstructorAttributes = unconstructorAttrs.toArray(new Attribute[unconstructorAttrs.size()]);
newquerycols1.addAll(newquerycols2);
List<Attribute<T, Serializable>> newqueryattrs = new ArrayList<>();
newqueryattrs.addAll(List.of(constructorAttributes));
newqueryattrs.addAll(unconstructorAttrs);
queryAttrs = newqueryattrs;
}
return new EntityBuilder<>(creator, aliasmap, constructorParameters, constructorAttributes,
unconstructorAttributes, attributeMap, queryAttrs.toArray(new Attribute[queryAttrs.size()]));
}
public List<T> getObjectList(final DataResultSet rset) {
List<T> list = new ArrayList<>();
List<String> sqlColumns = rset.getColumnLabels();
while (rset.next()) {
list.add(getObjectValue(sqlColumns, rset));
}
return list;
}
public T getObjectValue(final DataResultSetRow row) {
return getObjectValue(null, row);
}
protected T getObjectValue(List<String> sqlColumns, final DataResultSetRow row) {
if (row.wasNull()) {
return null;
}
T obj;
if (sqlColumns == null) {
sqlColumns = row.getColumnLabels();
}
Map<String, Attribute<T, Serializable>> attrs = this.sqlAttrMap;
if (this.constructorParameters == null) {
obj = creator.create();
for (String sqlCol : sqlColumns) {
Attribute<T, Serializable> attr = attrs.get(sqlCol);
if (attr != null) { //兼容返回的字段不存在类中
attr.set(obj, getFieldValue(attr, row, 0));
}
}
} else {
Object[] cps = new Object[this.constructorParameters.length];
for (int i = 0; i < this.constructorAttributes.length; i++) {
Attribute<T, Serializable> attr = this.constructorAttributes[i];
String sqlCol = getSQLColumn(null, attr.field());
if (sqlColumns.contains(sqlCol)) {
cps[i] = getFieldValue(attr, row, 0);
}
}
obj = creator.create(cps);
for (Attribute<T, Serializable> attr : this.unconstructorAttributes) {
String sqlCol = getSQLColumn(null, attr.field());
if (sqlColumns.contains(sqlCol)) {
attr.set(obj, getFieldValue(attr, row, 0));
}
}
}
return obj;
}
public List<T> getEntityList(final SelectColumn sels, final DataResultSet rset) {
List<T> list = new ArrayList<>();
while (rset.next()) {
list.add(getEntityValue(sels, rset));
}
return list;
}
/**
* 将一行的ResultSet组装成一个Entity对象
*
* @param sels 指定字段
* @param row ResultSet
*
* @return Entity对象
*/
public T getEntityValue(final SelectColumn sels, final DataResultSetRow row) {
if (row.wasNull()) {
return null;
}
T obj;
Attribute<T, Serializable>[] attrs = this.attributes;
if (this.constructorParameters == null) {
obj = creator.create();
} else {
Object[] cps = new Object[this.constructorParameters.length];
for (int i = 0; i < this.constructorAttributes.length; i++) {
Attribute<T, Serializable> attr = this.constructorAttributes[i];
if (sels == null || sels.test(attr.field())) {
cps[i] = getFieldValue(attr, row, 0);
}
}
obj = creator.create(cps);
attrs = this.unconstructorAttributes;
}
for (Attribute<T, Serializable> attr : attrs) {
if (sels == null || sels.test(attr.field())) {
attr.set(obj, getFieldValue(attr, row, 0));
}
}
return obj;
}
public List<T> getFullEntityList(final DataResultSet rset) {
List<T> list = new ArrayList<>();
while (rset.next()) {
list.add(getFullEntityValue(rset));
}
return list;
}
public T getFullEntityValue(final DataResultSetRow row) {
return getEntityValue(constructorAttributes, constructorAttributes == null ? attributes : unconstructorAttributes, row);
}
public T getFullEntityValue(final Serializable... values) {
return getEntityValue(constructorAttributes, constructorAttributes == null ? attributes : unconstructorAttributes, values);
}
/**
* 将一行的ResultSet组装成一个Entity对象
*
* @param constructorAttrs 构建函数的Attribute数组, 大小必须与this.constructorAttributes相同
* @param unconstructorAttrs 非构建函数的Attribute数组
* @param row ResultSet
*
* @return Entity对象
*/
protected T getEntityValue(final Attribute<T, Serializable>[] constructorAttrs, final Attribute<T, Serializable>[] unconstructorAttrs, final DataResultSetRow row) {
if (row.wasNull()) {
return null;
}
T obj;
int index = 0;
if (this.constructorParameters == null) {
obj = creator.create();
} else {
Object[] cps = new Object[this.constructorParameters.length];
for (int i = 0; i < constructorAttrs.length; i++) {
Attribute<T, Serializable> attr = constructorAttrs[i];
if (attr == null) {
continue;
}
cps[i] = getFieldValue(attr, row, ++index);
}
obj = creator.create(cps);
}
if (unconstructorAttrs != null) {
for (Attribute<T, Serializable> attr : unconstructorAttrs) {
if (attr == null) {
continue;
}
attr.set(obj, getFieldValue(attr, row, ++index));
}
}
return obj;
}
/**
* 将一行的ResultSet组装成一个Entity对象
*
* @param constructorAttrs 构建函数的Attribute数组, 大小必须与this.constructorAttributes相同
* @param unconstructorAttrs 非构建函数的Attribute数组
* @param values 字段值集合
*
* @return Entity对象
*/
protected T getEntityValue(final Attribute<T, Serializable>[] constructorAttrs, final Attribute<T, Serializable>[] unconstructorAttrs, final Serializable... values) {
if (values == null) {
return null;
}
T obj;
int index = -1;
if (this.constructorParameters == null) {
obj = creator.create();
} else {
Object[] cps = new Object[this.constructorParameters.length];
for (int i = 0; i < constructorAttrs.length; i++) {
Attribute<T, Serializable> attr = constructorAttrs[i];
if (attr == null) {
continue;
}
cps[i] = values[++index];
}
obj = creator.create(cps);
}
if (unconstructorAttrs != null) {
for (Attribute<T, Serializable> attr : unconstructorAttrs) {
if (attr == null) {
continue;
}
attr.set(obj, values[++index]);
}
}
return obj;
}
protected Serializable getFieldValue(Attribute<T, Serializable> attr, final DataResultSetRow row, int index) {
return row.getObject(attr, index, index > 0 ? null : this.getSQLColumn(null, attr.field()));
}
/**
* 根据field字段名获取数据库对应的字段名
*
* @param tabalis 表别名
* @param fieldname 字段名
*
* @return String
*/
public String getSQLColumn(String tabalis, String fieldname) {
return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname))
: (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname)));
}
public boolean hasConstructorAttribute() {
return constructorAttributes != null;
}
/**
* 判断Entity类的字段名与表字段名s是否存在不一致的值
*
* @return boolean
*/
@ConvertDisabled
public boolean isNoAlias() {
return this.aliasmap == null;
}
@ConvertDisabled
public Creator<T> getCreator() {
return creator;
}
}