mirror of https://gitee.com/stylefeng/roses
【8.3.0】【scanner】从新整理class类型解析
parent
3de0006f63
commit
97c18870d3
|
@ -1,9 +1,7 @@
|
|||
package cn.stylefeng.roses.kernel.rule.pojo.clazz;
|
||||
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
|
@ -14,8 +12,6 @@ import java.lang.reflect.Type;
|
|||
* @since 2024/8/6 21:49
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ClassParseResult {
|
||||
|
||||
/**
|
||||
|
@ -33,4 +29,23 @@ public class ClassParseResult {
|
|||
*/
|
||||
private Type genericType;
|
||||
|
||||
/**
|
||||
* 针对 FieldTypeEnum = FieldTypeEnum.OBJECT_WITH_GENERIC ,返回主体的class类型
|
||||
*/
|
||||
private Class<?> rawTypeClass;
|
||||
|
||||
public ClassParseResult() {
|
||||
}
|
||||
|
||||
public ClassParseResult(FieldTypeEnum fieldTypeEnum, Type genericType) {
|
||||
this.fieldTypeEnum = fieldTypeEnum;
|
||||
this.genericType = genericType;
|
||||
}
|
||||
|
||||
public ClassParseResult(FieldTypeEnum fieldTypeEnum, Type genericType, Class<?> rawTypeClass) {
|
||||
this.fieldTypeEnum = fieldTypeEnum;
|
||||
this.genericType = genericType;
|
||||
this.rawTypeClass = rawTypeClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,11 +2,10 @@ package cn.stylefeng.roses.kernel.scanner.api.context;
|
|||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.rule.pojo.clazz.ClassParseResult;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.enums.ParamTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.AdvancedClassTypeUtil;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -68,32 +67,20 @@ public class MetadataContext {
|
|||
/**
|
||||
* 判断某个类是否已经被解析过
|
||||
*
|
||||
* @return true-已经被解析过,false-没有被解析过
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/15 10:50
|
||||
*/
|
||||
public static boolean ensureFieldClassHaveParse(String uuid, Type genericType) {
|
||||
public static boolean ensureFieldClassHaveParse(String uuid, Class<?> genericType) {
|
||||
Set<String> classRecords = META_DATA_CLASS_COUNT_CONTEXT.get(uuid);
|
||||
if (classRecords != null) {
|
||||
// 获取字段类型,如果是数组,collection带实体的,需要获取真实的实体类型
|
||||
FieldTypeEnum classFieldType = AdvancedClassTypeUtil.getClassFieldType(genericType);
|
||||
ClassParseResult classParseResult = AdvancedClassTypeUtil.getClassFieldType(genericType);
|
||||
FieldTypeEnum classFieldType = classParseResult.getFieldTypeEnum();
|
||||
|
||||
// 如果是对象类型,直接判断
|
||||
if (classFieldType.equals(FieldTypeEnum.OBJECT)) {
|
||||
return classRecords.contains(((Class<?>) genericType).getName());
|
||||
}
|
||||
|
||||
// 数组类型,则获取数组的实体
|
||||
if (classFieldType.equals(FieldTypeEnum.ARRAY_WITH_OBJECT)) {
|
||||
Class<?> originClass = (Class<?>) genericType;
|
||||
return classRecords.contains(originClass.getComponentType().getName());
|
||||
}
|
||||
|
||||
// 集合类型,获取集合的真实类型
|
||||
if (classFieldType.equals(FieldTypeEnum.COLLECTION_WITH_OBJECT)) {
|
||||
// 获取泛型
|
||||
ParameterizedType parameterizedType = (ParameterizedType) genericType;
|
||||
Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0];
|
||||
return ensureFieldClassHaveParse(uuid, actualTypeArgument);
|
||||
return classRecords.contains(genericType.getName());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.factory;
|
||||
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.ClassReflectUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 针对字段注解的解析
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 10:38
|
||||
*/
|
||||
public class AnnotationParseFactory {
|
||||
|
||||
/**
|
||||
* 解析字段上的注解
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 11:57
|
||||
*/
|
||||
public static void parsingAnnotation(Field declaredField, FieldMetadata fieldDescription) {
|
||||
Annotation[] annotations = declaredField.getAnnotations();
|
||||
if (annotations != null && annotations.length > 0) {
|
||||
|
||||
// 设置字段的所有注解
|
||||
fieldDescription.setAnnotations(ClassReflectUtil.annotationsToStrings(annotations));
|
||||
|
||||
// 遍历字段上的所有注解,找到带groups属性的,按group分类组装注解
|
||||
Map<String, Set<String>> groupAnnotations = new HashMap<>();
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<?>[] validateGroupsClasses = ClassReflectUtil.invokeAnnotationMethodIgnoreError(annotation, "groups", Class[].class);
|
||||
if (validateGroupsClasses != null) {
|
||||
for (Class<?> validateGroupsClass : validateGroupsClasses) {
|
||||
ClassReflectUtil.addGroupValidateAnnotation(annotation, validateGroupsClass, groupAnnotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置分组注解
|
||||
fieldDescription.setGroupValidationMessage(groupAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.factory;
|
||||
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.constants.ScannerConstants;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.context.MetadataContext;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.AdvancedClassTypeUtil;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.ClassDescriptionUtil;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.FieldDescriptionUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 字段信息创建工具
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 13:49
|
||||
*/
|
||||
@Slf4j
|
||||
public class ClassDetailMetadataFactory {
|
||||
|
||||
/**
|
||||
* 根据传入的类型,解析出这个类型的所有子字段类型
|
||||
*
|
||||
* @param fieldType 需要被解析的对象的类型,可以是class也可以是泛型
|
||||
* @param uuid 随机字符串,保证唯一性,用来标识从开始到结束一个context周期内的一系列解析
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 14:31
|
||||
*/
|
||||
public static Set<FieldMetadata> createFieldDetailMetadataSet(Type fieldType, String uuid) {
|
||||
|
||||
// 获取参数的类型枚举
|
||||
FieldTypeEnum classFieldType = AdvancedClassTypeUtil.getClassFieldType(fieldType);
|
||||
|
||||
// 设置响应结果
|
||||
Set<FieldMetadata> fieldMetadata = null;
|
||||
|
||||
// 根据字段类型的不同进行响应的处理
|
||||
switch (classFieldType) {
|
||||
case BASIC:
|
||||
// 基本类型不需要填充子类型信息
|
||||
fieldMetadata = null;
|
||||
break;
|
||||
case BASE_ARRAY:
|
||||
// 如果是简单数组类型,则描述一下这个基本类型的信息
|
||||
Class<?> baseArrayFieldClazz = (Class<?>) fieldType;
|
||||
Class<?> baseArrayComponentType = baseArrayFieldClazz.getComponentType();
|
||||
FieldMetadata baseMetadata = ClassDescriptionUtil.createClassMetadata(baseArrayComponentType, FieldTypeEnum.BASIC, uuid);
|
||||
fieldMetadata = new LinkedHashSet<>();
|
||||
fieldMetadata.add(baseMetadata);
|
||||
break;
|
||||
case ARRAY_WITH_OBJECT:
|
||||
// 如果是带实体的数组,则加上实体对应的字段信息
|
||||
Class<?> objArrayClass = (Class<?>) fieldType;
|
||||
Class<?> objArrayComponentType = objArrayClass.getComponentType();
|
||||
fieldMetadata = ClassDetailMetadataFactory.createFieldDetailMetadataSet(objArrayComponentType, uuid);
|
||||
break;
|
||||
case BASE_COLLECTION:
|
||||
// 如果是基础集合,因为不确定集合的内容,所以使用Object来描述一下集合的具体内容
|
||||
FieldMetadata collectionFieldMetadata = ClassDescriptionUtil.createClassMetadata(Object.class, FieldTypeEnum.OBJECT, uuid);
|
||||
fieldMetadata = new LinkedHashSet<>();
|
||||
fieldMetadata.add(collectionFieldMetadata);
|
||||
break;
|
||||
case COLLECTION_WITH_OBJECT:
|
||||
// 如果是集合里带的具体实体对象,则描述一下具体实体的数据结构
|
||||
ParameterizedType collectionParameterizedType = (ParameterizedType) fieldType;
|
||||
Type[] actualTypeArguments = collectionParameterizedType.getActualTypeArguments();
|
||||
fieldMetadata = ClassDetailMetadataFactory.createFieldDetailMetadataSet(actualTypeArguments[0], uuid);
|
||||
break;
|
||||
case OBJECT:
|
||||
// 如果是实体对象,则描述实体对象的所有字段信息
|
||||
Class<?> objectClass = (Class<?>) fieldType;
|
||||
fieldMetadata = new LinkedHashSet<>();
|
||||
processClassFields(objectClass, fieldMetadata, uuid);
|
||||
break;
|
||||
case OBJECT_WITH_GENERIC:
|
||||
// 如果是带泛型的Object实体类型
|
||||
ParameterizedType objWithGenericParameterizedType = (ParameterizedType) fieldType;
|
||||
// 先获取主体类型
|
||||
Type rawType = objWithGenericParameterizedType.getRawType();
|
||||
// 获取具体泛型
|
||||
Type genericType = objWithGenericParameterizedType.getActualTypeArguments()[0];
|
||||
|
||||
// 判断带泛型的实体,有没有进行做字段解析,如果解析过,则跳过
|
||||
String totalName = fieldType.getTypeName() + genericType.getTypeName();
|
||||
if (MetadataContext.ensureFieldClassHaveParse(uuid, totalName)) {
|
||||
return null;
|
||||
}
|
||||
MetadataContext.addClassRecord(uuid, totalName);
|
||||
|
||||
// 获取主体的所有字段信息
|
||||
fieldMetadata = getEntityWithGenericFieldMetadataList(rawType, genericType, uuid);
|
||||
default:
|
||||
}
|
||||
|
||||
return fieldMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体带泛型类型的字段填充详情,例如PageResult<SysUser>这种字段
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 18:51
|
||||
*/
|
||||
public static Set<FieldMetadata> getEntityWithGenericFieldMetadataList(Type fieldType, Type genericType, String uuid) {
|
||||
if (fieldType instanceof Class<?>) {
|
||||
Class<?> clazz = (Class<?>) fieldType;
|
||||
// 获取主类型的所有属性
|
||||
Set<FieldMetadata> fieldDetailMetadataSet = createFieldDetailMetadataSet(clazz, uuid);
|
||||
if (fieldDetailMetadataSet == null) {
|
||||
return null;
|
||||
}
|
||||
for (FieldMetadata fieldMetadata : fieldDetailMetadataSet) {
|
||||
// 如果是带泛型集合,如下情况List<T>,又或是直接 T 这种形式
|
||||
if (FieldTypeEnum.COLLECTION_WITH_OBJECT.getCode().equals(fieldMetadata.getFieldType())
|
||||
|| FieldTypeEnum.WITH_UNKNOWN_GENERIC.getCode().equals(fieldMetadata.getFieldType())) {
|
||||
// 设置这个字段的子字段描述
|
||||
fieldMetadata.setGenericFieldMetadata(createFieldDetailMetadataSet(genericType, uuid));
|
||||
}
|
||||
|
||||
// 如果T在携带在一个实体类上,例如ResponseData<T>这种形式
|
||||
else if (FieldTypeEnum.OBJECT_WITH_GENERIC.getCode().equals(fieldMetadata.getFieldType())) {
|
||||
// 设置这个字段的子字段描述
|
||||
Set<FieldMetadata> current = null;
|
||||
try {
|
||||
current = getEntityWithGenericFieldMetadataList(Class.forName(fieldMetadata.getFieldClassPath()), genericType, uuid);
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("类无法找到" + fieldMetadata.getFieldClassPath(), e);
|
||||
continue;
|
||||
}
|
||||
fieldMetadata.setGenericFieldMetadata(current);
|
||||
}
|
||||
|
||||
// 如果是T这种形式,应该将当前fieldMetadata的类型改为泛型的类型,例如参数genericType是List时候
|
||||
if (FieldTypeEnum.WITH_UNKNOWN_GENERIC.getCode().equals(fieldMetadata.getFieldType())) {
|
||||
FieldTypeEnum classFieldType = AdvancedClassTypeUtil.getClassFieldType(genericType);
|
||||
fieldMetadata.setFieldType(classFieldType.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
return fieldDetailMetadataSet;
|
||||
} else {
|
||||
log.debug("带泛型的实体主题rawType非Class类型" + fieldType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类的字段信息,增加可以获取父级的类的字段
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 18:51
|
||||
*/
|
||||
private static void processClassFields(Class<?> clazz, Set<FieldMetadata> fieldMetadata, String uuid) {
|
||||
if (clazz == null || clazz == Object.class) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 在处理Object中所有字段之前,将当前父类放进context,所有子字段不能含有父类的类型,否则会递归
|
||||
MetadataContext.addClassRecord(uuid, clazz.getName());
|
||||
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
FieldMetadata fieldInfo;
|
||||
|
||||
// 判断字段是否是基础字段例如serialVersionUID,或者delFlag等字段
|
||||
if (ScannerConstants.DONT_PARSE_FIELD.contains(field.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断该实体是否被解析过,防止无限递归解析实体
|
||||
if (MetadataContext.ensureFieldClassHaveParse(uuid, field.getGenericType())) {
|
||||
fieldInfo = FieldDescriptionUtil.createBasicMetadata(field, uuid);
|
||||
} else {
|
||||
fieldInfo = FieldDescriptionUtil.createFieldMetadata(field, uuid);
|
||||
}
|
||||
fieldMetadata.add(fieldInfo);
|
||||
}
|
||||
|
||||
// 递归处理父类
|
||||
processClassFields(clazz.getSuperclass(), fieldMetadata, uuid);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.factory;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.rule.pojo.clazz.ClassParseResult;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.constants.ScannerConstants;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.context.MetadataContext;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.SubFieldMetadataDTO;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.AdvancedClassTypeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 字段信息创建工具,一般用这个类作为类解析的入口
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 13:49
|
||||
*/
|
||||
@Slf4j
|
||||
public class ClassMetaFactory {
|
||||
|
||||
/**
|
||||
* 通过传入的类型(Class或ParameterizedType)进行字段校验,解析出字段的元数据
|
||||
*
|
||||
* @param type 需要被解析的对象的类型,可以是class也可以是泛型
|
||||
* @param uuid 随机字符串,保证唯一性,用来标识从开始到结束一个context周期内的一系列解析
|
||||
* @return 传入类型的字段元数据信息
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 13:51
|
||||
*/
|
||||
public static FieldMetadata beginCreateFieldMetadata(Type type, String uuid) {
|
||||
|
||||
// 获取类型的枚举
|
||||
ClassParseResult classParseResult = AdvancedClassTypeUtil.getClassFieldType(type);
|
||||
|
||||
// 1. 如果是基础类型,直接渲染结果
|
||||
if (FieldTypeEnum.BASIC.equals(classParseResult.getFieldTypeEnum())) {
|
||||
return MetadataCreateFactory.createBaseClassMetadata((Class<?>) type, uuid);
|
||||
}
|
||||
|
||||
// 2. 如果是数组类型,则先创建一个数组类型的元数据,再获取数组具体的类型,再继续解析数组的类型
|
||||
else if (FieldTypeEnum.ARRAY.equals(classParseResult.getFieldTypeEnum())) {
|
||||
return createArrayMetaDateResult(uuid, classParseResult);
|
||||
}
|
||||
|
||||
// 3. 如果是collection集合类型,同array类型
|
||||
else if (FieldTypeEnum.COLLECTION.equals(classParseResult.getFieldTypeEnum())) {
|
||||
return createArrayMetaDateResult(uuid, classParseResult);
|
||||
}
|
||||
|
||||
// 4. 如果是Object类型,则找到对象的所有的子字段,填充到genericFieldMetadata这个字段中
|
||||
else if (FieldTypeEnum.OBJECT.equals(classParseResult.getFieldTypeEnum())) {
|
||||
// 获取对象的类信息
|
||||
Class<?> clazz = (Class<?>) type;
|
||||
|
||||
// 创建对象的基础信息
|
||||
FieldMetadata currentClassMetaData = MetadataCreateFactory.createBaseClassMetadata((Class<?>) type, uuid);
|
||||
|
||||
// 如果被初始化过,则不继续进行解析
|
||||
if (MetadataContext.ensureFieldClassHaveParse(uuid, clazz)) {
|
||||
return currentClassMetaData;
|
||||
}
|
||||
|
||||
// 获取对象的所有字段信息,这里因为要递归获取本类+父类的字段,所以先创建空集合
|
||||
Set<FieldMetadata> totalFieldList = new LinkedHashSet<>();
|
||||
ClassMetaFactory.processClassFields(clazz, totalFieldList, uuid);
|
||||
currentClassMetaData.setGenericFieldMetadata(totalFieldList);
|
||||
return currentClassMetaData;
|
||||
}
|
||||
|
||||
// 5. 如果是携带泛型的对象
|
||||
else if (FieldTypeEnum.OBJECT_WITH_GENERIC.equals(classParseResult.getFieldTypeEnum())) {
|
||||
|
||||
// 先解析主体的字段信息
|
||||
Class<?> rawTypeClass = classParseResult.getRawTypeClass();
|
||||
|
||||
// 解析主体字段的所有信息
|
||||
FieldMetadata rawTypeMetadata = ClassMetaFactory.beginCreateFieldMetadata(rawTypeClass, uuid);
|
||||
|
||||
// **这里需要遍历一下所有字段,如果有T类型,则需要单独配置一下T类型的FieldMetadata**
|
||||
// 1. 遍历所有字段
|
||||
Set<FieldMetadata> genericFieldMetadata = rawTypeMetadata.getGenericFieldMetadata();
|
||||
if (ObjectUtil.isEmpty(genericFieldMetadata)) {
|
||||
return rawTypeMetadata;
|
||||
}
|
||||
for (FieldMetadata subField : genericFieldMetadata) {
|
||||
if (!FieldTypeEnum.WITH_UNKNOWN_GENERIC.getCode().equals(subField.getFieldType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. 获取这个字段的类型,也就是泛型对象的泛型
|
||||
Type subFieldType = classParseResult.getGenericType();
|
||||
|
||||
// 3. 继续进行这个字段的解析,判断是否需要填充子字段或者数组字段
|
||||
SubFieldMetadataDTO typeSubInfo = ClassMetaFactory.getTypeSubInfo(uuid, subFieldType);
|
||||
subField.setGenericFieldMetadata(typeSubInfo.getGenericFieldMetadata());
|
||||
subField.setArrayFieldMetadata(typeSubInfo.getArrayFieldMetadata());
|
||||
}
|
||||
return rawTypeMetadata;
|
||||
}
|
||||
|
||||
// 6. 其他情况,返回最基本的数据
|
||||
else {
|
||||
return MetadataCreateFactory.createBaseClassMetadata((Class<?>) type, uuid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数组类型的元数据
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 10:05
|
||||
*/
|
||||
private static FieldMetadata createArrayMetaDateResult(String uuid, ClassParseResult classParseResult) {
|
||||
// 先创建一个数组类型的元数据
|
||||
FieldMetadata arrayItemMetadata = MetadataCreateFactory.createArrayItemMetadata(uuid);
|
||||
|
||||
// 获取数组元素的类型
|
||||
Type genericType = classParseResult.getGenericType();
|
||||
|
||||
// 再将数组的类型进行解析,(递归调用)
|
||||
FieldMetadata arrayFieldMetadata = ClassMetaFactory.beginCreateFieldMetadata(genericType, uuid);
|
||||
arrayItemMetadata.setArrayFieldMetadata(arrayFieldMetadata);
|
||||
|
||||
return arrayItemMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类的字段信息,增加可以获取父级的类的字段
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 10:15
|
||||
*/
|
||||
private static void processClassFields(Class<?> clazz, Set<FieldMetadata> fieldMetadata, String uuid) {
|
||||
if (clazz == null || Object.class.equals(clazz)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 在处理Object中所有字段之前,将当前父类放进context,所有子字段不能含有父类的类型,否则会递归
|
||||
MetadataContext.addClassRecord(uuid, clazz.getName());
|
||||
|
||||
// 获取类中的所有字段
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
|
||||
// 1. 判断字段是否是基础字段例如serialVersionUID,或者delFlag等字段
|
||||
if (ScannerConstants.DONT_PARSE_FIELD.contains(field.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. 先填充这个字段的基础信息
|
||||
FieldMetadata fieldInfo = MetadataCreateFactory.createBaseFieldMetadata(field, uuid);
|
||||
|
||||
// 3. 再根据这个字段的类型,进行递归解析子属性的填充
|
||||
Type genericType = field.getGenericType();
|
||||
|
||||
SubFieldMetadataDTO typeSubInfo = ClassMetaFactory.getTypeSubInfo(uuid, genericType);
|
||||
fieldInfo.setGenericFieldMetadata(typeSubInfo.getGenericFieldMetadata());
|
||||
fieldInfo.setArrayFieldMetadata(typeSubInfo.getArrayFieldMetadata());
|
||||
|
||||
fieldMetadata.add(fieldInfo);
|
||||
}
|
||||
|
||||
// 递归处理父类
|
||||
processClassFields(clazz.getSuperclass(), fieldMetadata, uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个Type是否包含子对象或者数组元素
|
||||
* <p>
|
||||
* 用来解析针对数组和obj类型的时候
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 11:43
|
||||
*/
|
||||
public static SubFieldMetadataDTO getTypeSubInfo(String uuid, Type type) {
|
||||
SubFieldMetadataDTO fieldInfo = new SubFieldMetadataDTO();
|
||||
|
||||
// 1. 获取这个对应type的类型信息
|
||||
FieldMetadata validateFieldHaveSubInfo = ClassMetaFactory.beginCreateFieldMetadata(type, uuid);
|
||||
|
||||
// 2. 填充他的子对象,用来针对obj类型的字段进行解析
|
||||
Set<FieldMetadata> genericFieldMetadata = validateFieldHaveSubInfo.getGenericFieldMetadata();
|
||||
if (ObjectUtil.isNotEmpty(genericFieldMetadata)) {
|
||||
fieldInfo.setGenericFieldMetadata(genericFieldMetadata);
|
||||
}
|
||||
|
||||
// 3. 填充他的数组对象,用来针对array类型的字段进行解析
|
||||
FieldMetadata arrayFieldMetadata = validateFieldHaveSubInfo.getArrayFieldMetadata();
|
||||
if (ObjectUtil.isNotEmpty(arrayFieldMetadata)) {
|
||||
fieldInfo.setArrayFieldMetadata(arrayFieldMetadata);
|
||||
}
|
||||
|
||||
return fieldInfo;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.factory;
|
||||
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.AdvancedClassTypeUtil;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.ClassDescriptionUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 字段信息创建工具,一般用这个类作为类解析的入口
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 13:49
|
||||
*/
|
||||
@Slf4j
|
||||
public class ClassMetadataFactory {
|
||||
|
||||
/**
|
||||
* 通过传入的类型(Class或ParameterizedType)进行字段校验,解析出字段的元数据
|
||||
*
|
||||
* @param type 需要被解析的对象的类型,可以是class也可以是泛型
|
||||
* @param uuid 随机字符串,保证唯一性,用来标识从开始到结束一个context周期内的一系列解析
|
||||
* @return 传入类型的字段元数据信息
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 13:51
|
||||
*/
|
||||
public static FieldMetadata beginCreateFieldMetadata(Type type, String uuid) {
|
||||
|
||||
// 获取类型的枚举
|
||||
FieldTypeEnum classFieldType = AdvancedClassTypeUtil.getClassFieldType(type);
|
||||
|
||||
// 设置响应结果
|
||||
FieldMetadata fieldMetadata = null;
|
||||
|
||||
// 组装类的基本信息
|
||||
if (type instanceof Class<?>) {
|
||||
Class<?> clazz = (Class<?>) type;
|
||||
|
||||
// 创建类型的基本信息
|
||||
fieldMetadata = ClassDescriptionUtil.createClassMetadata(clazz, classFieldType, uuid);
|
||||
|
||||
// 补充类型的子信息
|
||||
Set<FieldMetadata> fieldDetailMetadataSet = ClassDetailMetadataFactory.createFieldDetailMetadataSet(clazz, uuid);
|
||||
fieldMetadata.setGenericFieldMetadata(fieldDetailMetadataSet);
|
||||
}
|
||||
|
||||
// 如果是带泛型的
|
||||
else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
|
||||
// 创建类型的基本信息
|
||||
fieldMetadata = ClassDescriptionUtil.createParameterizedMetadata(parameterizedType, classFieldType, uuid);
|
||||
|
||||
// 补充类型的子信息
|
||||
Set<FieldMetadata> fieldDetailMetadataSet = ClassDetailMetadataFactory.createFieldDetailMetadataSet(type, uuid);
|
||||
fieldMetadata.setGenericFieldMetadata(fieldDetailMetadataSet);
|
||||
}
|
||||
|
||||
// 其他情况
|
||||
else {
|
||||
log.debug("未知类型的处理,既不是class也不是ParameterizedType,打印出类的信息如下:{}", type.getTypeName());
|
||||
}
|
||||
|
||||
return fieldMetadata;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.factory;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.stylefeng.roses.kernel.rule.annotation.ChineseDescription;
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.rule.pojo.clazz.ClassParseResult;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.context.MetadataContext;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.enums.ParamTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.util.AdvancedClassTypeUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 元数据的生成工厂
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 9:49
|
||||
*/
|
||||
public class MetadataCreateFactory {
|
||||
|
||||
/**
|
||||
* 根据一个类,创建metadata
|
||||
* <p>
|
||||
* 一般这个用在fieldTypeEnum为基础字段的时候使用
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 9:48
|
||||
*/
|
||||
public static FieldMetadata createBaseClassMetadata(Class<?> clazz, String uuid) {
|
||||
FieldMetadata fieldMetadataItem = new FieldMetadata();
|
||||
|
||||
// 设置唯一id
|
||||
fieldMetadataItem.setMetadataId(IdUtil.fastSimpleUUID());
|
||||
|
||||
// 设置字段中文含义
|
||||
fieldMetadataItem.setChineseName(clazz.getSimpleName());
|
||||
|
||||
// 设置字段类类型
|
||||
fieldMetadataItem.setFieldClassType(clazz.getSimpleName());
|
||||
|
||||
// 设置类的全路径
|
||||
fieldMetadataItem.setFieldClassPath(clazz.getName());
|
||||
|
||||
// 根据uuid获取参数的名称
|
||||
String paramName = MetadataContext.getParamName(uuid);
|
||||
if (StrUtil.isNotBlank(paramName)) {
|
||||
fieldMetadataItem.setFieldName(paramName);
|
||||
}
|
||||
|
||||
// 设置字段类型,基本类型
|
||||
fieldMetadataItem.setFieldType(FieldTypeEnum.BASIC.getCode());
|
||||
|
||||
// 设置当前context构造的参数类型
|
||||
ParamTypeEnum paramTypeMetadata = MetadataContext.getParamTypeMetadata(uuid);
|
||||
if (paramTypeMetadata != null) {
|
||||
fieldMetadataItem.setRequestParamType(paramTypeMetadata.getCode());
|
||||
}
|
||||
|
||||
// 设置字段
|
||||
return fieldMetadataItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个数组类型的元数据
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 9:53
|
||||
*/
|
||||
public static FieldMetadata createArrayItemMetadata(String uuid) {
|
||||
FieldMetadata fieldMetadataItem = new FieldMetadata();
|
||||
|
||||
// 设置唯一id
|
||||
fieldMetadataItem.setMetadataId(IdUtil.fastSimpleUUID());
|
||||
|
||||
// 设置字段中文含义
|
||||
fieldMetadataItem.setChineseName("数组元素");
|
||||
|
||||
// 设置字段类类型
|
||||
fieldMetadataItem.setFieldClassType("String");
|
||||
|
||||
// 设置类的全路径
|
||||
fieldMetadataItem.setFieldClassPath("java.lang.String");
|
||||
|
||||
// 设置字段名称
|
||||
fieldMetadataItem.setFieldName("arrayItem");
|
||||
|
||||
// 根据uuid获取参数的名称
|
||||
String paramName = MetadataContext.getParamName(uuid);
|
||||
if (StrUtil.isNotBlank(paramName)) {
|
||||
fieldMetadataItem.setFieldName(paramName);
|
||||
}
|
||||
|
||||
// 设置数组类型
|
||||
fieldMetadataItem.setFieldType(FieldTypeEnum.ARRAY.getCode());
|
||||
|
||||
// 设置当前context构造的参数类型
|
||||
ParamTypeEnum paramTypeMetadata = MetadataContext.getParamTypeMetadata(uuid);
|
||||
if (paramTypeMetadata != null) {
|
||||
fieldMetadataItem.setRequestParamType(paramTypeMetadata.getCode());
|
||||
}
|
||||
|
||||
// 设置字段
|
||||
return fieldMetadataItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建针对字段的元数据描述
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 10:36
|
||||
*/
|
||||
public static FieldMetadata createBaseFieldMetadata(Field field, String uuid) {
|
||||
FieldMetadata fieldMetadataItem = new FieldMetadata();
|
||||
|
||||
// 设置唯一id
|
||||
fieldMetadataItem.setMetadataId(IdUtil.fastSimpleUUID());
|
||||
|
||||
// 设置字段中文含义
|
||||
ChineseDescription annotation = field.getAnnotation(ChineseDescription.class);
|
||||
if (annotation != null) {
|
||||
fieldMetadataItem.setChineseName(annotation.value());
|
||||
}
|
||||
|
||||
// 设置字段类类型
|
||||
Class<?> classType = field.getType();
|
||||
fieldMetadataItem.setFieldClassType(classType.getSimpleName());
|
||||
|
||||
// 设置类的全路径
|
||||
fieldMetadataItem.setFieldClassPath(classType.getName());
|
||||
|
||||
// 设置对应字段名称
|
||||
fieldMetadataItem.setFieldName(field.getName());
|
||||
|
||||
// 处理注解信息
|
||||
AnnotationParseFactory.parsingAnnotation(field, fieldMetadataItem);
|
||||
|
||||
// 设置字段类型,基本、数组、还是object
|
||||
ClassParseResult classParseResult = AdvancedClassTypeUtil.getClassFieldType(field.getGenericType());
|
||||
fieldMetadataItem.setFieldType(classParseResult.getFieldTypeEnum().getCode());
|
||||
|
||||
// 设置当前context构造的参数类型
|
||||
ParamTypeEnum paramTypeMetadata = MetadataContext.getParamTypeMetadata(uuid);
|
||||
if (paramTypeMetadata != null) {
|
||||
fieldMetadataItem.setRequestParamType(paramTypeMetadata.getCode());
|
||||
}
|
||||
|
||||
return fieldMetadataItem;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
||||
*/
|
||||
package cn.stylefeng.roses.kernel.scanner.api.pojo.resource;
|
||||
|
||||
import cn.stylefeng.roses.kernel.rule.annotation.ChineseDescription;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用来临时保存,字段的子字段信息的数据,用在obj和数组类型
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/7 11:41
|
||||
*/
|
||||
@Data
|
||||
public class SubFieldMetadataDTO {
|
||||
|
||||
/**
|
||||
* 泛型或object类型的字段的描述
|
||||
*/
|
||||
@ChineseDescription("泛型或object类型的字段的描述")
|
||||
private Set<FieldMetadata> genericFieldMetadata;
|
||||
|
||||
/**
|
||||
* 针对数组类型的字段,指定数组的子类型
|
||||
*/
|
||||
@ChineseDescription("针对数组类型的字段,指定数组的子类型")
|
||||
private FieldMetadata arrayFieldMetadata;
|
||||
|
||||
}
|
|
@ -137,7 +137,7 @@ public class AdvancedClassTypeUtil {
|
|||
|
||||
// 如果泛型的主体是实体包装类
|
||||
else if (AdvancedClassTypeUtil.ensureEntityFlag(rawTypeClass)) {
|
||||
return new ClassParseResult(FieldTypeEnum.OBJECT_WITH_GENERIC, actualTypeArgument);
|
||||
return new ClassParseResult(FieldTypeEnum.OBJECT_WITH_GENERIC, actualTypeArgument, rawTypeClass);
|
||||
}
|
||||
|
||||
// 泛型的主体情况不确定,不处理
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.util;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.context.MetadataContext;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.enums.GenericFieldMetadataType;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.enums.ParamTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* 类的元数据描述
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 10:59
|
||||
*/
|
||||
public class ClassDescriptionUtil {
|
||||
|
||||
/**
|
||||
* 创建针对类的基础描述
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 18:06
|
||||
*/
|
||||
public static FieldMetadata createClassMetadata(Class<?> clazz, FieldTypeEnum fieldTypeEnum, String uuid) {
|
||||
FieldMetadata fieldMetadataItem = new FieldMetadata();
|
||||
// 设置唯一id
|
||||
fieldMetadataItem.setMetadataId(IdUtil.fastSimpleUUID());
|
||||
// 设置字段中文含义
|
||||
fieldMetadataItem.setChineseName(clazz.getSimpleName());
|
||||
// 设置字段类类型
|
||||
fieldMetadataItem.setFieldClassType(clazz.getSimpleName());
|
||||
// 设置类的全路径
|
||||
fieldMetadataItem.setFieldClassPath(clazz.getName());
|
||||
// 根据uuid获取参数的名称
|
||||
String paramName = MetadataContext.getParamName(uuid);
|
||||
if (StrUtil.isNotBlank(paramName)) {
|
||||
fieldMetadataItem.setFieldName(paramName);
|
||||
}
|
||||
|
||||
// 【2024年8月5日新增】判断数组的类型
|
||||
fieldMetadataItem.setGenericFieldMetadataType(GenericFieldMetadataType.BASE_TYPE.getCode());
|
||||
if (FieldTypeEnum.ARRAY_WITH_OBJECT.equals(fieldTypeEnum)) {
|
||||
fieldMetadataItem.setGenericFieldMetadataType(GenericFieldMetadataType.OBJECT_TYPE.getCode());
|
||||
}
|
||||
// 如果是集合类型,判断集合的泛型,集合的泛型是对象的话,就是对象类型,否则就是基本类型
|
||||
else if (FieldTypeEnum.COLLECTION_WITH_OBJECT.equals(fieldTypeEnum)) {
|
||||
if (ClassDescriptionUtil.getClassGenObjectFlag(clazz)) {
|
||||
fieldMetadataItem.setGenericFieldMetadataType(GenericFieldMetadataType.OBJECT_TYPE.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
// 设置字段类型,基本、数组、还是object
|
||||
fieldMetadataItem.setFieldType(fieldTypeEnum.getCode());
|
||||
// 设置当前context构造的参数类型
|
||||
ParamTypeEnum paramTypeMetadata = MetadataContext.getParamTypeMetadata(uuid);
|
||||
if (paramTypeMetadata != null) {
|
||||
fieldMetadataItem.setRequestParamType(paramTypeMetadata.getCode());
|
||||
}
|
||||
// 设置字段
|
||||
return fieldMetadataItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建针对类的基础描述
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 18:06
|
||||
*/
|
||||
public static FieldMetadata createParameterizedMetadata(ParameterizedType parameterizedType, FieldTypeEnum fieldTypeEnum, String uuid) {
|
||||
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
|
||||
FieldMetadata classMetadata = createClassMetadata(rawType, fieldTypeEnum, uuid);
|
||||
|
||||
// 设置泛型的类型
|
||||
boolean classGenObjectFlag = ClassDescriptionUtil.getClassGenObjectFlag(parameterizedType);
|
||||
if (classGenObjectFlag) {
|
||||
classMetadata.setGenericFieldMetadataType(GenericFieldMetadataType.OBJECT_TYPE.getCode());
|
||||
}
|
||||
return classMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的泛型,是否为Object类型
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/5 14:36
|
||||
*/
|
||||
public static boolean getClassGenObjectFlag(Class<?> clazz) {
|
||||
Type genericSuperclass = clazz.getGenericSuperclass();
|
||||
return getClassGenObjectFlag(genericSuperclass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的泛型,是否为Object类型
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2024/8/5 14:36
|
||||
*/
|
||||
public static boolean getClassGenObjectFlag(Type type) {
|
||||
if (type instanceof ParameterizedType parameterizedType) {
|
||||
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
||||
if (actualTypeArguments.length > 0) {
|
||||
Type actualTypeArgument = actualTypeArguments[0];
|
||||
FieldTypeEnum classFieldType = AdvancedClassTypeUtil.getClassFieldType(actualTypeArgument);
|
||||
return FieldTypeEnum.OBJECT.equals(classFieldType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.scanner.api.util;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.stylefeng.roses.kernel.rule.annotation.ChineseDescription;
|
||||
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.context.MetadataContext;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.enums.GenericFieldMetadataType;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.enums.ParamTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.factory.ClassDetailMetadataFactory;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 字段的元数据描述
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 10:59
|
||||
*/
|
||||
public class FieldDescriptionUtil {
|
||||
|
||||
/**
|
||||
* 创建类内字段的元数据,只组装基本信息
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 18:06
|
||||
*/
|
||||
public static FieldMetadata createBasicMetadata(Field field, String uuid) {
|
||||
FieldMetadata fieldMetadataItem = new FieldMetadata();
|
||||
// 设置唯一id
|
||||
fieldMetadataItem.setMetadataId(IdUtil.fastSimpleUUID());
|
||||
// 设置字段中文含义
|
||||
ChineseDescription annotation = field.getAnnotation(ChineseDescription.class);
|
||||
if (annotation != null) {
|
||||
fieldMetadataItem.setChineseName(annotation.value());
|
||||
}
|
||||
// 设置字段类类型
|
||||
Class<?> classType = field.getType();
|
||||
fieldMetadataItem.setFieldClassType(classType.getSimpleName());
|
||||
// 设置类的全路径
|
||||
fieldMetadataItem.setFieldClassPath(classType.getName());
|
||||
// 设置对应字段名称
|
||||
fieldMetadataItem.setFieldName(field.getName());
|
||||
// 处理注解信息
|
||||
parsingAnnotation(field, fieldMetadataItem);
|
||||
// 设置是否带泛型
|
||||
Type genericType = field.getGenericType();
|
||||
// 【2024年8月5日新增】更新判断泛型的对象类型的方法
|
||||
boolean classGenObjectFlag = ClassDescriptionUtil.getClassGenObjectFlag(genericType);
|
||||
if (classGenObjectFlag) {
|
||||
fieldMetadataItem.setGenericFieldMetadataType(GenericFieldMetadataType.OBJECT_TYPE.getCode());
|
||||
} else {
|
||||
fieldMetadataItem.setGenericFieldMetadataType(GenericFieldMetadataType.BASE_TYPE.getCode());
|
||||
}
|
||||
// 设置字段类型,基本、数组、还是object
|
||||
FieldTypeEnum classFieldType = AdvancedClassTypeUtil.getClassFieldType(genericType);
|
||||
fieldMetadataItem.setFieldType(classFieldType.getCode());
|
||||
// 设置当前context构造的参数类型
|
||||
ParamTypeEnum paramTypeMetadata = MetadataContext.getParamTypeMetadata(uuid);
|
||||
if (paramTypeMetadata != null) {
|
||||
fieldMetadataItem.setRequestParamType(paramTypeMetadata.getCode());
|
||||
}
|
||||
return fieldMetadataItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建类内字段的元数据,组装基本信息 + 子字段信息
|
||||
* <p>
|
||||
* 为何区分两个方法分别组装,因为存在实体中又包含本实体字段的情况,会出现无限递归
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/13 18:06
|
||||
*/
|
||||
public static FieldMetadata createFieldMetadata(Field field, String uuid) {
|
||||
// 先组装基础数据
|
||||
FieldMetadata fieldMetadata = createBasicMetadata(field, uuid);
|
||||
// 组装子类型数据
|
||||
Type genericType = field.getGenericType();
|
||||
Set<FieldMetadata> fieldDetailMetadataSet = ClassDetailMetadataFactory.createFieldDetailMetadataSet(genericType, uuid);
|
||||
fieldMetadata.setGenericFieldMetadata(fieldDetailMetadataSet);
|
||||
return fieldMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析字段上的注解
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @since 2022/1/14 11:57
|
||||
*/
|
||||
private static void parsingAnnotation(Field declaredField, FieldMetadata fieldDescription) {
|
||||
Annotation[] annotations = declaredField.getAnnotations();
|
||||
if (annotations != null && annotations.length > 0) {
|
||||
|
||||
// 设置字段的所有注解
|
||||
fieldDescription.setAnnotations(ClassReflectUtil.annotationsToStrings(annotations));
|
||||
|
||||
// 遍历字段上的所有注解,找到带groups属性的,按group分类组装注解
|
||||
Map<String, Set<String>> groupAnnotations = new HashMap<>();
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<?>[] validateGroupsClasses = ClassReflectUtil.invokeAnnotationMethodIgnoreError(annotation, "groups", Class[].class);
|
||||
if (validateGroupsClasses != null) {
|
||||
for (Class<?> validateGroupsClass : validateGroupsClasses) {
|
||||
ClassReflectUtil.addGroupValidateAnnotation(annotation, validateGroupsClass, groupAnnotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置分组注解
|
||||
fieldDescription.setGroupValidationMessage(groupAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,7 @@ import cn.stylefeng.roses.kernel.scanner.api.annotation.PostResource;
|
|||
import cn.stylefeng.roses.kernel.scanner.api.constants.ScannerConstants;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.context.MetadataContext;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.exception.ScannerException;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.factory.ClassMetadataFactory;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.factory.ClassMetaFactory;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.holder.IpAddrHolder;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.FieldMetadata;
|
||||
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.ParameterMetadata;
|
||||
|
@ -312,7 +312,7 @@ public class ApiResourceScanner implements BeanPostProcessor {
|
|||
// 填充方法返回结果字段的详细信息
|
||||
Type returnType = MethodReflectUtil.getMethodReturnType(method);
|
||||
String processReturnTypeUuid = RandomUtil.randomString(32);
|
||||
resourceDefinition.setResponseFieldDescriptions(ClassMetadataFactory.beginCreateFieldMetadata(returnType, processReturnTypeUuid));
|
||||
resourceDefinition.setResponseFieldDescriptions(ClassMetaFactory.beginCreateFieldMetadata(returnType, processReturnTypeUuid));
|
||||
MetadataContext.cleanContext(processReturnTypeUuid);
|
||||
|
||||
// 填充方法的请求参数字段的详细信息
|
||||
|
@ -325,7 +325,7 @@ public class ApiResourceScanner implements BeanPostProcessor {
|
|||
MetadataContext.addParamTypeMetadata(parameterContextUuid, parameterMetadata.getParamTypeEnum());
|
||||
MetadataContext.addParameterName(parameterContextUuid, parameterMetadata.getParameterName());
|
||||
fieldMetadataLinkedHashSet.add(
|
||||
ClassMetadataFactory.beginCreateFieldMetadata(parameterMetadata.getParameterizedType(), parameterContextUuid));
|
||||
ClassMetaFactory.beginCreateFieldMetadata(parameterMetadata.getParameterizedType(), parameterContextUuid));
|
||||
MetadataContext.cleanContext(parameterContextUuid);
|
||||
}
|
||||
resourceDefinition.setParamFieldDescriptions(fieldMetadataLinkedHashSet);
|
||||
|
|
Loading…
Reference in New Issue