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(...); - 你的
Userdata 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
相关产品推荐
相关产品推荐

