goupan
2024-04-03 5506e9a45e717ffcb67ec313b5a4e8206d9b3a39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package cn.stylefeng.roses.kernel.scanner.api.factory;
 
import cn.stylefeng.roses.kernel.rule.enums.FieldTypeEnum;
import cn.stylefeng.roses.kernel.rule.util.ClassTypeUtil;
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.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
 * @date 2022/1/13 13:49
 */
@Slf4j
public class ClassDetailMetadataFactory {
 
    /**
     * 根据传入的类型,解析出这个类型的所有子字段类型
     *
     * @param fieldType 需要被解析的对象的类型,可以是class也可以是泛型
     * @param uuid      随机字符串,保证唯一性,用来标识从开始到结束一个context周期内的一系列解析
     * @author fengshuonan
     * @date 2022/1/14 14:31
     */
    public static Set<FieldMetadata> createFieldDetailMetadataSet(Type fieldType, String uuid) {
 
        // 获取参数的类型枚举
        FieldTypeEnum classFieldType = ClassTypeUtil.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;
                Field[] fields = objectClass.getDeclaredFields();
                fieldMetadata = new LinkedHashSet<>();
 
                // 在处理Object中所有字段之前,将当前父类放进context,所有子字段不能含有父类的类型,否则会递归
                MetadataContext.addClassRecord(uuid, objectClass.getName());
 
                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);
                }
                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
     * @date 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 = ClassTypeUtil.getClassFieldType(genericType);
                    fieldMetadata.setFieldType(classFieldType.getCode());
                }
            }
 
            return fieldDetailMetadataSet;
        } else {
            log.debug("带泛型的实体主题rawType非Class类型" + fieldType);
            return null;
        }
    }
 
}