You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何禁止Kotlin类标注@Serializable并触发编译/运行时告警?

Kotlin类A禁止添加@Serializable注解的实现方案

以下是几种能在编译期或运行时阻止类A被标注@Serializable的可行方案:

方案一:编译期通过KSP强制检查(推荐)

KSP是Kotlin官方的符号处理工具,能在编译阶段扫描代码,发现违规直接抛出错误,从根源阻止问题代码生成。

实现步骤:

  1. 配置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")
    }
    
  2. 编写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()
        }
    }
    
  3. 注册处理器:在项目的resources/META-INF/services/目录下创建文件com.google.devtools.ksp.processing.SymbolProcessorProvider,内容为处理器类的全限定名(如com.example.ForbidSerializableProcessorProvider)。

配置完成后,只要开发者给类A添加@Serializable,编译时就会直接报错,中断编译流程。

方案二:编译期通过自定义Lint规则检查(Android项目适用)

Android项目可通过自定义Lint规则,扫描代码中的注解违规,可配置为警告或错误。

实现步骤:

  1. 创建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"
    }
    
  2. 编写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)
            )
        }
    }
    
  3. 注册规则:在模块的resources/META-INF/services/目录下创建文件com.android.tools.lint.client.api.IssueRegistry,内容为自定义的IssueRegistry类(需返回上述ISSUE)。
  4. 主项目依赖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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 08:31:02