Description
MyBatis version
3.5.8 (any version above 3.4.2)
Database vendor and version
Any (tested on Postgres 12.7 and latest JDBC, but also fails in testing framework)
Test case or example project
https://github.com/matthewmillett-instaclustr/mybatis-issues/tree/master/gh-2427
Steps to reproduce
Run tests
Expected result
shouldGetAUser()
passes, by using the constructor within the User
class to construct the User
object
shouldGetAnAccount()
passes (regression check)
Actual result
shouldGetAUser()
fails with the exception java.lang.ClassCastException: class test.UserPrimaryKey cannot be cast to class test.User (test.UserPrimaryKey and test.User are in unnamed module of loader 'app')
shouldGetAnAccount()
passes (regression check)
Explanation
I believe that this issue was introduced with #604 (PR #859). Before 3.4.2, Mybatis would use the type User
, and find the constructor within the User
class to build the result object. However, in 3.4.2 and above, Mybatis attempts to search the super class UserPrimaryKey
, and uses the constructor within the UserPrimaryKey
class to build a User
object. It builds the UserPrimaryKey
object fine, but then hits an error when attempting to cast it to the expected result object of User
.
Sample fix
This is far from an ideal solution, but proves to show that the above explanation holds true.
Within org.apache.ibatis.type.TypeHandlerRegistry#getJdbcHandlerMapForSuperclass
, if we add the following check after the call to clazz.getSuperclass()
, the code works as intended:
if (clazz.getSuperclass() != null && clazz.getSuperclass().getName().contains("PrimaryKey")) {
return typeHandlerMap.get(clazz);
}
An alternative way of resolving this may be to check for assignability within the above function, and only if the super class is assignable to the subclass then return the typeHandlerMap
of the super class. I'm not sure how backwards compatible this would be, and/or if it would work.
Other
I'm pretty sure this is not a configuration problem, but if it is, then please let me know. If it can be resolved with the correct annotations within the mapper, I will be willing to give it a go. I couldn't see any other related tickets with a similar issue. I know the hierarchy of User
extending UserPrimaryKey
implementing PrimaryKey
is a bit odd, but modifying our inheritance/implementation structure is not an option.