@hadss/turbo-trans-json-plugin 1.0.0-rc.0 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/core/Types.d.ts +7 -0
- package/dist/core/Types.js +7 -1
- package/dist/core/analyzers/ClassAnalyzer.d.ts +15 -0
- package/dist/core/analyzers/ClassAnalyzer.js +200 -120
- package/dist/core/analyzers/CustomTypeAnalyzer.d.ts +3 -0
- package/dist/core/analyzers/CustomTypeAnalyzer.js +65 -60
- package/dist/core/constants/DecoratorConstants.d.ts +1 -0
- package/dist/core/constants/DecoratorConstants.js +3 -1
- package/dist/core/handlers/CustomClassHandler.js +0 -1
- package/dist/core/import-rewrite/services/BuildProfileUpdater.js +1 -1
- package/dist/core/import-rewrite/services/ImportRewriteService.js +1 -1
- package/dist/core/interfaces/index.d.ts +2 -2
- package/dist/core/services/CodeAnalysisService.js +2 -1
- package/dist/core/services/CodeGenerationService/CodeGenerationService.js +1 -1
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.d.ts +0 -1
- package/dist/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.js +0 -20
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.d.ts +4 -4
- package/dist/core/services/CodeGenerationService/generators/OriginalClassGenerator.js +26 -45
- package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.d.ts +22 -0
- package/dist/core/services/CodeGenerationService/generators/SendableClassGenerator.js +194 -129
- package/dist/core/services/CodeGenerationService/generators/SerializerGenerator.js +20 -15
- package/dist/core/services/CodeGenerationService/generators/TempSerializerGenerator.js +2 -1
- package/dist/core/services/CodeGenerationService/shared/ImportManager.d.ts +2 -2
- package/dist/core/template/HandlebarsTemplateEngine.d.ts +2 -0
- package/dist/core/template/HandlebarsTemplateEngine.js +24 -2
- package/dist/core/utils/DeepCopyUtil.js +4 -2
- package/dist/core/utils/GenericTypeSubstitutionUtil.d.ts +1 -0
- package/dist/core/utils/GenericTypeSubstitutionUtil.js +27 -1
- package/dist/core/utils/SerializationPathUtil.d.ts +1 -1
- package/dist/core/utils/TsMorphUtil.js +6 -1
- package/dist/json-plugin/JSONExecuteController.d.ts +4 -0
- package/dist/json-plugin/JSONExecuteController.js +46 -36
- package/dist/json-plugin/interfaces/impl/TargetContext.js +4 -2
- package/dist/json-plugin/tasks/BaseTask.d.ts +2 -2
- package/dist/json-plugin/tasks/WatchTask.js +2 -1
- package/package.json +1 -1
- package/src/core/Types.ts +97 -89
- package/src/core/analyzers/ClassAnalyzer.ts +358 -197
- package/src/core/analyzers/CustomTypeAnalyzer.ts +145 -74
- package/src/core/constants/DecoratorConstants.ts +7 -5
- package/src/core/constants/PathConstants.ts +7 -7
- package/src/core/constants/StringConstants.ts +95 -97
- package/src/core/handlers/BaseTypeHandler.ts +11 -2
- package/src/core/handlers/CustomClassHandler.ts +4 -7
- package/src/core/handlers/DateHandler.ts +54 -46
- package/src/core/handlers/DecimalHandler.ts +53 -45
- package/src/core/handlers/EnumHandler.ts +2 -1
- package/src/core/handlers/GenericContainerHandler.ts +3 -1
- package/src/core/handlers/TupleHandler.ts +2 -1
- package/src/core/handlers/TypeHandlerRegistry.ts +3 -2
- package/src/core/handlers/UnionTypeHandler.ts +8 -7
- package/src/core/import-rewrite/services/BuildProfileUpdater.ts +7 -5
- package/src/core/import-rewrite/services/ImportRewriteService.ts +1 -3
- package/src/core/import-rewrite/services/ImportTransformService.ts +2 -2
- package/src/core/import-rewrite/types/ImportRewriteTypes.ts +3 -3
- package/src/core/index.ts +4 -4
- package/src/core/interfaces/ITask.ts +6 -5
- package/src/core/interfaces/ITaskContext.ts +9 -9
- package/src/core/interfaces/index.ts +2 -2
- package/src/core/logger/Logger.ts +28 -28
- package/src/core/services/CodeAnalysisService.ts +3 -2
- package/src/core/services/CodeGenerationEngine.ts +42 -42
- package/src/core/services/CodeGenerationService/CodeGenerationService.ts +1 -2
- package/src/core/services/CodeGenerationService/generators/MergedSendableClassGenerator.ts +0 -29
- package/src/core/services/CodeGenerationService/generators/OriginalClassGenerator.ts +31 -64
- package/src/core/services/CodeGenerationService/generators/SendableClassGenerator.ts +261 -170
- package/src/core/services/CodeGenerationService/generators/SerializerGenerator.ts +26 -19
- package/src/core/services/CodeGenerationService/generators/TempSerializerGenerator.ts +5 -3
- package/src/core/services/CodeGenerationService/shared/ImportManager.ts +8 -8
- package/src/core/template/HandlebarsTemplateEngine.ts +43 -10
- package/src/core/utils/ConfigManager.ts +2 -1
- package/src/core/utils/DeepCopyUtil.ts +4 -2
- package/src/core/utils/GenericTypeSubstitutionUtil.ts +45 -2
- package/src/core/utils/SerializationPathUtil.ts +7 -6
- package/src/core/utils/TsMorphUtil.ts +9 -2
- package/src/index.ts +2 -2
- package/src/json-plugin/JSONExecuteController.ts +51 -38
- package/src/json-plugin/interfaces/IModuleContext.ts +8 -8
- package/src/json-plugin/interfaces/ITargetContext.ts +6 -6
- package/src/json-plugin/interfaces/impl/ModuleContext.ts +10 -10
- package/src/json-plugin/interfaces/impl/TargetContext.ts +63 -58
- package/src/json-plugin/tasks/BaseTask.ts +5 -4
- package/src/json-plugin/tasks/CleanTask.ts +7 -7
- package/src/json-plugin/tasks/WatchTask.ts +20 -18
- package/template/SerializerPerformanceTemplate.hbs +14 -4
- package/template/SerializerStrictTemplate.hbs +9 -1
- package/template/SerializerTemplate.hbs +71 -46
|
@@ -14,28 +14,12 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import {
|
|
17
|
-
ClassDeclaration,
|
|
18
|
-
|
|
19
|
-
Decorator,
|
|
20
|
-
InterfaceDeclaration,
|
|
21
|
-
NewExpression,
|
|
22
|
-
PropertyDeclaration,
|
|
23
|
-
PropertySignature,
|
|
24
|
-
SyntaxKind,
|
|
25
|
-
TypeNode
|
|
17
|
+
ClassDeclaration, ConstructorDeclaration, Decorator, InterfaceDeclaration, NewExpression, ObjectLiteralExpression,
|
|
18
|
+
PropertyDeclaration, PropertySignature, SyntaxKind, TypeNode
|
|
26
19
|
} from 'ts-morph';
|
|
27
20
|
import {
|
|
28
|
-
ClassAnalysis,
|
|
29
|
-
InterfaceAnalysis,
|
|
30
|
-
ClassDecorators,
|
|
31
|
-
ConstructorParam,
|
|
32
|
-
DeserializationMode,
|
|
33
|
-
GenericInfo,
|
|
34
|
-
InheritanceInfo,
|
|
35
|
-
PropertyAnalysis,
|
|
36
|
-
PropertyDecorators,
|
|
37
|
-
PropertyKind,
|
|
38
|
-
SerializableOptions,
|
|
21
|
+
ClassAnalysis, ClassDecorators, ConstructorParam, DeserializationMode, GenericInfo, InheritanceInfo,
|
|
22
|
+
InterfaceAnalysis, PropertyAnalysis, PropertyDecorators, PropertyKind, PropertyVisibility, SerializableOptions,
|
|
39
23
|
TypeStructure
|
|
40
24
|
} from '../Types';
|
|
41
25
|
import { DecoratorConstants } from '../constants';
|
|
@@ -45,7 +29,6 @@ import { CustomTypeAnalyzer } from './CustomTypeAnalyzer';
|
|
|
45
29
|
import { CustomError, ErrorCodes } from '../utils/CustomError';
|
|
46
30
|
import { Logger } from '../logger/Logger';
|
|
47
31
|
import { TsMorphUtil } from '../utils/TsMorphUtil';
|
|
48
|
-
import { logger } from 'handlebars';
|
|
49
32
|
|
|
50
33
|
export class ClassAnalyzer {
|
|
51
34
|
/**
|
|
@@ -97,14 +80,15 @@ export class ClassAnalyzer {
|
|
|
97
80
|
}
|
|
98
81
|
|
|
99
82
|
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
83
|
+
* 分析接口的完整结构,包括属性、继承关系等信息
|
|
84
|
+
* @param interfaceDecl 接口声明节点
|
|
85
|
+
* @returns 接口分析结果
|
|
86
|
+
*/
|
|
104
87
|
public static analyzeInterface(interfaceDecl: InterfaceDeclaration): InterfaceAnalysis {
|
|
105
88
|
const interfaceName = interfaceDecl.getName();
|
|
106
89
|
if (!interfaceName) {
|
|
107
|
-
throw new CustomError(`Interface name is undefined in ${interfaceDecl.getSourceFile().getFilePath()}`,
|
|
90
|
+
throw new CustomError(`Interface name is undefined in ${interfaceDecl.getSourceFile().getFilePath()}`,
|
|
91
|
+
ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
|
|
108
92
|
}
|
|
109
93
|
const sourceFilePath = interfaceDecl.getSourceFile().getFilePath();
|
|
110
94
|
const generics: GenericInfo = {
|
|
@@ -141,7 +125,8 @@ export class ClassAnalyzer {
|
|
|
141
125
|
*/
|
|
142
126
|
private static analyzeInheritanceInfo(cls: ClassDeclaration | InterfaceDeclaration): InheritanceInfo {
|
|
143
127
|
const heritageClaus = cls.getHeritageClauses();
|
|
144
|
-
Logger.debug(
|
|
128
|
+
Logger.debug(
|
|
129
|
+
`分析类的继承信息: ${cls.getName()} ${heritageClaus.length} ${heritageClaus.map(c => c.getText()).join(',')}`);
|
|
145
130
|
for (const clause of heritageClaus) {
|
|
146
131
|
const token = clause.getToken();
|
|
147
132
|
// 接口实现
|
|
@@ -155,7 +140,8 @@ export class ClassAnalyzer {
|
|
|
155
140
|
Logger.debug(`继承信息: text: ${className} getTypeArguments: ${args.map(type => type.getText()).join(', ')}`);
|
|
156
141
|
const classDecl = CustomTypeAnalyzer.getInstance().findClassDeclFromClassName(className, cls.getSourceFile());
|
|
157
142
|
if (!classDecl) {
|
|
158
|
-
throw new CustomError(`class ${className} decl does not exist ${cls.getName} implement ${className}`,
|
|
143
|
+
throw new CustomError(`class ${className} decl does not exist ${cls.getName} implement ${className}`,
|
|
144
|
+
ErrorCodes.CLASS_DECLARATION_NOT_FOUND);
|
|
159
145
|
}
|
|
160
146
|
if (classDecl instanceof InterfaceDeclaration) {
|
|
161
147
|
const baseClassAnalysis = this.analyzeInterface(classDecl);
|
|
@@ -219,45 +205,69 @@ export class ClassAnalyzer {
|
|
|
219
205
|
return undefined;
|
|
220
206
|
}
|
|
221
207
|
const args = decorator.getArguments();
|
|
222
|
-
let generateSendable: boolean | undefined;
|
|
223
|
-
let _with: string | undefined;
|
|
224
|
-
let deserializationMode: DeserializationMode | undefined;
|
|
225
|
-
|
|
226
208
|
const firstArg = args[0];
|
|
227
209
|
|
|
228
|
-
if (!firstArg) {
|
|
210
|
+
if (!firstArg || firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) {
|
|
229
211
|
return {};
|
|
230
212
|
}
|
|
231
213
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
generateSendable = true;
|
|
244
|
-
} else if (initializer.getKind() === SyntaxKind.FalseKeyword) {
|
|
245
|
-
generateSendable = false;
|
|
246
|
-
}
|
|
247
|
-
} else if (propertyName === 'with' && initializer) {
|
|
248
|
-
// 处理 with 参数,存储完整的表达式文本
|
|
249
|
-
_with = initializer.getText();
|
|
250
|
-
} else if (propertyName === 'deserializationMode' && initializer) {
|
|
251
|
-
// 处理 deserializationMode 参数:'performance' | 'strict'
|
|
252
|
-
const modeText = initializer.getText().replace(/['"]/g, ''); // 去掉引号
|
|
253
|
-
if (modeText === DeserializationMode.PERFORMANCE || modeText === DeserializationMode.STRICT) {
|
|
254
|
-
deserializationMode = modeText as DeserializationMode;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
214
|
+
return this.extractOptionsFromObjectLiteral(firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private static extractOptionsFromObjectLiteral(objectLiteral: ObjectLiteralExpression): SerializableOptions {
|
|
218
|
+
const options: SerializableOptions = {};
|
|
219
|
+
const properties = objectLiteral.getProperties();
|
|
220
|
+
|
|
221
|
+
for (const prop of properties) {
|
|
222
|
+
// early return: 非属性赋值节点
|
|
223
|
+
if (prop.getKind() !== SyntaxKind.PropertyAssignment) {
|
|
224
|
+
continue;
|
|
258
225
|
}
|
|
226
|
+
const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
|
|
227
|
+
const initializer = propAssignment.getInitializer();
|
|
228
|
+
// early return: 无初始化器
|
|
229
|
+
if (!initializer) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.extractSingleOption(options, propAssignment.getName(), initializer);
|
|
234
|
+
}
|
|
235
|
+
return options;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private static extractSingleOption(
|
|
239
|
+
options: SerializableOptions,
|
|
240
|
+
propertyName: string,
|
|
241
|
+
initializer: ReturnType<typeof Object.prototype.valueOf>
|
|
242
|
+
): void {
|
|
243
|
+
if (propertyName === 'generateSendable') {
|
|
244
|
+
options.generateSendable = this.parseBooleanInitializer(initializer);
|
|
245
|
+
} else if (propertyName === 'with') {
|
|
246
|
+
options.with = (initializer as { getText(): string }).getText();
|
|
247
|
+
} else if (propertyName === 'deserializationMode') {
|
|
248
|
+
this.parseDeserializationMode(options, initializer);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private static parseBooleanInitializer(initializer: ReturnType<typeof Object.prototype.valueOf>): boolean | undefined {
|
|
253
|
+
const kind = (initializer as { getKind(): SyntaxKind }).getKind();
|
|
254
|
+
if (kind === SyntaxKind.TrueKeyword) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
if (kind === SyntaxKind.FalseKeyword) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private static parseDeserializationMode(
|
|
264
|
+
options: SerializableOptions,
|
|
265
|
+
initializer: ReturnType<typeof Object.prototype.valueOf>
|
|
266
|
+
): void {
|
|
267
|
+
const modeText = (initializer as { getText(): string }).getText().replace(/['"]/g, '');
|
|
268
|
+
if (modeText === DeserializationMode.PERFORMANCE || modeText === DeserializationMode.STRICT) {
|
|
269
|
+
options.deserializationMode = modeText as DeserializationMode;
|
|
259
270
|
}
|
|
260
|
-
return { with: _with, generateSendable, deserializationMode };
|
|
261
271
|
}
|
|
262
272
|
|
|
263
273
|
/**
|
|
@@ -266,36 +276,53 @@ export class ClassAnalyzer {
|
|
|
266
276
|
* @returns 序列化名称
|
|
267
277
|
*/
|
|
268
278
|
private static parseSerialNameOptions(decorator?: Decorator): string | undefined {
|
|
279
|
+
// early return: 无装饰器
|
|
269
280
|
if (!decorator) {
|
|
270
281
|
return undefined;
|
|
271
282
|
}
|
|
272
283
|
const args = decorator.getArguments();
|
|
284
|
+
// early return: 无参数
|
|
273
285
|
if (args.length === 0) {
|
|
274
286
|
return undefined;
|
|
275
287
|
}
|
|
276
288
|
|
|
277
289
|
const firstArg = args[0];
|
|
278
290
|
|
|
291
|
+
// early return: 非对象字面量
|
|
292
|
+
if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) {
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
279
296
|
// 处理对象形式:@SerialName({ name: 'xxx' })
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
297
|
+
const properties = firstArg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression).getProperties();
|
|
298
|
+
return this.extractNameFromProperties(properties);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* 从属性列表中提取name属性的值
|
|
303
|
+
* @param properties 属性列表
|
|
304
|
+
* @returns name属性的字符串值
|
|
305
|
+
*/
|
|
306
|
+
private static extractNameFromProperties(properties: ReturnType<ObjectLiteralExpression['getProperties']>): string | undefined {
|
|
307
|
+
for (const prop of properties) {
|
|
308
|
+
// early return: 非属性赋值节点
|
|
309
|
+
if (prop.getKind() !== SyntaxKind.PropertyAssignment) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
|
|
313
|
+
// early return: 非name属性
|
|
314
|
+
if (propAssignment.getName() !== 'name') {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const initializer = propAssignment.getInitializer();
|
|
319
|
+
// early return: 非字符串字面量
|
|
320
|
+
if (!initializer || initializer.getKind() !== SyntaxKind.StringLiteral) {
|
|
321
|
+
continue;
|
|
296
322
|
}
|
|
297
|
-
}
|
|
298
323
|
|
|
324
|
+
return initializer.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
|
|
325
|
+
}
|
|
299
326
|
return undefined;
|
|
300
327
|
}
|
|
301
328
|
|
|
@@ -320,40 +347,49 @@ export class ClassAnalyzer {
|
|
|
320
347
|
genericParameters
|
|
321
348
|
);
|
|
322
349
|
|
|
323
|
-
|
|
324
|
-
if (propertyAnalysis.type.kind === PropertyKind.UNKNOWN) {
|
|
325
|
-
const hasTransient = propertyAnalysis.decorators?.isTransient;
|
|
326
|
-
const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
|
|
327
|
-
|
|
328
|
-
if (!hasTransient && !hasCustomSerializer) {
|
|
329
|
-
if (prop instanceof PropertyDeclaration) {
|
|
330
|
-
// 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
|
|
331
|
-
throw new CustomError(
|
|
332
|
-
`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
|
|
333
|
-
}' (类: ${cls.getName()})。\n` +
|
|
334
|
-
`请选择以下任一解决方案:\n` +
|
|
335
|
-
` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
|
|
336
|
-
` @Transient()\n` +
|
|
337
|
-
` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
|
|
338
|
-
` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
|
|
339
|
-
` @Serializable({with: DateSerializer.INSTANCE})\n` +
|
|
340
|
-
` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`,
|
|
341
|
-
ErrorCodes.TYPE_NOT_SUPPORT
|
|
342
|
-
);
|
|
343
|
-
} else {
|
|
344
|
-
// 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
|
|
345
|
-
throw new CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
|
|
346
|
-
}' (接口: ${cls.getName()})`, ErrorCodes.TYPE_NOT_SUPPORT);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// 保留所有属性(包括 UNKNOWN 类型),生成阶段再筛选
|
|
350
|
+
this.checkUnknownType(cls, prop, propertyAnalysis);
|
|
352
351
|
ownProperties.push(propertyAnalysis);
|
|
353
352
|
}
|
|
354
353
|
return ownProperties;
|
|
355
354
|
}
|
|
356
355
|
|
|
356
|
+
private static checkUnknownType(
|
|
357
|
+
cls: ClassDeclaration | InterfaceDeclaration,
|
|
358
|
+
prop: PropertyDeclaration | PropertySignature,
|
|
359
|
+
propertyAnalysis: PropertyAnalysis
|
|
360
|
+
): void {
|
|
361
|
+
if (propertyAnalysis.type.kind !== PropertyKind.UNKNOWN) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const hasTransient = propertyAnalysis.decorators?.isTransient;
|
|
366
|
+
const hasCustomSerializer = !!propertyAnalysis.decorators?.with;
|
|
367
|
+
|
|
368
|
+
if (hasTransient || hasCustomSerializer) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (prop instanceof PropertyDeclaration) {
|
|
373
|
+
// 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
|
|
374
|
+
throw new CustomError(
|
|
375
|
+
`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
|
|
376
|
+
}' (类: ${cls.getName()})。\n` +
|
|
377
|
+
`请选择以下任一解决方案:\n` +
|
|
378
|
+
` 1. 添加 @Transient() 跳过序列化(属性仍会参与 Sendable 转换和对象拷贝):\n` +
|
|
379
|
+
` @Transient()\n` +
|
|
380
|
+
` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};\n\n` +
|
|
381
|
+
` 2. 添加 @Serializable({with: CustomSerializer}) 指定自定义序列化器:\n` +
|
|
382
|
+
` @Serializable({with: DateSerializer.INSTANCE})\n` +
|
|
383
|
+
` ${propertyAnalysis.name}: ${propertyAnalysis.type.sourceText};`,
|
|
384
|
+
ErrorCodes.TYPE_NOT_SUPPORT
|
|
385
|
+
);
|
|
386
|
+
} else {
|
|
387
|
+
// 未知类型且没有 @Transient 或自定义序列化器,抛出清晰错误
|
|
388
|
+
throw new CustomError(`不支持的类型 '${propertyAnalysis.type.sourceText}' 用于属性 '${propertyAnalysis.name
|
|
389
|
+
}' (接口: ${cls.getName()})`, ErrorCodes.TYPE_NOT_SUPPORT);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
357
393
|
/**
|
|
358
394
|
* 对属性进行分类,区分继承属性、重写属性和自有属性
|
|
359
395
|
* @param ownProperties 自有属性数组
|
|
@@ -370,8 +406,8 @@ export class ClassAnalyzer {
|
|
|
370
406
|
overriddenProperties: PropertyAnalysis[];
|
|
371
407
|
properties: PropertyAnalysis[];
|
|
372
408
|
} {
|
|
409
|
+
// early return: 没有继承,所有属性都是自有属性
|
|
373
410
|
if (!inheritance.isInherited || !inheritance.baseClassAnalysis) {
|
|
374
|
-
// 没有继承,所有属性都是自有属性
|
|
375
411
|
return {
|
|
376
412
|
inheritedProperties: [],
|
|
377
413
|
overriddenProperties: [],
|
|
@@ -382,22 +418,34 @@ export class ClassAnalyzer {
|
|
|
382
418
|
// 递归收集所有祖先属性 - 传递泛型参数进行替换
|
|
383
419
|
const allAncestorProperties = this.collectAllAncestorProperties(
|
|
384
420
|
inheritance.baseClassAnalysis,
|
|
385
|
-
inheritance.genericTypeArguments || [],
|
|
386
|
-
currentClassGenericParams
|
|
421
|
+
inheritance.genericTypeArguments || [],
|
|
422
|
+
currentClassGenericParams
|
|
387
423
|
);
|
|
388
424
|
|
|
425
|
+
return this.buildPropertyClassification(ownProperties, allAncestorProperties);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* 根据自有属性和祖先属性构建属性分类结果
|
|
430
|
+
* @param ownProperties 自有属性数组
|
|
431
|
+
* @param allAncestorProperties 所有祖先属性数组
|
|
432
|
+
* @returns 分类后的属性对象
|
|
433
|
+
*/
|
|
434
|
+
private static buildPropertyClassification(
|
|
435
|
+
ownProperties: PropertyAnalysis[],
|
|
436
|
+
allAncestorProperties: PropertyAnalysis[]
|
|
437
|
+
): {
|
|
438
|
+
inheritedProperties: PropertyAnalysis[];
|
|
439
|
+
overriddenProperties: PropertyAnalysis[];
|
|
440
|
+
properties: PropertyAnalysis[];
|
|
441
|
+
} {
|
|
389
442
|
// 构建自有属性名称集合,用于快速查找重写
|
|
390
443
|
const ownPropertyNames = new Set(ownProperties.map((prop) => prop.name));
|
|
391
444
|
|
|
392
|
-
//
|
|
393
|
-
const inheritedProperties
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (!ownPropertyNames.has(ancestorProp.name)) {
|
|
397
|
-
// 被当前类继承了
|
|
398
|
-
inheritedProperties.push(ancestorProp);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
445
|
+
// 分类祖先属性:过滤出被继承的(未被重写的)
|
|
446
|
+
const inheritedProperties = allAncestorProperties.filter(
|
|
447
|
+
(ancestorProp) => !ownPropertyNames.has(ancestorProp.name)
|
|
448
|
+
);
|
|
401
449
|
|
|
402
450
|
// 确定当前类中的重写属性
|
|
403
451
|
const overriddenProperties = ownProperties.filter((prop) =>
|
|
@@ -407,11 +455,7 @@ export class ClassAnalyzer {
|
|
|
407
455
|
// 合并最终属性:继承的 + 当前类的(重写优先)
|
|
408
456
|
const properties = [...inheritedProperties, ...ownProperties];
|
|
409
457
|
|
|
410
|
-
return {
|
|
411
|
-
inheritedProperties,
|
|
412
|
-
overriddenProperties,
|
|
413
|
-
properties
|
|
414
|
-
};
|
|
458
|
+
return { inheritedProperties, overriddenProperties, properties };
|
|
415
459
|
}
|
|
416
460
|
|
|
417
461
|
/**
|
|
@@ -436,22 +480,82 @@ export class ClassAnalyzer {
|
|
|
436
480
|
const substitutedProperties = classAnalysis.ownProperties.map((property) =>
|
|
437
481
|
GenericTypeSubstitutionUtil.substitutePropertyType(property, genericMapping, currentClassGenericParams)
|
|
438
482
|
);
|
|
439
|
-
|
|
440
483
|
allProperties.push(...substitutedProperties);
|
|
441
484
|
|
|
442
|
-
// 3.
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
classAnalysis.inheritance.genericTypeArguments || [], // 传递当前层的泛型参数
|
|
447
|
-
currentClassGenericParams // 保持传递当前类的泛型参数
|
|
448
|
-
);
|
|
449
|
-
allProperties.push(...ancestorProperties);
|
|
450
|
-
}
|
|
485
|
+
// 3. 递归处理更上层祖先
|
|
486
|
+
this.collectAncestorPropertiesRecursively(
|
|
487
|
+
classAnalysis, parentGenericParams, genericMapping, currentClassGenericParams, allProperties
|
|
488
|
+
);
|
|
451
489
|
|
|
452
490
|
return allProperties;
|
|
453
491
|
}
|
|
454
492
|
|
|
493
|
+
/**
|
|
494
|
+
* 递归收集更上层祖先的属性
|
|
495
|
+
* @param classAnalysis 当前类分析结果
|
|
496
|
+
* @param parentGenericParams 父类泛型参数
|
|
497
|
+
* @param genericMapping 泛型映射
|
|
498
|
+
* @param currentClassGenericParams 当前类泛型参数列表
|
|
499
|
+
* @param allProperties 属性收集数组
|
|
500
|
+
*/
|
|
501
|
+
private static collectAncestorPropertiesRecursively(
|
|
502
|
+
classAnalysis: ClassAnalysis | InterfaceAnalysis,
|
|
503
|
+
parentGenericParams: string[],
|
|
504
|
+
genericMapping: Map<string, TypeNode>,
|
|
505
|
+
currentClassGenericParams: string[],
|
|
506
|
+
allProperties: PropertyAnalysis[]
|
|
507
|
+
): void {
|
|
508
|
+
// early return: 没有继承关系
|
|
509
|
+
if (!classAnalysis.inheritance.isInherited || !classAnalysis.inheritance.baseClassAnalysis) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// 解析父类的泛型参数,将泛型引用替换为具体类型
|
|
514
|
+
const parentGenericTypeArgs = classAnalysis.inheritance.genericTypeArguments || [];
|
|
515
|
+
const resolvedParentGenericArgs = this.resolveGenericTypeArgs(
|
|
516
|
+
parentGenericTypeArgs, parentGenericParams, genericMapping
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
Logger.debug(
|
|
520
|
+
`[CollectAncestors] Resolved parent generic args: ${resolvedParentGenericArgs.map(a => a.getText()).join(', ')}`);
|
|
521
|
+
|
|
522
|
+
const ancestorProperties = this.collectAllAncestorProperties(
|
|
523
|
+
classAnalysis.inheritance.baseClassAnalysis,
|
|
524
|
+
resolvedParentGenericArgs,
|
|
525
|
+
currentClassGenericParams
|
|
526
|
+
);
|
|
527
|
+
allProperties.push(...ancestorProperties);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* 解析泛型类型参数,将泛型引用替换为具体类型
|
|
532
|
+
* @param typeArgs 类型参数数组
|
|
533
|
+
* @param parentGenericParams 父类泛型参数
|
|
534
|
+
* @param genericMapping 泛型映射
|
|
535
|
+
* @returns 解析后的类型参数数组
|
|
536
|
+
*/
|
|
537
|
+
private static resolveGenericTypeArgs(
|
|
538
|
+
typeArgs: TypeNode[],
|
|
539
|
+
parentGenericParams: string[],
|
|
540
|
+
genericMapping: Map<string, TypeNode>
|
|
541
|
+
): TypeNode[] {
|
|
542
|
+
return typeArgs.map(typeArg => {
|
|
543
|
+
// 解析类型参数为 TypeStructure
|
|
544
|
+
const typeStructure = TypeHandlerRegistry.getInstance().parseType(typeArg, {
|
|
545
|
+
depth: 0,
|
|
546
|
+
genericParams: parentGenericParams
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// 如果是泛型引用,进行替换
|
|
550
|
+
if (typeStructure.kind === PropertyKind.GENERIC && genericMapping.has(typeStructure.sourceText)) {
|
|
551
|
+
return genericMapping.get(typeStructure.sourceText)!;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// 否则保持原样
|
|
555
|
+
return typeArg;
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
455
559
|
/**
|
|
456
560
|
* 提取构造函数参数信息
|
|
457
561
|
* @param constructor 构造函数声明
|
|
@@ -485,45 +589,75 @@ export class ClassAnalyzer {
|
|
|
485
589
|
genericParameters: string[]
|
|
486
590
|
): PropertyAnalysis {
|
|
487
591
|
const name = prop.getName();
|
|
592
|
+
const typeNode = this.getTypeNode(prop);
|
|
593
|
+
const type = TypeHandlerRegistry.getInstance().parseType(typeNode, { genericParams: genericParameters, depth: 0 });
|
|
594
|
+
type.isOptional = prop.hasQuestionToken();
|
|
595
|
+
|
|
596
|
+
const defaultValue = prop instanceof PropertyDeclaration ?
|
|
597
|
+
this.analyzeDefaultValue(prop, constructorParams) : undefined;
|
|
598
|
+
const decorators = prop instanceof PropertyDeclaration ? this.analyzePropertyDecorators(prop) : undefined;
|
|
599
|
+
const visibility = this.getPropertyVisibility(prop);
|
|
600
|
+
|
|
601
|
+
const constructorParam = constructorParams.find((param) => param.name === name);
|
|
602
|
+
const isMust = this.calculateIsMust(prop, type, constructorParam, decorators, defaultValue);
|
|
603
|
+
|
|
604
|
+
if (decorators?.isTransient && constructorParam) {
|
|
605
|
+
this.validateTransientConstructorParam(name, constructorParam);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return {
|
|
609
|
+
name,
|
|
610
|
+
defaultValue,
|
|
611
|
+
decorators,
|
|
612
|
+
type,
|
|
613
|
+
isMust,
|
|
614
|
+
visibility
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
private static getTypeNode(prop: PropertyDeclaration | PropertySignature): TypeNode {
|
|
488
619
|
let typeNode = prop.getTypeNode();
|
|
489
620
|
if (!typeNode) {
|
|
490
621
|
typeNode = this.analyzePropertyType(prop);
|
|
491
622
|
}
|
|
492
|
-
|
|
493
623
|
if (!typeNode) {
|
|
494
|
-
throw new CustomError(`无法分析属性 '${
|
|
624
|
+
throw new CustomError(`无法分析属性 '${prop.getName()}' 的类型。请检查属性声明。`, ErrorCodes.TYPE_NOT_SUPPORT);
|
|
495
625
|
}
|
|
626
|
+
return typeNode;
|
|
627
|
+
}
|
|
496
628
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
? constructorParam.isOptional ||
|
|
507
|
-
constructorParam.defaultValue !== undefined ||
|
|
508
|
-
this.hasUndefinedInUnion(constructorParam.type)
|
|
509
|
-
: true;
|
|
629
|
+
private static getPropertyVisibility(prop: PropertyDeclaration | PropertySignature): PropertyVisibility {
|
|
630
|
+
if (prop.hasModifier(SyntaxKind.PrivateKeyword)) {
|
|
631
|
+
return PropertyVisibility.PRIVATE;
|
|
632
|
+
}
|
|
633
|
+
if (prop.hasModifier(SyntaxKind.ProtectedKeyword)) {
|
|
634
|
+
return PropertyVisibility.PROTECTED;
|
|
635
|
+
}
|
|
636
|
+
return PropertyVisibility.PUBLIC;
|
|
637
|
+
}
|
|
510
638
|
|
|
511
|
-
|
|
639
|
+
private static calculateIsMust(
|
|
640
|
+
prop: PropertyDeclaration | PropertySignature,
|
|
641
|
+
type: TypeStructure,
|
|
642
|
+
constructorParam: ConstructorParam | undefined,
|
|
643
|
+
decorators: PropertyDecorators | undefined,
|
|
644
|
+
defaultValue: string | undefined
|
|
645
|
+
): boolean {
|
|
512
646
|
if (constructorParam) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
// 3. 类型字符串中包含undefined作为联合类型成员
|
|
518
|
-
isMust = !isParamOptional;
|
|
519
|
-
} else {
|
|
520
|
-
// 属性不在构造函数中,判断属性本身的必要性
|
|
521
|
-
isMust = decorators?.isRequired || !this.isOptional(prop, defaultValue, type);
|
|
647
|
+
const isParamOptional = constructorParam.isOptional ||
|
|
648
|
+
constructorParam.defaultValue !== undefined ||
|
|
649
|
+
this.hasUndefinedInUnion(constructorParam.type);
|
|
650
|
+
return !isParamOptional;
|
|
522
651
|
}
|
|
652
|
+
return decorators?.isRequired || !this.isOptional(prop, defaultValue, type);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
private static validateTransientConstructorParam(name: string, constructorParam: ConstructorParam): void {
|
|
656
|
+
const isParamOptional = constructorParam.isOptional ||
|
|
657
|
+
constructorParam.defaultValue !== undefined ||
|
|
658
|
+
this.hasUndefinedInUnion(constructorParam.type);
|
|
523
659
|
|
|
524
|
-
|
|
525
|
-
// 检查构造函数参数是否可选或有默认值
|
|
526
|
-
if (decorators?.isTransient && constructorParam && !isParamOptional) {
|
|
660
|
+
if (!isParamOptional) {
|
|
527
661
|
throw new CustomError(
|
|
528
662
|
`@Transient 属性 '${name}' 的构造函数参数必须是可选的或有默认值。\n` +
|
|
529
663
|
`因为 @Transient 属性不参与序列化,反序列化时无法从外部数据获取值。\n` +
|
|
@@ -533,14 +667,6 @@ export class ClassAnalyzer {
|
|
|
533
667
|
ErrorCodes.TRANSIENT_ATTR_OPTIONAL
|
|
534
668
|
);
|
|
535
669
|
}
|
|
536
|
-
|
|
537
|
-
return {
|
|
538
|
-
name,
|
|
539
|
-
defaultValue,
|
|
540
|
-
decorators,
|
|
541
|
-
type,
|
|
542
|
-
isMust
|
|
543
|
-
};
|
|
544
670
|
}
|
|
545
671
|
|
|
546
672
|
private static analyzePropertyType(prop: PropertyDeclaration | PropertySignature): TypeNode | undefined {
|
|
@@ -598,7 +724,8 @@ export class ClassAnalyzer {
|
|
|
598
724
|
return typeText;
|
|
599
725
|
}
|
|
600
726
|
|
|
601
|
-
private static getTypeFromInitializer(prop: PropertyDeclaration | PropertySignature,
|
|
727
|
+
private static getTypeFromInitializer(prop: PropertyDeclaration | PropertySignature,
|
|
728
|
+
propName: string): TypeNode | undefined {
|
|
602
729
|
const initializer = prop.getInitializer();
|
|
603
730
|
if (!initializer) {
|
|
604
731
|
return undefined;
|
|
@@ -626,7 +753,8 @@ export class ClassAnalyzer {
|
|
|
626
753
|
}
|
|
627
754
|
|
|
628
755
|
const exprText = expression.getText();
|
|
629
|
-
const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet',
|
|
756
|
+
const supportedTypes = ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array', 'Object', 'ArrayList', 'HashMap', 'HashSet',
|
|
757
|
+
'LinkedList', 'Decimal', 'List'];
|
|
630
758
|
|
|
631
759
|
if (!supportedTypes.includes(exprText)) {
|
|
632
760
|
return undefined;
|
|
@@ -651,7 +779,8 @@ export class ClassAnalyzer {
|
|
|
651
779
|
* @param type 类型结构
|
|
652
780
|
* @returns 是否为可选属性
|
|
653
781
|
*/
|
|
654
|
-
private static isOptional(node: PropertyDeclaration | PropertySignature, defaultValue: string | undefined,
|
|
782
|
+
private static isOptional(node: PropertyDeclaration | PropertySignature, defaultValue: string | undefined,
|
|
783
|
+
type: TypeStructure): boolean {
|
|
655
784
|
// 1. 语法上带 ?(prop?: T, param?: T)
|
|
656
785
|
if (node.hasQuestionToken()) {
|
|
657
786
|
return true;
|
|
@@ -768,14 +897,14 @@ export class ClassAnalyzer {
|
|
|
768
897
|
*/
|
|
769
898
|
private static analyzePropertyDecorators(prop: PropertyDeclaration): PropertyDecorators {
|
|
770
899
|
const decorators = prop.getDecorators();
|
|
771
|
-
let isRequired
|
|
772
|
-
let isTransient
|
|
900
|
+
let isRequired = false;
|
|
901
|
+
let isTransient = false;
|
|
902
|
+
let isPlainValue = false;
|
|
773
903
|
let serialName: string | undefined;
|
|
774
904
|
let _with: string | undefined;
|
|
775
905
|
|
|
776
906
|
decorators.forEach((decorator) => {
|
|
777
907
|
const name = decorator.getName();
|
|
778
|
-
|
|
779
908
|
switch (name) {
|
|
780
909
|
case DecoratorConstants.SERIAL_NAME:
|
|
781
910
|
serialName = this.parseSerialNameOptions(decorator);
|
|
@@ -786,39 +915,71 @@ export class ClassAnalyzer {
|
|
|
786
915
|
case DecoratorConstants.TRANSIENT:
|
|
787
916
|
isTransient = true;
|
|
788
917
|
break;
|
|
918
|
+
case DecoratorConstants.PLAIN_VALUE:
|
|
919
|
+
isPlainValue = true;
|
|
920
|
+
break;
|
|
789
921
|
case DecoratorConstants.SERIALIZABLE:
|
|
790
922
|
_with = this.parseSerializableOptions(decorator)!.with;
|
|
923
|
+
break;
|
|
791
924
|
}
|
|
792
925
|
});
|
|
793
926
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const conflictingDecorators: string[] = [];
|
|
797
|
-
if (isRequired) {
|
|
798
|
-
conflictingDecorators.push('@Required');
|
|
799
|
-
}
|
|
800
|
-
if (serialName) {
|
|
801
|
-
conflictingDecorators.push('@SerialName');
|
|
802
|
-
}
|
|
803
|
-
if (_with) {
|
|
804
|
-
conflictingDecorators.push('@Serializable');
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
if (conflictingDecorators.length > 0) {
|
|
808
|
-
throw new CustomError(
|
|
809
|
-
`属性 '${prop.getName()}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
|
|
810
|
-
`@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
|
|
811
|
-
`请移除 @Transient 或移除其他序列化注解。`,
|
|
812
|
-
ErrorCodes.ANNOTATION_CONFLICT
|
|
813
|
-
);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
927
|
+
this.checkTransientConflicts(prop.getName(), isTransient, isRequired, !!serialName, !!_with, isPlainValue);
|
|
928
|
+
this.checkPlainValueConflicts(prop.getName(), isPlainValue, !!_with);
|
|
816
929
|
|
|
817
930
|
return {
|
|
818
931
|
isRequired,
|
|
819
932
|
isTransient,
|
|
933
|
+
isPlainValue,
|
|
820
934
|
serialName,
|
|
821
935
|
with: _with
|
|
822
936
|
};
|
|
823
937
|
}
|
|
938
|
+
|
|
939
|
+
private static checkTransientConflicts(
|
|
940
|
+
propName: string,
|
|
941
|
+
isTransient: boolean,
|
|
942
|
+
isRequired: boolean,
|
|
943
|
+
hasSerialName: boolean,
|
|
944
|
+
hasWith: boolean,
|
|
945
|
+
isPlainValue: boolean
|
|
946
|
+
): void {
|
|
947
|
+
if (!isTransient) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
const conflictingDecorators: string[] = [];
|
|
952
|
+
if (isRequired) {
|
|
953
|
+
conflictingDecorators.push('@Required');
|
|
954
|
+
}
|
|
955
|
+
if (hasSerialName) {
|
|
956
|
+
conflictingDecorators.push('@SerialName');
|
|
957
|
+
}
|
|
958
|
+
if (hasWith) {
|
|
959
|
+
conflictingDecorators.push('@Serializable');
|
|
960
|
+
}
|
|
961
|
+
if (isPlainValue) {
|
|
962
|
+
conflictingDecorators.push('@PlainValue');
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
if (conflictingDecorators.length > 0) {
|
|
966
|
+
throw new CustomError(
|
|
967
|
+
`属性 '${propName}' 的注解冲突:@Transient 与 ${conflictingDecorators.join(', ')} 不能同时使用。\n` +
|
|
968
|
+
`@Transient 表示跳过序列化,与其他序列化配置注解互斥。\n` +
|
|
969
|
+
`请移除 @Transient 或移除其他序列化注解。`,
|
|
970
|
+
ErrorCodes.ANNOTATION_CONFLICT
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
private static checkPlainValueConflicts(propName: string, isPlainValue: boolean, hasWith: boolean): void {
|
|
976
|
+
if (isPlainValue && hasWith) {
|
|
977
|
+
throw new CustomError(
|
|
978
|
+
`属性 '${propName}' 的注解冲突:@PlainValue 与 @Serializable(with:) 不能同时使用。\n` +
|
|
979
|
+
`@PlainValue 跳过类型转换直接使用原始值,与自定义序列化器冲突。\n` +
|
|
980
|
+
`请移除 @PlainValue 或移除自定义序列化器。`,
|
|
981
|
+
ErrorCodes.ANNOTATION_CONFLICT
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
824
985
|
}
|