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 ofrecord
- use
javaType
in theresultMap
- explicit downgrade (via
pom.xml
to3.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 javaTyp
s. 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!