Issue

While upgrading an application from SpringBoot2/MyBatisSpring2 to SpringBoot3/MyBatisSpring3 I noticed errors while running the tests:

Failed to find a constructor in 'com.example.demo.Foo' by arg names [id, name]. There might be more info in debug log.

Debugging org.apache.ibatis.mapping.ResultMap showed that the argNames were resolved correctly yet argTypesMatch() returned false, which in turn lead to the error above.

Workaround

  • use class instead of record
  • use javaType in the resultMap
  • explicit downgrade (via pom.xml to 3.5.9)

MyBatis version

3.5.11

Database vendor and version

PostgreSQL 14.4

Test case or example project

https://github.com/tzie0062/issue-mybatis-record

Steps to reproduce

Using a resultMap with records

Expected result

Mapper works

Actual result

Mapper fails with

Caused by: org.apache.ibatis.builder.BuilderException: Error in result map 'com.example.demo.FooRepository.foo_map'. Failed to find a constructor in 'com.example.demo.Foo' by arg names [id, name]. There might be more info in debug log.
    at org.apache.ibatis.mapping.ResultMap$Builder.build(ResultMap.java:130)
    at org.apache.ibatis.builder.MapperBuilderAssistant.addResultMap(MapperBuilderAssistant.java:208)
    at org.apache.ibatis.builder.ResultMapResolver.resolve(ResultMapResolver.java:47)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElement(XMLMapperBuilder.java:289)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElement(XMLMapperBuilder.java:254)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElements(XMLMapperBuilder.java:246)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:119)
    ... 102 more

Comment From: harawata

Hello, @tzie0062 ,

Thank you for the report and the repro! You can verify the fix in the latest 3.5.12-SNAPSHOT. Please let me know if there is any issue.

Comment From: harawata

Hello again, @tzie0062 .

After the discussion in #2804 , I now realize that it was a mistake to fix this issue and the fix will be reverted in 3.5.13.

javaType in constructor mapping is optional only when there is a 'writable property' in the target class. As Foo is declared as a record, there is no writable properties. So, you must specify javaTyps. The valid result map would be...

<resultMap id="foo_map" type="com.example.demo.Foo">
  <constructor>
     <idArg column="id" javaType="java.lang.Long" />
     <arg column="name" javaType="java.lang.String" /> 
  </constructor>
</resultMap>

Note that you don't have to specify name because the mapping order matches the actual constructor arguments order (see #721 if you are interested).

I apologize for the confusion.

Comment From: tzie0062

Hi @harawata !

I don't mind adding the javaType, however I still think something was broken between 3.5.9 and 3.5.11. Please have a look at the repo I mentioned above - I just updated it to have a BarRepository which returns an immutable object (no record). The Bar class does not have 'writeable properties' and the mapping works without javaType in the resultMap.

If you set the mybatis version to 3.5.9 in the pom, you will see that both record and immutable object work fine (without javaType), but the record fails in 3.5.11.

Comment From: harawata

Hi @tzie0062 ,

I haven't checked your updated demo, but it probably is the same issue as #2840 . Please see my comment there.

To avoid further confusion, we plan to release 3.5.13 as soon as possible.

Comment From: tzie0062

Thanks for the update @harawata !

I'll update all my mapper-files accordingly. It's a bit unfortunate that this change was introduced in a minor version, but I only see it as a minor inconvenience. Thanks for all the work/time you put in!

Comment From: harawata

Hi @tzie0062 ,

Thank you again for your patience and for taking the time to participate!