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

Spring Boot+Kotlin+JPA无命名查询插入PostgreSQL JSON数据报错排查

解决Spring Boot+Kotlin中JPA插入PostgreSQL JSON类型的byte类型错误问题

我来帮你排查这个问题——你遇到的"Column 'user_detail'是JSON类型,但收到byte类型"错误,主要是代码里的几个细节疏漏导致的,咱们一步步拆解修正:

核心问题分析

这个错误本质是JPA没有正确识别你定义的转换器,默认把UserDetail对象序列化成了字节数组,和PostgreSQL的JSON列类型不匹配。具体问题出在这些地方:


1. 注解拼写错误

你代码里用了@Convertor,但JPA的转换注解正确写法是@Converter(少了一个字母e)!这个拼写错误直接导致转换器根本没被JPA识别,自然不会生效。

2. 代码拼写与语法错误

  • convertToDatabaseColumn方法里把userDetail拼写成了userDeatail,这会导致赋值失败或者编译错误;
  • Kotlin里抛出异常不需要用new关键字,应该写成throw RuntimeException(...);
  • 你的User data class语法有误,Kotlin的data class参数需要正确放在构造函数括号内,注解位置也要对应到属性上。

3. 服务层调用逻辑错误

你直接调用jpaRepo.save(userDetail),但你的Repository应该是针对User实体的,必须创建User对象并设置userDetail属性后再保存,不能直接保存嵌套的UserDetail对象。


修正后的完整代码

实体类与转换器

import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.persistence.*
import org.postgresql.util.PGObject

@Entity
@Table(name = "users")
data class User(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    val identifier: Int? = null,

    @Convert(converter = JSONConverter::class) // 正确使用@Convert指定转换器
    @Column(name = "user_detail", columnDefinition = "json") // 显式声明列类型更稳妥
    var userDetail: UserDetail? = null
)

@Converter(autoApply = false) // 仅在指定属性上生效,避免全局影响
class JSONConverter(private val objectMapper: ObjectMapper) : AttributeConverter<UserDetail, PGObject> {

    override fun convertToDatabaseColumn(attribute: UserDetail?): PGObject? {
        val pgObject = PGObject().apply { type = "json" }
        attribute ?: return null

        return try {
            pgObject.value = objectMapper.writeValueAsString(attribute)
            pgObject
        } catch (e: JsonProcessingException) {
            throw RuntimeException("无法序列化UserDetail为JSON", e)
        }
    }

    override fun convertToEntityAttribute(dbData: PGObject?): UserDetail? {
        dbData ?: return null
        if (dbData.value.isNullOrEmpty()) return null

        return try {
            objectMapper.readValue(dbData.value, UserDetail::class.java)
        } catch (e: JsonProcessingException) {
            throw RuntimeException("无法将JSON反序列化为UserDetail", e)
        }
    }
}

data class UserDetail(
    val name: String,
    val address: String? = null
)

服务层调用代码

// 假设你的Repository定义如下
interface UserRepository : JpaRepository<User, Int>

// 服务层保存逻辑
fun createUser() {
    val userDetail = UserDetail(name = "abc", address = "some address")
    val user = User(userDetail = userDetail)
    userRepository.save(user) // 保存User实体,而非UserDetail
}

额外注意事项

  • 如果你用的是Spring Boot 3.x,注解要导入jakarta.persistence包;如果是2.x版本,用javax.persistence包,别搞混;
  • 确保项目中引入了PostgreSQL JDBC驱动依赖(比如Gradle的implementation("org.postgresql:postgresql"));
  • ObjectMapper通过构造函数注入即可,Spring会自动管理,不用手动实例化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:45:09