Hibernate可以自定义一些类型转换器,即从java对象转换成数据库中的值,或者把数据库中的值转成java对象。
JsonType即在保存时把java对象转换成json字符串存在数据库,在读取数据库时再把json字符串转成对应的java对象。

自定义类型需要实现UserType接口,并实现对应方法

这只是一个简单的实现,仅在H2数据库中和Hibernate 6中使用没问题,其hypersistence-utils适配了各种数据库,并支持Hibernate的各种版本

class JsonType: UserType<Any>, DynamicParameterizedType {

    private lateinit var className: String

    override fun setParameterValues(parameters: Properties) {
        className = parameters.getProperty("org.hibernate.type.ParameterType.returnedClass")
    }

    override fun equals(x: Any?, y: Any?): Boolean {
        return x == y
    }

    override fun hashCode(x: Any?): Int {
        return x?.hashCode() ?: 0
    }

    override fun returnedClass(): Class<Any> {
        return javaType.javaTypeClass
    }

    private val javaType = ObjectJavaType.INSTANCE

    override fun getSqlType(): Int {
        return Types.VARCHAR
    }


    override fun nullSafeGet(
        rs: ResultSet,
        position: Int,
        session: SharedSessionContractImplementor?,
        owner: Any?
    ): Any {
        val value = rs.getObject(position)
        return SpringUtils.getBean<ObjectMapper>().readValue(value?.toString() ?: "{}", Class.forName(className))
    }

    override fun nullSafeSet(
        st: PreparedStatement,
        value: Any?,
        index: Int,
        session: SharedSessionContractImplementor?
    ) {
        if (value == null) {
            st.setObject(index, "{}")
        } else {
            val bean = SpringUtils.getBean<ObjectMapper>()
            bean.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY)
            st.setObject(index, SpringUtils.getBean<ObjectMapper>().writeValueAsString(value))
        }
    }

    override fun deepCopy(value: Any?): Any? {
        return value
    }

    override fun isMutable(): Boolean {
        return true
    }

    override fun disassemble(value: Any?): Serializable {
        TODO("Not yet implemented")
    }

    override fun assemble(cached: Serializable?, owner: Any?): Any {
        TODO("Not yet implemented")
    }

    override fun replace(detached: Any?, managed: Any?, owner: Any?): Any {
        TODO("Not yet implemented")
    }
}

其中,SpringUtils

@Component
@Lazy(false)
class SpringUtils: ApplicationContextAware {

    companion object {

        lateinit var applicationContext: ApplicationContext

        inline fun <reified T: Any> getBean(name: String): T {
            return applicationContext.getBean(name) as T
        }

        inline fun <reified T: Any> getBean() = applicationContext.getBean(T::class.java)

    }

    override fun setApplicationContext(applicationContext: ApplicationContext) {
        SpringUtils.applicationContext = applicationContext
    }
}

使用,在对应的实体类属性上标明注解

@Type(value = JsonType::class)
最后修改:2023 年 07 月 22 日
如果觉得我的文章对你有用,请随意赞赏