baomidou / mybatis-plus

An powerful enhanced toolkit of MyBatis for simplify development
https://baomidou.com
Apache License 2.0
16.4k stars 4.31k forks source link

[Bug]: kotlin使用自定义typehandler或者JacksonTypeHandler提示:”No typehandler found for property properties“ #6351

Closed wzyxdwll closed 2 months ago

wzyxdwll commented 3 months ago

确认

当前程序版本

3.5.5

问题描述

版本信息: kotlin: 1.9.24 mybatis-plus: .3.5.5 spring boot: 3.3.1

代码如下: customPropertyPojo:

data class CustomPropertyPojo(
    val name: String? = null,
    val type: Int? = null,
)

entity:

@TableName("info_custom_property", autoResultMap = true)
@Schema(name = "CustomProperty", description = "")
class CustomProperty : Serializable {

    @TableId(value = "id", type = IdType.ASSIGN_ID)
    var id: String? = null

    var weight: Int? = null

    @TableField(fill = FieldFill.INSERT)
    var createTime: Long? = null

    @TableField(fill = FieldFill.UPDATE)
    var updateTime: Long? = null

    @TableField(fill = FieldFill.INSERT)
    var createBy: String? = null

    @TableField(fill = FieldFill.UPDATE)
    var updateBy: String? = null

    @Version
    var version: Long? = null

    @TableLogic
    var deleted: Int? = null

    var extra: String? = null

    var tenantId: String? = null

    @Schema(description = "属性类型")
    var propertyType: Int? = null

    @Schema(description = "属性")
    @TableField(value = "properties", jdbcType = JdbcType.VARCHAR, typeHandler = JsonbTypeHandler::class)
    var properties: CustomPropertyPojo? = null

    @Schema(description = "描述")
    var description: String? = null

    @Schema(description = "备注")
    var remark: String? = null

    override fun toString(): String {
        return "CustomProperty{" +
        "id=" + id +
        ", weight=" + weight +
        ", createTime=" + createTime +
        ", updateTime=" + updateTime +
        ", createBy=" + createBy +
        ", updateBy=" + updateBy +
        ", version=" + version +
        ", deleted=" + deleted +
        ", extra=" + extra +
        ", tenantId=" + tenantId +
        ", propertyType=" + propertyType +
        ", properties=" + properties +
        ", description=" + description +
        ", remark=" + remark +
        "}"
    }

jsonbTypeHandler:

@MappedTypes(CustomPropertyPojo::class)
@MappedJdbcTypes(JdbcType.VARCHAR)
class JsonbTypeHandler<T>(private val clazz: Class<T>) : BaseTypeHandler<T>() {

    init {
        requireNotNull(clazz) { "Type argument cannot be null" }
    }

    private val objectMapper = ObjectMapper()

    @Throws(SQLException::class)
    override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: T, jdbcType: JdbcType?) {
        val jsonbObject = PGobject().apply {
            type = "jsonb"
            value = objectMapper.writeValueAsString(parameter)
        }
        ps.setObject(i, jsonbObject)
    }

    @Throws(SQLException::class)
    override fun getNullableResult(rs: ResultSet, columnName: String): T? {
        return parseJsonb(rs.getString(columnName))
    }

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

    @Throws(SQLException::class)
    override fun getNullableResult(cs: CallableStatement, columnIndex: Int): T? {
        return parseJsonb(cs.getString(columnIndex))
    }

    private fun parseJsonb(jsonbString: String?): T? {
        return jsonbString?.let {
            objectMapper.readValue(it, clazz)
        }
    }
}

mapper xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.meother.business.mapper.CustomPropertyMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.meother.business.entity.CustomProperty">
        <id column="id" property="id" />
        <result column="weight" property="weight" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="create_by" property="createBy" />
        <result column="update_by" property="updateBy" />
        <result column="version" property="version" />
        <result column="deleted" property="deleted" />
        <result column="extra" property="extra" />
        <result column="tenant_id" property="tenantId" />
        <result column="property_type" property="propertyType" />
        <result column="properties" property="properties" jdbcType="VARCHAR" />
        <result column="description" property="description" />
        <result column="remark" property="remark" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, weight, create_time, update_time, create_by, update_by, version, deleted, extra, tenant_id, property_type, properties, description, remark
    </sql>

</mapper>

详细堆栈日志

具体报错:

Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\IdeaProject\qmyz-server\qmyz-server-provider\build\resources\main\mappers\business\CustomPropertyMapper.xml]'. Cause: java.lang.IllegalStateException: No typehandler found for property properties
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:127) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:100) ~[mybatis-3.5.15.jar:3.5.15]
    at com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean.buildSqlSessionFactory(MybatisSqlSessionFactoryBean.java:562) ~[mybatis-plus-extension-3.5.5.jar:3.5.5]
    ... 198 common frames omitted
Caused by: java.lang.IllegalStateException: No typehandler found for property properties
    at org.apache.ibatis.mapping.ResultMapping$Builder.validate(ResultMapping.java:153) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.mapping.ResultMapping$Builder.build(ResultMapping.java:140) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.MapperBuilderAssistant.buildResultMapping(MapperBuilderAssistant.java:352) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildResultMappingFromContext(XMLMapperBuilder.java:403) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElement(XMLMapperBuilder.java:286) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElement(XMLMapperBuilder.java:261) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElements(XMLMapperBuilder.java:253) ~[mybatis-3.5.15.jar:3.5.15]
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:123) ~[mybatis-3.5.15.jar:3.5.15]
    ... 200 common frames omitted
wzyxdwll commented 3 months ago

我把xml文件改了一下 将properties改成如下:

就可以正常使用了,但是理论上在entity中用注解应该也能正常工作才对?

miemieYaho commented 3 months ago

注解生效范围不是全局

wzyxdwll commented 3 months ago

注解生效范围不是全局

您的意思是还是需要在application里面配置typehandler的包扫描是么? 我尝试了一下xml和注解都需要加typehandler

miemieYaho commented 3 months ago

注解只生效于mp自带的crud

miemieYaho commented 3 months ago

string的typehandler也不要全局扫,会误伤其他的

wzyxdwll commented 3 months ago

注解只生效于mp自带的crud

我使用的就是mp自带的crud还是要在mapper.xml里面加typehandler的属性

miemieYaho commented 3 months ago

如果自带crud都不生效那你提供复现demo吧

wzyxdwll commented 3 months ago

如果自带crud都不生效那你提供复现demo吧

好的 我整理一下,提供个demo出来

wzyxdwll commented 2 months ago

mbp-demo.zip

demo在这里,把mapper.xml里面的typehandler去掉或者是entity里面的typehandler去掉都不行

miemieYaho commented 2 months ago

试了,不管去不去掉xml都正常的,而且本来不管你xml写什么resultMap都不会影响mp自带的查询

miemieYaho commented 2 months ago

image

wzyxdwll commented 2 months ago

您的意思是去掉整个xml么?而不是去掉xml的asset字段的typehandler么?

image

miemieYaho commented 2 months ago

image 都说了你xml里写的东西根本就没有用到,去掉整个和去掉部分有区别吗?

wzyxdwll commented 2 months ago

image 都说了你xml里写的东西根本就没有用到,去掉整个和去掉部分有区别吗?

image

miemieYaho commented 2 months ago

你这不是启动报错嘛,那肯定要报错啊,有什么问题?上面也说注解的生效范围,你自己写的resultmap又不在这个范围内

wzyxdwll commented 2 months ago

好的 我理解了 感谢解答