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
classinstead ofrecord - use
javaTypein theresultMap - explicit downgrade (via
pom.xmlto3.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!