Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mybatis sqlbound parametMapping get property type failed #3155

Open
Chishide opened this issue May 3, 2024 · 10 comments
Open

Mybatis sqlbound parametMapping get property type failed #3155

Chishide opened this issue May 3, 2024 · 10 comments

Comments

@Chishide
Copy link

Chishide commented May 3, 2024

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
Copy link
Member

harawata commented May 4, 2024

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
Copy link

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
Copy link

mgorzcom commented May 20, 2024

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
Copy link
Member

harawata commented Aug 8, 2024

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
Copy link

DuDisv commented Nov 18, 2024

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
Copy link

DuDisv commented Nov 18, 2024

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
Copy link
Member

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
Copy link

DuDisv commented Nov 18, 2024

@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
Copy link
Member

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
Copy link

DuDisv commented Nov 19, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants