4-1-3 Kotlin注解-案例详解

34 阅读7分钟

Kotlin注解案例详解

我将通过多个实际案例深入讲解Kotlin注解的用法,包括自定义注解、注解处理器(KAPT/KSP)、运行时注解处理等。

案例1:自定义注解与运行时处理

1.1 数据验证注解

// ================ 验证注解定义 ================

/**
 * 验证注解的元注解
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class Validate

/**
 * 非空验证
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class NotEmpty(
    val message: String = "字段不能为空"
)

/**
 * 长度验证
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class Length(
    val min: Int = 0,
    val max: Int = Int.MAX_VALUE,
    val message: String = "长度不符合要求"
)

/**
 * 正则验证
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class Pattern(
    val regex: String,
    val message: String = "格式不正确"
)

/**
 * 范围验证
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class Range(
    val min: Long = Long.MIN_VALUE,
    val max: Long = Long.MAX_VALUE,
    val message: String = "值超出范围"
)

/**
 * 邮箱验证
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class Email(
    val message: String = "邮箱格式不正确"
)

// ================ 验证器类 ================

/**
 * 验证结果
 */
data class ValidationResult(
    val isValid: Boolean,
    val errors: Map<String, List<String>>
)

/**
 * 验证异常
 */
class ValidationException(val validationResult: ValidationResult) : 
    IllegalArgumentException("数据验证失败: ${validationResult.errors}")

/**
 * 验证器
 */
object Validator {
    
    fun validate(obj: Any): ValidationResult {
        val errors = mutableMapOf<String, MutableList<String>>()
        
        obj.javaClass.declaredFields.forEach { field ->
            // 跳过非验证字段
            if (!field.isAnnotationPresent(Validate::class.java)) {
                return@forEach
            }
            
            field.isAccessible = true
            val value = field.get(obj)
            val fieldName = field.name
            
            // 验证NotEmpty
            field.getAnnotation(NotEmpty::class.java)?.let { annotation ->
                if (value == null || (value is String && value.isBlank())) {
                    errors.getOrPut(fieldName) { mutableListOf() }
                        .add(annotation.message)
                }
            }
            
            // 验证Length
            field.getAnnotation(Length::class.java)?.let { annotation ->
                when (value) {
                    is String -> {
                        if (value.length < annotation.min || value.length > annotation.max) {
                            errors.getOrPut(fieldName) { mutableListOf() }
                                .add("${annotation.message} (当前长度: ${value.length}, 要求: ${annotation.min}-${annotation.max})")
                        }
                    }
                    is Collection<*> -> {
                        if (value.size < annotation.min || value.size > annotation.max) {
                            errors.getOrPut(fieldName) { mutableListOf() }
                                .add("${annotation.message} (当前长度: ${value.size}, 要求: ${annotation.min}-${annotation.max})")
                        }
                    }
                }
            }
            
            // 验证Pattern
            field.getAnnotation(Pattern::class.java)?.let { annotation ->
                if (value is String && !Regex(annotation.regex).matches(value)) {
                    errors.getOrPut(fieldName) { mutableListOf() }
                        .add(annotation.message)
                }
            }
            
            // 验证Range
            field.getAnnotation(Range::class.java)?.let { annotation ->
                when (value) {
                    is Int -> {
                        if (value < annotation.min || value > annotation.max) {
                            errors.getOrPut(fieldName) { mutableListOf() }
                                .add("${annotation.message} (当前值: $value, 要求: ${annotation.min}-${annotation.max})")
                        }
                    }
                    is Long -> {
                        if (value < annotation.min || value > annotation.max) {
                            errors.getOrPut(fieldName) { mutableListOf() }
                                .add("${annotation.message} (当前值: $value, 要求: ${annotation.min}-${annotation.max})")
                        }
                    }
                }
            }
            
            // 验证Email
            field.getAnnotation(Email::class.java)?.let { annotation ->
                if (value is String) {
                    val emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\$"
                    if (!Regex(emailRegex).matches(value)) {
                        errors.getOrPut(fieldName) { mutableListOf() }
                            .add(annotation.message)
                    }
                }
            }
        }
        
        return ValidationResult(errors.isEmpty(), errors)
    }
    
    fun validateAndThrow(obj: Any) {
        val result = validate(obj)
        if (!result.isValid) {
            throw ValidationException(result)
        }
    }
}

// ================ 使用示例 ================

data class User(
    @field:Validate
    @field:NotEmpty("用户名不能为空")
    @field:Length(min = 3, max = 20, message = "用户名长度必须为3-20位")
    val username: String,
    
    @field:Validate
    @field:NotEmpty("密码不能为空")
    @field:Length(min = 6, max = 30, message = "密码长度必须为6-30位")
    val password: String,
    
    @field:Validate
    @field:Email("邮箱格式不正确")
    val email: String?,
    
    @field:Validate
    @field:Range(min = 0, max = 150, message = "年龄必须在0-150之间")
    val age: Int,
    
    @field:Validate
    @field:Pattern(
        regex = "^1[3-9]\\d{9}\$",
        message = "手机号格式不正确"
    )
    val phone: String?,
    
    // 非验证字段
    val createdAt: Long = System.currentTimeMillis()
)

fun main() {
    val validUser = User(
        username = "john_doe",
        password = "password123",
        email = "john@example.com",
        age = 25,
        phone = "13800138000"
    )
    
    val invalidUser = User(
        username = "ab", // 太短
        password = "123", // 太短
        email = "invalid-email",
        age = 200, // 超出范围
        phone = "123456" // 格式错误
    )
    
    println("验证有效用户:")
    println(Validator.validate(validUser))
    
    println("\n验证无效用户:")
    println(Validator.validate(invalidUser))
    
    // 验证并抛出异常
    try {
        Validator.validateAndThrow(invalidUser)
    } catch (e: ValidationException) {
        println("\n验证异常: ${e.validationResult.errors}")
    }
}

案例2:依赖注入注解

// ================ DI注解定义 ================

/**
 * 标记可注入的类
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Component

/**
 * 单例组件
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@Component
annotation class Singleton

/**
 * 配置类
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@Component
annotation class Configuration

/**
 * Bean定义
 */
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Bean

/**
 * 自动注入
 */
@Target(AnnotationTarget.FIELD, AnnotationTarget.CONSTRUCTOR)
@Retention(AnnotationRetention.RUNTIME)
annotation class Autowired

/**
 * 限定符
 */
@Target(AnnotationTarget.FIELD, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class Qualifier(val name: String)

/**
 * 值注入
 */
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class Value(val expression: String)

// ================ DI容器实现 ================

/**
 * Bean定义
 */
data class BeanDefinition(
    val name: String,
    val type: Class<*>,
    val instance: Any? = null,
    val isSingleton: Boolean = false,
    val factory: (() -> Any)? = null
)

/**
 * 简易DI容器
 */
class ApplicationContext(private val scanPackages: List<String> = emptyList()) {
    private val beanDefinitions = mutableMapOf<String, BeanDefinition>()
    private val singletonInstances = mutableMapOf<String, Any>()
    
    init {
        if (scanPackages.isNotEmpty()) {
            scanComponents()
        }
    }
    
    /**
     * 扫描组件
     */
    private fun scanComponents() {
        // 这里简化实现,实际项目会使用类路径扫描
        println("扫描组件包: $scanPackages")
    }
    
    /**
     * 注册Bean
     */
    fun <T : Any> registerBean(
        name: String,
        type: Class<T>,
        instance: T? = null,
        isSingleton: Boolean = false,
        factory: (() -> T)? = null
    ) {
        beanDefinitions[name] = BeanDefinition(name, type, instance, isSingleton, factory)
    }
    
    /**
     * 获取Bean
     */
    @Suppress("UNCHECKED_CAST")
    fun <T : Any> getBean(name: String): T {
        val definition = beanDefinitions[name] 
            ?: throw NoSuchElementException("未找到Bean: $name")
        
        return when {
            definition.isSingleton -> {
                singletonInstances.getOrPut(name) {
                    createBeanInstance(definition)
                } as T
            }
            definition.instance != null -> definition.instance as T
            definition.factory != null -> definition.factory!!() as T
            else -> createBeanInstance(definition) as T
        }
    }
    
    /**
     * 按类型获取Bean
     */
    @Suppress("UNCHECKED_CAST")
    fun <T : Any> getBean(type: Class<T>): T {
        val matchingBeans = beanDefinitions.values
            .filter { type.isAssignableFrom(it.type) }
        
        return when (matchingBeans.size) {
            0 -> throw NoSuchElementException("未找到类型为 ${type.name} 的Bean")
            1 -> getBean(matchingBeans.first().name) as T
            else -> throw IllegalStateException("找到多个类型为 ${type.name} 的Bean")
        }
    }
    
    /**
     * 创建Bean实例
     */
    private fun createBeanInstance(definition: BeanDefinition): Any {
        val constructors = definition.type.declaredConstructors
        
        // 查找有@Autowired注解的构造器
        val autowiredConstructor = constructors.find { constructor ->
            constructor.isAnnotationPresent(Autowired::class.java)
        }
        
        return if (autowiredConstructor != null) {
            // 获取构造器参数
            val parameters = autowiredConstructor.parameters.map { param ->
                if (param.isAnnotationPresent(Qualifier::class.java)) {
                    val qualifier = param.getAnnotation(Qualifier::class.java)
                    getBean(qualifier.name)
                } else {
                    getBean(param.type)
                }
            }.toTypedArray()
            
            autowiredConstructor.newInstance(*parameters)
        } else {
            // 使用默认构造器
            definition.type.getDeclaredConstructor().newInstance()
        }.also { instance ->
            // 注入字段
            injectFields(instance)
        }
    }
    
    /**
     * 注入字段
     */
    private fun injectFields(instance: Any) {
        instance.javaClass.declaredFields.forEach { field ->
            if (field.isAnnotationPresent(Autowired::class.java)) {
                field.isAccessible = true
                
                val beanToInject = if (field.isAnnotationPresent(Qualifier::class.java)) {
                    val qualifier = field.getAnnotation(Qualifier::class.java)
                    getBean(qualifier.name)
                } else {
                    getBean(field.type)
                }
                
                field.set(instance, beanToInject)
            }
            
            // 注入值
            if (field.isAnnotationPresent(Value::class.java)) {
                field.isAccessible = true
                val valueAnnotation = field.getAnnotation(Value::class.java)
                val value = resolveValueExpression(valueAnnotation.expression)
                field.set(instance, convertValue(value, field.type))
            }
        }
    }
    
    /**
     * 解析值表达式
     */
    private fun resolveValueExpression(expression: String): String {
        // 简化实现,实际会从配置文件读取
        return when (expression) {
            "\${app.name}" -> "MyApplication"
            "\${app.version}" -> "1.0.0"
            "\${database.url}" -> "jdbc:mysql://localhost:3306/test"
            else -> expression
        }
    }
    
    /**
     * 转换值类型
     */
    private fun convertValue(value: String, targetType: Class<*>): Any {
        return when (targetType) {
            String::class.java -> value
            Int::class.java -> value.toInt()
            Long::class.java -> value.toLong()
            Boolean::class.java -> value.toBoolean()
            else -> throw IllegalArgumentException("不支持的转换类型: ${targetType.name}")
        }
    }
}

// ================ 使用示例 ================

// 定义Repository
interface UserRepository {
    fun findById(id: Long): String
    fun save(user: String): Long
}

@Singleton
@Qualifier("userRepository")
class UserRepositoryImpl : UserRepository {
    override fun findById(id: Long): String {
        return "User_$id"
    }
    
    override fun save(user: String): Long {
        println("保存用户: $user")
        return System.currentTimeMillis()
    }
}

@Singleton
@Qualifier("productRepository")
class ProductRepositoryImpl : UserRepository {
    override fun findById(id: Long): String {
        return "Product_$id"
    }
    
    override fun save(user: String): Long {
        println("保存产品: $user")
        return System.currentTimeMillis()
    }
}

// 定义Service
interface UserService {
    fun getUser(id: Long): String
}

@Singleton
class UserServiceImpl : UserService {
    
    @Autowired
    @Qualifier("userRepository")
    private lateinit var userRepository: UserRepository
    
    @Value("\${app.name}")
    private lateinit var appName: String
    
    @Value("\${app.version}")
    private lateinit var appVersion: String
    
    override fun getUser(id: Long): String {
        println("应用: $appName v$appVersion")
        return userRepository.findById(id)
    }
}

// 定义Controller
@Singleton
class UserController {
    
    @Autowired
    private lateinit var userService: UserService
    
    fun handleRequest(id: Long): String {
        return userService.getUser(id)
    }
}

// 配置类
@Configuration
class AppConfig {
    
    @Bean
    fun configBean(): Map<String, String> {
        return mapOf(
            "environment" to "development",
            "maxConnections" to "100"
        )
    }
}

fun main() {
    // 创建DI容器
    val context = ApplicationContext(listOf("com.example"))
    
    // 注册Bean
    context.registerBean("userRepository", UserRepositoryImpl::class.java, isSingleton = true)
    context.registerBean("productRepository", ProductRepositoryImpl::class.java, isSingleton = true)
    context.registerBean("userService", UserServiceImpl::class.java, isSingleton = true)
    context.registerBean("userController", UserController::class.java, isSingleton = true)
    
    // 获取Bean并使用
    val controller = context.getBean<UserController>("userController")
    val result = controller.handleRequest(1)
    println("结果: $result")
    
    // 按类型获取Bean
    val service = context.getBean(UserService::class.java)
    println("按类型获取Bean: ${service.getUser(2)}")
}

案例3:编译时注解处理器(KAPT)

项目结构:

build.gradle.kts (注解处理器模块)
build.gradle.kts (使用模块)

3.1 注解处理器模块

build.gradle.kts (注解处理器模块):

plugins {
    kotlin("jvm")
    `maven-publish`
}

dependencies {
    implementation(kotlin("stdlib"))
    implementation("com.google.auto.service:auto-service:1.0.1")
    kapt("com.google.auto.service:auto-service:1.0.1")
    implementation("com.squareup:kotlinpoet:1.12.0")
}

sourceSets {
    main {
        java.srcDirs("src/main/kotlin")
        resources.srcDirs("src/main/resources")
    }
}

publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["java"])
        }
    }
}

注解定义 (src/main/kotlin/com/example/annotations.kt):

package com.example.annotations

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Builder

@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.SOURCE)
annotation class BuilderProperty(
    val required: Boolean = false,
    val defaultValue: String = ""
)

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class ToString

@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.SOURCE)
annotation class ToStringExclude

注解处理器 (src/main/kotlin/com/example/processor/BuilderProcessor.kt):

package com.example.processor

import com.google.auto.service.AutoService
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.example.annotations.Builder
import com.example.annotations.BuilderProperty
import javax.annotation.processing.*
import javax.lang.model.SourceVersion
import javax.lang.model.element.TypeElement
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.tools.Diagnostic

@AutoService(Processor::class)
class BuilderProcessor : AbstractProcessor() {
    
    private lateinit var filer: Filer
    private lateinit var messager: Messager
    
    override fun init(processingEnv: ProcessingEnvironment) {
        super.init(processingEnv)
        filer = processingEnv.filer
        messager = processingEnv.messager
    }
    
    override fun getSupportedAnnotationTypes(): Set<String> {
        return setOf(Builder::class.java.canonicalName)
    }
    
    override fun getSupportedSourceVersion(): SourceVersion {
        return SourceVersion.latestSupported()
    }
    
    override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
        roundEnv.getElementsAnnotatedWith(Builder::class.java).forEach { element ->
            if (element.kind != ElementKind.CLASS) {
                messager.printMessage(Diagnostic.Kind.ERROR, "@Builder只能用于类", element)
                return@forEach
            }
            
            val classElement = element as TypeElement
            generateBuilderClass(classElement)
        }
        
        return true
    }
    
    private fun generateBuilderClass(classElement: TypeElement) {
        val className = classElement.simpleName.toString()
        val packageName = processingEnv.elementUtils.getPackageOf(classElement).toString()
        val builderClassName = "${className}Builder"
        
        val typeSpec = TypeSpec.classBuilder(builderClassName)
            .addModifiers(KModifier.PUBLIC)
        
        // 添加属性字段
        classElement.enclosedElements
            .filter { it.kind == ElementKind.FIELD }
            .forEach { field ->
                val fieldName = field.simpleName.toString()
                val fieldType = field.asType().toString()
                val builderProperty = field.getAnnotation(BuilderProperty::class.java)
                
                val propertySpec = PropertySpec.builder(fieldName, fieldType.asTypeName())
                    .mutable(true)
                    .initializer(
                        if (builderProperty?.required == true) {
                            "error(\"$fieldName是必填字段\")"
                        } else if (builderProperty?.defaultValue?.isNotEmpty() == true) {
                            "\"${builderProperty.defaultValue}\""
                        } else {
                            when (fieldType) {
                                "kotlin.String" -> "\"\""
                                "kotlin.Int" -> "0"
                                "kotlin.Long" -> "0L"
                                "kotlin.Boolean" -> "false"
                                else -> "null"
                            }
                        }
                    )
                    .build()
                
                typeSpec.addProperty(propertySpec)
                
                // 添加setter方法
                val setterFun = FunSpec.builder(fieldName)
                    .addParameter(fieldName, fieldType.asTypeName())
                    .returns(ClassName(packageName, builderClassName))
                    .addStatement("this.$fieldName = $fieldName")
                    .addStatement("return this")
                    .build()
                
                typeSpec.addFunction(setterFun)
            }
        
        // 添加build方法
        val buildFun = FunSpec.builder("build")
            .returns(ClassName(packageName, className))
            .addStatement("return $className(")
            .apply {
                classElement.enclosedElements
                    .filter { it.kind == ElementKind.FIELD }
                    .forEachIndexed { index, field ->
                        val fieldName = field.simpleName.toString()
                        val comma = if (index > 0) "," else ""
                        addStatement("    ${comma}$fieldName = $fieldName")
                    }
            }
            .addStatement(")")
            .build()
        
        typeSpec.addFunction(buildFun)
        
        // 生成文件
        val fileSpec = FileSpec.builder(packageName, builderClassName)
            .addType(typeSpec.build())
            .build()
        
        try {
            fileSpec.writeTo(filer)
            messager.printMessage(Diagnostic.Kind.NOTE, "生成Builder类: $builderClassName")
        } catch (e: Exception) {
            messager.printMessage(Diagnostic.Kind.ERROR, "生成失败: ${e.message}")
        }
    }
}

// 扩展函数:转换类型字符串为TypeName
private fun String.asTypeName(): TypeName {
    return when (this) {
        "kotlin.String" -> STRING
        "kotlin.Int" -> INT
        "kotlin.Long" -> LONG
        "kotlin.Boolean" -> BOOLEAN
        "kotlin.Double" -> DOUBLE
        "kotlin.Float" -> FLOAT
        "kotlin.Byte" -> BYTE
        "kotlin.Short" -> SHORT
        "kotlin.Char" -> CHAR
        "kotlin.Unit" -> UNIT
        "kotlin.Any" -> ANY
        else -> {
            // 处理泛型类型,如List<String>
            if (contains("<")) {
                val rawType = substringBefore("<")
                val typeArg = substringAfter("<").substringBefore(">")
                val rawTypeName = ClassName.bestGuess(rawType)
                val typeArgName = typeArg.asTypeName()
                rawTypeName.parameterizedBy(typeArgName)
            } else {
                ClassName.bestGuess(this)
            }
        }
    }
}

3.2 使用模块

build.gradle.kts (使用模块):

plugins {
    kotlin("jvm")
    kotlin("kapt")
}

dependencies {
    implementation(project(":annotations")) // 注解模块
    kapt(project(":processor")) // 注解处理器模块
}

kapt {
    correctErrorTypes = true
}

实体类 (src/main/kotlin/com/example/model/User.kt):

package com.example.model

import com.example.annotations.Builder
import com.example.annotations.BuilderProperty

@Builder
data class User(
    @BuilderProperty(required = true)
    val id: Long,
    
    @BuilderProperty(required = true)
    val username: String,
    
    @BuilderProperty(defaultValue = "")
    val email: String,
    
    @BuilderProperty(defaultValue = "0")
    val age: Int,
    
    @BuilderProperty(defaultValue = "false")
    val isActive: Boolean
)

编译后会生成 (build/generated/source/kapt/main/com/example/model/UserBuilder.kt):

package com.example.model

import kotlin.String
import kotlin.Unit
import kotlin.error

public class UserBuilder {
  public var id: Long = error("id是必填字段")

  public var username: String = error("username是必填字段")

  public var email: String = ""

  public var age: Int = 0

  public var isActive: Boolean = false

  public fun id(id: Long): UserBuilder {
    this.id = id
    return this
  }

  public fun username(username: String): UserBuilder {
    this.username = username
    return this
  }

  public fun email(email: String): UserBuilder {
    this.email = email
    return this
  }

  public fun age(age: Int): UserBuilder {
    this.age = age
    return this
  }

  public fun isActive(isActive: Boolean): UserBuilder {
    this.isActive = isActive
    return this
  }

  public fun build(): User = User(
      id = id,
      username = username,
      email = email,
      age = age,
      isActive = isActive
  )
}

使用生成的Builder:

fun main() {
    val user = UserBuilder()
        .id(1L)
        .username("john_doe")
        .email("john@example.com")
        .age(25)
        .isActive(true)
        .build()
    
    println(user)
}

案例4:Kotlin Symbol Processing (KSP) - 更现代的注解处理器

4.1 KSP处理器实现

build.gradle.kts (KSP处理器模块):

plugins {
    kotlin("jvm")
    `maven-publish`
}

dependencies {
    implementation(kotlin("stdlib"))
    implementation("com.google.devtools.ksp:symbol-processing-api:1.8.0-1.0.9")
    implementation("com.squareup:kotlinpoet:1.12.0")
    implementation("com.squareup:kotlinpoet-ksp:1.12.0")
}

KSP处理器 (src/main/kotlin/com/example/ksp/ToStringProcessor.kt):

package com.example.ksp

import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.*
import com.google.devtools.ksp.validate
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toTypeName
import com.example.annotations.ToString
import com.example.annotations.ToStringExclude

class ToStringProcessor(
    private val codeGenerator: CodeGenerator,
    private val logger: KSPLogger
) : SymbolProcessor {
    
    override fun process(resolver: Resolver): List<KSAnnotated> {
        val symbols = resolver.getSymbolsWithAnnotation(ToString::class.qualifiedName!!)
        val ret = symbols.filter { !it.validate() }.toList()
        
        symbols
            .filter { it is KSClassDeclaration && it.validate() }
            .forEach { it.accept(ToStringVisitor(), Unit) }
        
        return ret
    }
    
    inner class ToStringVisitor : KSVisitorVoid() {
        override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
            val packageName = classDeclaration.packageName.asString()
            val className = classDeclaration.simpleName.asString()
            val generatedClassName = "${className}Extensions"
            
            logger.info("处理类: $className")
            
            // 获取所有属性(排除排除的属性)
            val properties = classDeclaration.getAllProperties()
                .filter { property ->
                    property.annotations.none { 
                        it.annotationType.resolve().declaration.qualifiedName?.asString() == 
                        ToStringExclude::class.qualifiedName
                    }
                }
                .toList()
            
            // 生成toString扩展函数
            val toStringFun = FunSpec.builder("toStringFormatted")
                .receiver(classDeclaration.toClassName())
                .returns(String::class)
                .addStatement("return buildString {")
                .addStatement("    append(\"$className(\")")
                
            properties.forEachIndexed { index, property ->
                val propertyName = property.simpleName.asString()
                val comma = if (index > 0) ", " else ""
                toStringFun.addStatement(
                    "    append(\"$comma$propertyName = \${this.$propertyName}\")"
                )
            }
            
            toStringFun.addStatement("    append(\")\")")
            toStringFun.addStatement("}")
            
            // 生成文件
            val fileSpec = FileSpec.builder(packageName, generatedClassName)
                .addFunction(toStringFun.build())
                .build()
            
            val dependencies = Dependencies(
                aggregating = false,
                classDeclaration.containingFile!!,
                *resolver.getAllFiles().toList().toTypedArray()
            )
            
            codeGenerator.createNewFile(
                dependencies,
                packageName,
                generatedClassName
            ).use { outputStream ->
                fileSpec.writeTo(outputStream)
            }
        }
    }
}

class ToStringProcessorProvider : SymbolProcessorProvider {
    override fun create(
        environment: SymbolProcessorEnvironment
    ): SymbolProcessor {
        return ToStringProcessor(environment.codeGenerator, environment.logger)
    }
}

4.2 配置KSP (使用模块的build.gradle.kts):

plugins {
    kotlin("jvm")
    id("com.google.devtools.ksp")
}

dependencies {
    implementation(project(":annotations"))
    ksp(project(":ksp-processor"))
}

kotlin {
    sourceSets.main {
        kotlin.srcDir("build/generated/ksp/main/kotlin")
    }
}

ksp {
    arg("option1", "value1")
    arg("option2", "value2")
}

案例5:路由注解框架

// ================ 路由注解定义 ================

/**
 * Activity路由
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Router(
    val path: String,
    val description: String = ""
)

/**
 * 方法路由
 */
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Route(
    val path: String,
    val method: HttpMethod = HttpMethod.GET,
    val authRequired: Boolean = false
)

/**
 * 路径参数
 */
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class PathParam(val name: String)

/**
 * 查询参数
 */
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class QueryParam(val name: String)

/**
 * 请求体
 */
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class Body

/**
 * HTTP方法枚举
 */
enum class HttpMethod {
    GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
}

// ================ 路由信息类 ================

/**
 * 参数信息
 */
data class ParameterInfo(
    val name: String,
    val type: Class<*>,
    val annotation: Annotation?
)

/**
 * 路由信息
 */
data class RouteInfo(
    val path: String,
    val method: HttpMethod,
    val handler: Any,
    val function: java.lang.reflect.Method,
    val parameters: List<ParameterInfo>,
    val authRequired: Boolean
)

/**
 * 路由表
 */
object RouterTable {
    private val routes = mutableMapOf<String, MutableMap<HttpMethod, RouteInfo>>()
    
    fun register(controller: Any) {
        val controllerClass = controller.javaClass
        
        // 获取控制器基础路径
        val basePath = controllerClass.getAnnotation(Router::class.java)?.path ?: ""
        
        controllerClass.declaredMethods.forEach { method ->
            val routeAnnotation = method.getAnnotation(Route::class.java)
            if (routeAnnotation != null) {
                val fullPath = if (basePath.isNotEmpty()) {
                    "$basePath${routeAnnotation.path}"
                } else {
                    routeAnnotation.path
                }
                
                // 获取参数信息
                val parameters = method.parameters.map { param ->
                    val annotations = param.annotations
                    val annotation = annotations.firstOrNull {
                        it is PathParam || it is QueryParam || it is Body
                    }
                    
                    ParameterInfo(param.name, param.type, annotation)
                }
                
                val routeInfo = RouteInfo(
                    path = fullPath,
                    method = routeAnnotation.method,
                    handler = controller,
                    function = method,
                    parameters = parameters,
                    authRequired = routeAnnotation.authRequired
                )
                
                routes.getOrPut(fullPath) { mutableMapOf() }[routeAnnotation.method] = routeInfo
            }
        }
    }
    
    fun findRoute(path: String, method: HttpMethod): RouteInfo? {
        return routes[path]?.get(method)
    }
    
    fun getAllRoutes(): List<RouteInfo> {
        return routes.values.flatMap { it.values }
    }
}

/**
 * HTTP请求上下文
 */
data class RequestContext(
    val path: String,
    val method: HttpMethod,
    val headers: Map<String, String>,
    val pathParams: Map<String, String>,
    val queryParams: Map<String, List<String>>,
    val body: String?
)

/**
 * HTTP响应
 */
data class HttpResponse(
    val statusCode: Int,
    val headers: Map<String, String>,
    val body: Any?
)

/**
 * 路由处理器
 */
class RouterHandler {
    
    fun handleRequest(context: RequestContext): HttpResponse {
        val routeInfo = RouterTable.findRoute(context.path, context.method)
            ?: return HttpResponse(404, emptyMap(), "路由未找到: ${context.path}")
        
        // 检查权限
        if (routeInfo.authRequired && !checkAuth(context)) {
            return HttpResponse(401, emptyMap(), "未授权")
        }
        
        try {
            // 准备参数
            val args = prepareArguments(routeInfo, context)
            
            // 调用方法
            val result = routeInfo.function.invoke(routeInfo.handler, *args)
            
            return HttpResponse(200, emptyMap(), result)
        } catch (e: Exception) {
            return HttpResponse(500, emptyMap(), "服务器错误: ${e.message}")
        }
    }
    
    private fun prepareArguments(routeInfo: RouteInfo, context: RequestContext): Array<Any?> {
        return routeInfo.parameters.map { param ->
            when (val annotation = param.annotation) {
                is PathParam -> context.pathParams[annotation.name]
                is QueryParam -> context.queryParams[annotation.name]?.firstOrNull()
                is Body -> parseBody(context.body, param.type)
                else -> null
            }
        }.toTypedArray()
    }
    
    private fun parseBody(body: String?, type: Class<*>): Any? {
        if (body.isNullOrEmpty()) return null
        
        return when (type) {
            String::class.java -> body
            Map::class.java -> {
                body.split("&").associate { pair ->
                    val (key, value) = pair.split("=")
                    key to value
                }
            }
            else -> {
                // 这里可以集成JSON解析库
                body
            }
        }
    }
    
    private fun checkAuth(context: RequestContext): Boolean {
        val authHeader = context.headers["Authorization"]
        return authHeader?.startsWith("Bearer ") == true
    }
}

// ================ 控制器定义 ================

@Router("/api/users", "用户管理")
class UserController {
    
    @Route("/", HttpMethod.GET)
    fun getUsers(
        @QueryParam("page") page: Int = 1,
        @QueryParam("size") size: Int = 20
    ): Map<String, Any> {
        return mapOf(
            "page" to page,
            "size" to size,
            "users" to listOf(
                mapOf("id" to 1, "name" to "张三"),
                mapOf("id" to 2, "name" to "李四")
            )
        )
    }
    
    @Route("/{id}", HttpMethod.GET, authRequired = true)
    fun getUserById(@PathParam("id") id: Long): Map<String, Any> {
        return mapOf(
            "id" to id,
            "name" to "用户$id",
            "email" to "user$id@example.com"
        )
    }
    
    @Route("/", HttpMethod.POST, authRequired = true)
    fun createUser(@Body userData: Map<String, Any>): Map<String, Any> {
        return mapOf(
            "success" to true,
            "message" to "用户创建成功",
            "data" to userData,
            "id" to System.currentTimeMillis()
        )
    }
    
    @Route("/{id}", HttpMethod.PUT, authRequired = true)
    fun updateUser(
        @PathParam("id") id: Long,
        @Body userData: Map<String, Any>
    ): Map<String, Any> {
        return mapOf(
            "success" to true,
            "message" to "用户更新成功",
            "id" to id,
            "data" to userData
        )
    }
    
    @Route("/{id}", HttpMethod.DELETE, authRequired = true)
    fun deleteUser(@PathParam("id") id: Long): Map<String, Any> {
        return mapOf(
            "success" to true,
            "message" to "用户删除成功",
            "id" to id
        )
    }
}

@Router("/api/products", "产品管理")
class ProductController {
    
    @Route("/search", HttpMethod.GET)
    fun searchProducts(
        @QueryParam("keyword") keyword: String?,
        @QueryParam("category") category: String?
    ): Map<String, Any> {
        return mapOf(
            "keyword" to keyword,
            "category" to category,
            "products" to listOf(
                mapOf("id" to 1, "name" to "产品1", "price" to 99.99),
                mapOf("id" to 2, "name" to "产品2", "price" to 199.99)
            )
        )
    }
}

// ================ 使用示例 ================

fun main() {
    // 注册控制器
    val userController = UserController()
    val productController = ProductController()
    
    RouterTable.register(userController)
    RouterTable.register(productController)
    
    // 打印所有路由
    println("已注册的路由:")
    RouterTable.getAllRoutes().forEach { route ->
        println("  ${route.method} ${route.path} (需要认证: ${route.authRequired})")
    }
    
    // 创建路由器
    val routerHandler = RouterHandler()
    
    // 模拟请求
    println("\n模拟请求:")
    
    // 请求1: 获取用户列表(不需要认证)
    val request1 = RequestContext(
        path = "/api/users/",
        method = HttpMethod.GET,
        headers = emptyMap(),
        pathParams = emptyMap(),
        queryParams = mapOf(
            "page" to listOf("1"),
            "size" to listOf("10")
        ),
        body = null
    )
    
    val response1 = routerHandler.handleRequest(request1)
    println("请求1结果: ${response1.statusCode} - ${response1.body}")
    
    // 请求2: 获取用户详情(需要认证但未提供)
    val request2 = RequestContext(
        path = "/api/users/123",
        method = HttpMethod.GET,
        headers = emptyMap(),
        pathParams = mapOf("id" to "123"),
        queryParams = emptyMap(),
        body = null
    )
    
    val response2 = routerHandler.handleRequest(request2)
    println("请求2结果: ${response2.statusCode} - ${response2.body}")
    
    // 请求3: 获取用户详情(带认证)
    val request3 = RequestContext(
        path = "/api/users/123",
        method = HttpMethod.GET,
        headers = mapOf("Authorization" to "Bearer token123"),
        pathParams = mapOf("id" to "123"),
        queryParams = emptyMap(),
        body = null
    )
    
    val response3 = routerHandler.handleRequest(request3)
    println("请求3结果: ${response3.statusCode} - ${response3.body}")
    
    // 请求4: 创建用户
    val request4 = RequestContext(
        path = "/api/users/",
        method = HttpMethod.POST,
        headers = mapOf("Authorization" to "Bearer token123"),
        pathParams = emptyMap(),
        queryParams = emptyMap(),
        body = "name=王五&email=wangwu@example.com&age=30"
    )
    
    val response4 = routerHandler.handleRequest(request4)
    println("请求4结果: ${response4.statusCode} - ${response4.body}")
    
    // 请求5: 搜索产品
    val request5 = RequestContext(
        path = "/api/products/search",
        method = HttpMethod.GET,
        headers = emptyMap(),
        pathParams = emptyMap(),
        queryParams = mapOf(
            "keyword" to listOf("手机"),
            "category" to listOf("电子产品")
        ),
        body = null
    )
    
    val response5 = routerHandler.handleRequest(request5)
    println("请求5结果: ${response5.statusCode} - ${response5.body}")
}

注解最佳实践总结

1. 选择合适的保留策略

  • RUNTIME: 运行时处理(反射)
  • CLASS: 编译时处理(字节码操作)
  • SOURCE: 源码级别处理(注解处理器)

2. 注解处理器性能优化

// 使用增量处理
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.ISOLATING)
class MyProcessor : AbstractProcessor()

// 缓存处理结果
object AnnotationCache {
    private val cache = mutableMapOf<String, Any>()
    
    @Synchronized
    fun getOrCompute(key: String, compute: () -> Any): Any {
        return cache.getOrPut(key, compute)
    }
}

3. 元注解使用

// 定义元注解
@Target(AnnotationTarget.ANNOTATION_CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class ExperimentalApi

// 使用元注解
@ExperimentalApi
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class PreviewFeature

4. 编译时常量

const val VERSION = "1.0.0"

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class ApiVersion(val version: String = VERSION)

5. 重复注解

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@Repeatable
annotation class Permission(val value: String)

@Permission("READ")
@Permission("WRITE")
@Permission("EXECUTE")
fun sensitiveOperation() {
    // 需要多个权限
}

6. 注解别名

typealias ApiEndpoint = Route

@ApiEndpoint("/api/test", HttpMethod.GET)
fun testEndpoint() {
    // 使用别名
}

这些案例展示了Kotlin注解的强大功能,从简单的数据验证到复杂的框架开发,注解都能提供优雅的解决方案。在实际项目中,合理使用注解可以大大提高代码的可维护性和可扩展性。