使用kotlin-reflect读取JSON生成匿名对象的动态属性如何实现?
问题分析与解决方案
现有代码的核心问题
- 变量引用错误:
let块的参数默认名为it,你代码中直接使用未定义的res变量引用反序列化得到的对象,运行时会直接报错。 - 反序列化类型选择错误:调用
asObject(Any::class.java)时,绝大多数JSON解析库会将JSON对象反序列化为Map类型(而非自定义类实例),Map本身的Kotlin成员属性不包含JSON的键名,通过反射查找成员属性自然找不到对应结果。 - 反射调用参数错误:
KProperty的getter.call仅需要传入实例对象本身作为唯一参数,你额外传入了属性名参数,会触发参数数量不匹配的反射调用异常。 - 不必要的类型校验:你只过滤
KMutableProperty<*>类型的属性,不可变属性会被直接排除,哪怕属性存在也会被过滤掉。
正确实现方案
方案1:优先转Map读取(无需反射,性能更高)
绝大多数场景下反序列化为Any的JSON对象本质是Map,直接强转后读取对应键即可:
val decodedToken = JWT(jwtString) decodedToken.getClaim("useful_claim").asObject(Any::class.java)?.let { claimObj -> // 直接转Map读取,无需反射 (claimObj as? Map<*, *>)?.get(BuildConfig.VARIABLE_NAME)?.let { value -> (value as? List<*>)?.filterIsInstance<MyClass>()?.let { return it } } }
方案2:反射读取(仅适用于反序列化结果为自定义类实例的场景)
如果确认反序列化得到的是带成员属性的Kotlin类实例,正确的反射写法如下:
val decodedToken = JWT(jwtString) decodedToken.getClaim("useful_claim").asObject(Any::class.java)?.let { instance -> // 查找对应名称的属性 val reflectProp = instance::class.memberProperties.find { it.name == BuildConfig.VARIABLE_NAME } reflectProp?.let { prop -> // 调用getter仅传入实例本身即可 (prop.getter.call(instance) as? List<*>)?.filterIsInstance<MyClass>()?.let { return it } } }
内容的提问来源于stack exchange,提问作者Cédric
相关产品推荐
相关产品推荐

