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

Kotlin自定义YAML解析器@YamlArg注解映射失效求助

问题分析

你遇到的核心问题是:Kotlin中构造函数参数(即使标注了@YamlArg)和类的memberProperties并非直接一一对应——如果构造参数没有用val/var声明为类成员属性,memberProperties里根本找不到它;就算用了val/var,直接通过memberProperties获取注解,也可能拿不到标注在构造参数上的@YamlArg(注解目标范围没覆盖的话)。

解决方案

1. 修正@YamlArg注解的目标范围

确保注解能同时作用于构造函数参数和类属性,这样不管注解标在哪,都能被反射获取到:

@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
annotation class YamlArg(val value: String)

2. 重构解析器的映射逻辑:从构造函数参数入手

不要直接遍历memberProperties,而是先处理类的主构造函数参数,建立YAML键到构造参数/类属性的映射:

abstract class AbstractYamlParser {
    protected fun <T : Any> buildPropertyMap(clazz: KClass<T>): Map<String, KParameter> {
        val propertyMap = mutableMapOf<String, KParameter>()
        val primaryConstructor = clazz.primaryConstructor ?: error("No primary constructor found")
        
        primaryConstructor.parameters.forEach { param ->
            // 获取参数上的@YamlArg注解
            val yamlArg = param.findAnnotation<YamlArg>()
            val yamlKey = yamlArg?.value ?: param.name ?: error("Parameter has no name")
            propertyMap[yamlKey] = param
        }
        return propertyMap
    }

    // 解析时使用映射表,根据YAML键找到对应的构造参数注入值
    fun <T : Any> parse(yamlContent: String, clazz: KClass<T>): T {
        val yamlMap = parseYamlToMap(yamlContent) // 假设你已实现YAML转Map的逻辑
        val propertyMap = buildPropertyMap(clazz)
        val primaryConstructor = clazz.primaryConstructor!!
        
        val args = primaryConstructor.parameters.associateWith { param ->
            val yamlKey = propertyMap.entries.first { it.value == param }.key
            yamlMap[yamlKey] ?: error("Missing value for key: $yamlKey")
        }
        
        return primaryConstructor.callBy(args)
    }

    // 抽象方法:实现具体的YAML转Map逻辑
    abstract fun parseYamlToMap(yamlContent: String): Map<String, Any>
}

3. 领域类的正确写法

确保构造参数用val/var声明(需要成为类属性时),保留参数名(Kotlin默认保留,混淆时需配置规则):

data class Person(
    val name: String,
    @YamlArg("city of birth") val from: String
)

4. 测试用例验证

调用解析器方法,验证映射是否生效:

val yaml = """
name: Alice
city of birth: New York
""".trimIndent()

val parser = object : AbstractYamlParser() {
    override fun parseYamlToMap(yamlContent: String): Map<String, Any> {
        // 这里可以用SnakeYAML等库实现YAML转Map,示例简化处理
        return mapOf(
            "name" to "Alice",
            "city of birth" to "New York"
        )
    }
}

val person = parser.parse(yaml, Person::class)
println(person.from) // 输出: New York
关键注意点
  • 若领域类没有主构造函数,需额外处理次构造函数的映射逻辑
  • 混淆打包时,要保留类、构造函数参数、注解的反射信息,否则反射会失效
  • 若需要支持后期初始化的类属性,可以在buildPropertyMap中额外遍历memberProperties补充映射关系

内容的提问来源于stack exchange,提问作者nuno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:37:24