Skip to content

TypeHandler incorrectly selects super classes/interfaces #2427

Open
@matthewmillett-instaclustr

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions