mybatis / mybatis-3

MyBatis SQL mapper framework for Java
http://mybatis.github.io/mybatis-3/
Apache License 2.0
19.82k stars 12.87k forks source link

Mybatis sqlbound parametMapping get property type failed #3155

Open Chishide opened 6 months ago

Chishide commented 6 months ago

image image

Hi all, in this case, this sql parsed with two params and mybatis wrap them as ParamMap type, when parsing the boud sql, the DynamicContext class wrap this ParamMap to ContexMap for binding field, ParameterMappingTokenHandler will deal the raw sql properties but can not get the correct property type because it the additionalParameters is wrapped can not get the value by propery, this property type will be recgonized as Object type, I know this can be work well with all most situations but in some case it will work wrong like enum field or customize field, is this a bug or can you give some adive?

MyBatis version

3.5.7

Database vendor and version

mysql

Test case or example project

Steps to reproduce

Expected result

Actual result

harawata commented 6 months ago

Hello @Chishide ,

I'm not sure. Please create a small demo project and share it on your GitHub repository. Here are some templates and examples: https://github.com/harawata/mybatis-issues

mgorzcom commented 6 months ago

I think i have similar problem.

My example: postgres:12.4, mybatis 3.5.16 Table:

CREATE TABLE test_table (
  id NUMERIC NOT NULL,
  create_time TIMESTAMP(6)
)

Dto and mapping configuration:

package example;

import java.util.Date;

public class DbTestDto {

    public DbTestDto() {}

    public DbTestDto(Long id, Date createTime) {
        this.id = id;
        this.createTime = createTime;
    }

    private Long id;
    private Date createTime;

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}
package example;

import org.apache.ibatis.annotations.Param;

public interface DbTestDao {
    void insert(@Param("dbTestDto") DbTestDto dbTestDto);
}
<?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='example.DbTestDao'>

    <insert id="insert" parameterType="example.DbTestDto">
        insert into TEST_TABLE (
            id,
            create_time
        )
        values (
            #{dbTestDto.id},
            #{dbTestDto.createTime}
        )
    </insert>

</mapper>

Problem: Until i specify javaType in mapper (for example javaType=java.util.Date for dbTestDto.createTime) javaType is resolved as java.lang.Object and org.apache.ibatis.type.UnknownTypeHandler is always used: obraz

In my case i am not able to set javaType, bacause i use some external library (which mybatis) without possibility to override.

I think that the problem is with org.apache.ibatis.reflection.MetaClass#hasGetter method in that case. On debug i see: obraz

Check your's junit test org.apache.ibatis.reflection.MetaClassTest#shouldCheckGetterExistance

mgorzcom commented 6 months ago

Simplest reproduction - debug org.apache.ibatis.submitted.keygen.Jdbc3KeyGeneratorTest and CountryMapper#insertNamedBean obraz

Hmm.. Maybe it is impacted by difference between RawSqlSource and DynamicSqlSource (initialisation of sqlSource field)

harawata commented 3 months ago

I still don't understand what the expected/actual results are (because you guys ignored the issue report form). Is there an exception? Does the query insert an unexpected value?

And please stop using images unless it is absolutely necessary. Pasting debug window images is not helpful very much.

To fix a problem, we need to reproduce the problem first. The best way to show "how" is to create a small demo project. Here are some project templates and examples. https://github.com/harawata/mybatis-issues

Thank you!

DuDisv commented 1 week ago

The issue arises when using a custom save or update method where a Map is passed as the method's parameter, structured like this: { "param1" : POJO, "et" : POJO }

When MyBatis builds the BoundSql and creates the DynamicContext, it wraps the parameters again. This leads to a situation where, during the SQL parsing phase (org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler#buildParameterMapping), the correct propertyType cannot be obtained, which in turn prevents the deduction of the appropriate TypeHandler

image

the root cause lies here

image

our objectWrapper is MapWrapper. The property we're trying to access is "et.name", but the MapWrapper's internal map structure looks like this: { "_parameter" : {"param1" POJO, "et" : POJO}, "_databaseId" : null }

This happens because the DynamicContext wraps the parameters and constructs the MapWrapper

image

As a result, we cannot obtain the actual property getter return type. I hope this explanation is clear.

DuDisv commented 1 week ago

when the field's jdbcType is JSON (in Mysql). saving data results in errors. My current solution is specify the typeHandler xml: #{jsonField, typeHandler=com.yourpackage.JSONArrayTypeHandler}

harawata commented 1 week ago

Hello @DuDisv ,

Please read my previous comment. It would be really helpful if you could share an executable test case or demo project.

And, again, please do not use images when posting text information.

Thank you!

DuDisv commented 1 week ago

@harawata Hi , I have created a test demo project , project url When executing the updateUser method, the database reported an error.【Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.】

harawata commented 1 week ago

Thank you for the demo, @DuDisv !

I am now pretty sure that the reported problem is a known issue. I already wrote a patch that will address the issue, but it is targeted at v4 because the change is huge.

My patch is available in the following branch if you guys are interested. https://github.com/harawata/mybatis-3/tree/type-based-handler-resolution Feedback is welcome!

DuDisv commented 1 week ago

Thank you for your reply. I really appreciate it. @harawata