目录

自定义字段类型处理器:

package com.xxx.common.handler

import cn.hutool.core.util.StrUtil
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.JavaType
import com.fasterxml.jackson.databind.JsonMappingException
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.type.TypeFactory
import com.rollong.common.json.JSONUtil.toJSONString
import org.apache.ibatis.type.BaseTypeHandler
import org.apache.ibatis.type.JdbcType
import org.springframework.core.ResolvableType
import org.springframework.util.Assert
import java.io.IOException
import java.lang.reflect.Type
import java.sql.CallableStatement
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException

/**
 * 自定义字段类型处理器:为了解决字段类型处理器泛型被擦除的问题
 * @author flicker
 */
abstract class BaseAttributeTypeHandler<T> : BaseTypeHandler<Any?>() {
    private val javaType: JavaType

    /**
     * 构造方法
     */
    init {
        val resolvableType = ResolvableType.forClass(javaClass)
        val type = resolvableType.`as`(BaseAttributeTypeHandler::class.java).getGeneric().type
        javaType = constructType(type)
    }

    @Throws(SQLException::class)
    override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: Any?, jdbcType: JdbcType) {
        ps.setString(i, toJSONString(parameter!!))
    }

    @Throws(SQLException::class)
    override fun getNullableResult(rs: ResultSet, columnName: String): Any? {
        val value = rs.getString(columnName)
        return convertToEntityAttribute(value)
    }

    @Throws(SQLException::class)
    override fun getNullableResult(rs: ResultSet, columnIndex: Int): Any? {
        return convertToEntityAttribute(rs.getString(columnIndex))
    }

    @Throws(SQLException::class)
    override fun getNullableResult(cs: CallableStatement, columnIndex: Int): Any? {
        val value = cs.getString(columnIndex)
        return convertToEntityAttribute(value)
    }

    private fun convertToEntityAttribute(dbData: String): Any? {
        return if (StrUtil.isEmpty(dbData)) {
            if (MutableList::class.java.isAssignableFrom(javaType.rawClass)) {
                emptyList<Any>()
            } else if (MutableSet::class.java.isAssignableFrom(javaType.rawClass)) {
                emptySet<Any>()
            } else if (MutableMap::class.java.isAssignableFrom(javaType.rawClass)) {
                emptyMap<Any, Any>()
            } else {
                null
            }
        } else toObject<Any>(
            dbData,
            javaType
        )
    }

    companion object {
        /**
         * ObjectMapper
         */
        private val OBJECT_MAPPER = ObjectMapper()
        private fun constructType(type: Type): JavaType {
            Assert.notNull(type, "[Assertion failed] - type is required; it must not be null")
            return TypeFactory.defaultInstance().constructType(type)
        }

        private fun <T> toObject(json: String, javaType: JavaType): T {
            Assert.hasText(json, "[Assertion failed] - this json must have text; it must not be null, empty, or blank")
            Assert.notNull(javaType, "[Assertion failed] - javaType is required; it must not be null")
            return try {
                OBJECT_MAPPER.readValue(json, javaType)
            } catch (e: JsonParseException) {
                throw RuntimeException(e.message, e)
            } catch (e: JsonMappingException) {
                throw RuntimeException(e.message, e)
            } catch (e: IOException) {
                throw RuntimeException(e.message, e)
            }
        }
    }
}

使用:

@TableField(typeHandler = VCContentHandler::class)
var content: List<ViewComponentContent>? = null

class VCContentHandler : BaseAttributeTypeHandler<List<ViewComponentContent>>(JsonObjectType.jsonb)

参考资料:

MyBatis-Plus - 字段类型处理器之泛型擦除解决方案_放羊的牧码的博客-CSDN博客_mybatis plus 泛型

希望实现一个通用的嵌套泛型的TypeHandler · Issue #I4SCBF · baomidou/mybatis-plus - Gitee.com