如何禁止Kotlin类标注@Serializable并触发编译/运行时告警?
Kotlin类A禁止添加@Serializable注解的实现方案
以下是几种能在编译期或运行时阻止类A被标注@Serializable的可行方案:
方案一:编译期通过KSP强制检查(推荐)
KSP是Kotlin官方的符号处理工具,能在编译阶段扫描代码,发现违规直接抛出错误,从根源阻止问题代码生成。
实现步骤:
- 配置KSP依赖:在项目根模块或应用模块的
build.gradle.kts中添加插件和依赖(版本需与项目Kotlin版本匹配):plugins { id("com.google.devtools.ksp") version "1.9.20-1.0.14" } dependencies { ksp("com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14") } - 编写KSP处理器:
创建处理器类扫描所有带@Serializable的类,若类名为A则抛出编译错误:class ForbidSerializableProcessorProvider : SymbolProcessorProvider { override fun create(env: SymbolProcessorEnvironment): SymbolProcessor { return ForbidSerializableProcessor(env) } } class ForbidSerializableProcessor(private val env: SymbolProcessorEnvironment) : SymbolProcessor { override fun process(resolver: Resolver): List<KSAnnotated> { val serializableClasses = resolver.getSymbolsWithAnnotation("kotlinx.serialization.Serializable") .filterIsInstance<KSClassDeclaration>() serializableClasses.forEach { cls -> if (cls.simpleName.asString() == "A") { env.logger.error("类A禁止添加@Serializable注解", cls) } } return emptyList() } } - 注册处理器:在项目的
resources/META-INF/services/目录下创建文件com.google.devtools.ksp.processing.SymbolProcessorProvider,内容为处理器类的全限定名(如com.example.ForbidSerializableProcessorProvider)。
配置完成后,只要开发者给类A添加@Serializable,编译时就会直接报错,中断编译流程。
方案二:编译期通过自定义Lint规则检查(Android项目适用)
Android项目可通过自定义Lint规则,扫描代码中的注解违规,可配置为警告或错误。
实现步骤:
- 创建Lint规则模块:新建一个Java/Kotlin模块,在
build.gradle中添加Lint依赖:dependencies { compileOnly "com.android.tools.lint:lint-api:30.1.0" compileOnly "com.android.tools.lint:lint-checks:30.1.0" } - 编写Lint检查类:
class ForbidSerializableForA : Detector(), SourceCodeScanner { override fun getApplicableAnnotations(): List<String> { return listOf("kotlinx.serialization.Serializable") } override fun visitAnnotation(context: JavaContext, annotation: UAnnotation, klass: UClass) { if (klass.name == "A") { context.report( issue = ISSUE, scope = klass, location = context.getNameLocation(klass), message = "类A禁止添加@Serializable注解" ) } } companion object { val ISSUE = Issue.create( id = "ForbidSerializableOnClassA", briefDescription = "类A禁止使用@Serializable", explanation = "项目要求类A绝对不能被标注@Serializable注解", category = Category.CORRECTNESS, priority = 10, severity = Severity.ERROR, // 设为ERROR阻止编译,WARNING仅提示 implementation = Implementation(ForbidSerializableForA::class.java, Scope.JAVA_FILE_SCOPE) ) } } - 注册规则:在模块的
resources/META-INF/services/目录下创建文件com.android.tools.lint.client.api.IssueRegistry,内容为自定义的IssueRegistry类(需返回上述ISSUE)。 - 主项目依赖Lint模块:在应用模块的
build.gradle中添加Lint模块依赖,编译时即可触发检查。
方案三:运行时反射检查(兜底方案)
若无法使用编译期检查,可在应用启动时通过反射扫描类A,发现注解则抛出异常:
private fun checkClassAAnnotation() { val clazz = A::class.java val hasSerializable = clazz.isAnnotationPresent(kotlinx.serialization.Serializable::class.java) if (hasSerializable) { throw IllegalArgumentException("类A禁止添加@Serializable注解") } } // 在应用初始化时调用,比如Application的onCreate class MyApplication : Application() { override fun onCreate() { super.onCreate() checkClassAAnnotation() } }
该方案仅能在运行时发现问题,无法提前拦截编译,仅作为编译期方案的补充。
内容的提问来源于stack exchange,提问作者T D Nguyen
相关产品推荐
相关产品推荐

