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

使用Kotlin和Spring Boot实现通用更新端点及复杂属性反序列化问题

解决方案

首先确认你使用的ObjectMapper是Spring容器注入的实例,不要手动创建,Spring Boot默认会自动将引入的Kotlin模块注册到容器托管的ObjectMapper中。

修正后的接口代码如下:

@PatchMapping(ENTITY_URL)
fun update(@PathVariable("id") entity: E,  @RequestBody fields: Map<String,Any>): E {
    entity::class.memberProperties
        .filterIsInstance<KMutableProperty<*>>()
        .forEach { prop ->
            fields[prop.name]?.let { fieldValue ->
                // 构造带泛型信息的目标类型,支持Kotlin原生类型、集合、自定义实体
                val targetType = objectMapper.typeFactory.constructType(prop.returnType.javaType)
                // 直接完成Jackson内部结构到目标类型的转换,无需序列化后再反序列化
                val typedValue = objectMapper.convertValue<Any>(fieldValue, targetType)
                prop.setter.call(entity, typedValue)
            }
        }
    repo.save(entity)
    return entity
}

核心修改点说明

  • 替换readValue为convertValue方法:@RequestBody解析出来的fields中存储的是Jackson已经处理过的结构化数据(集合为ArrayList、对象为LinkedHashMap),转成字符串再反序列化属于冗余操作,还容易引发格式异常,convertValue是Jackson提供的内部类型转换工具,适配性更高。
  • 自动获取带泛型的类型信息:通过Kotlin反射prop.returnType.javaType可以直接拿到包含泛型参数的完整类型信息,不需要手动调用Class.forName做反射,自动兼容Kotlin的Set、List等原生集合类型,泛型参数比如Set<Role>中的Role也会被正确识别,不会再出现集合类型不匹配的问题。

可选优化

可以在属性过滤阶段增加逻辑,避免异常场景:

entity::class.memberProperties
    .filterIsInstance<KMutableProperty<*>>()
    // 过滤掉标注了@JsonIgnore的属性、以及请求中没有传的字段
    .filter { prop ->
        fields.containsKey(prop.name)
        && !prop.annotations.any { it is com.fasterxml.jackson.annotation.JsonIgnore }
    }
    .forEach { // 原有逻辑 }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 11:27:00