Skip to content

TypeHandler lost information of actualTypeArguments when class is ParameterizedType #2187

Closed
@DavidTangWei

Description

@DavidTangWei

MyBatis version

3.4.5

Database vendor and version

mysql 5.7+

Test case or example project

deserialize data in table test to POJO Test using mybatis mapper.xml.

create table test {
    `id` bigint pk,
    `names` json
}
//POJO Test    
class Test {
    private long id;
    public void setId(long id) {
        this.id = id;
    }
    private List<String> names;
    public void setNames(List<String> names) {
        this.names = names;
    }
}

// typehandler use jackson for deserialization 
// the clazz in constructor lost actualTypeArguments when real class is ParameterizedType
class JsonTypeHandler<T>(private var clazz: Class<T>) : BaseTypeHandler<T>() {
    
    protected val objectMapper = ObjectMapper()
   
    override fun setNonNullParameter(ps: PreparedStatement?, i: Int, parameter: T, jdbcType: JdbcType?) {
        ps?.setString(i, this.toJson(parameter))
    }

    private fun toJson(obj: T): String {
        try {
            return this.objectMapper.writeValueAsString(obj)
        } catch (e: Exception) {
            throw RuntimeException(e);
        }
    }
    <resultMap id="testMapper" type="Test">
        <result property="id" column="id" />
        <result property="names" column="names" 
                typeHandler="JsonTypeHandler"/>
    </resultMap>

After debug the source code of mybatis, the class in the constructor of TypeHandler is get from org.apache.ibatis.reflection.Reflector#setTypes. But when the type is ParameterizedType to be added, ignore the actualTypeArguments and only add rawType.

//org.apache.ibatis.reflection.Reflector
 private void addSetMethod(String name, Method method) {
   if (isValidPropertyName(name)) {
     setMethods.put(name, new MethodInvoker(method));
     Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, type);
     setTypes.put(name, typeToClass(paramTypes[0]));
   }
 }

 private Class<?> typeToClass(Type src) {
   Class<?> result = null;
   if (src instanceof Class) {
     result = (Class<?>) src;
   } else if (src instanceof ParameterizedType) {
     // ignore the `actualTypeArguments` and only add `rawType`.
     result = (Class<?>) ((ParameterizedType) src).getRawType();
   } 
   ...
   }
   return result;
 }

Expected result

TypeHandler need to get the real ParameterizedType. Otherwise, I need to write many useless code to create many class inherit TypeHandler to pass the ParameterizedType manual.

Actual result

TypeHandler lost information of actualTypeArguments when class is ParameterizedType

Activity

DavidTangWei

DavidTangWei commented on Mar 10, 2021

@DavidTangWei
Author

@harawata hi.
Why do TypeHandler ignore the actualTypeArguments when the type is ParameterizedType ? Do you have plan to give us another method to get the actualTypeArguments.
I need your help! Please reply, thanks!

harawata

harawata commented on Mar 10, 2021

@harawata
Member

Hello @DavidTangWei ,

It is a known limitation.
I have been working on a patch, but it requires a lot of changes and I don't have much free time recently.

wyl0706

wyl0706 commented on Sep 12, 2021

@wyl0706

@harawata
I am experiencing the same problem, is there a plan to complete it?
My problem link: https://stackoverflow.com/questions/69140073/how-to-use-generics-in-mybatis-jsontypehandler

harawata

harawata commented on Sep 13, 2021

@harawata
Member

@wyl0706 There will be a new comment when/if there is any news. :)

half-dead

half-dead commented on Sep 29, 2022

@half-dead

@harawata any update on this issue?

FlyInWind1

FlyInWind1 commented on Nov 26, 2022

@FlyInWind1
Contributor

I am trying to work on this https://github.com/FlyInWind1/mybatis-3

FlyInWind1

FlyInWind1 commented on Dec 7, 2022

@FlyInWind1
Contributor

I have impl ListTypeHandler. I pass ResolvedType (wrap jackson JavaType) to TypeHandler, instead of Class.
link https://github.com/FlyInWind1/mybatis-3
And this is my mybatis-plus https://github.com/FlyInWind1/mybatis-plus

bunnyblueair

bunnyblueair commented on Mar 23, 2023

@bunnyblueair

any update on this issue?

gr0l

gr0l commented on Oct 23, 2023

@gr0l

Any updates on this issue?

la3rence

la3rence commented on Apr 26, 2024

@la3rence

Any update on this?

Jasonyou-boy

Jasonyou-boy commented on May 18, 2024

@Jasonyou-boy

Is there any update?I had the same problem

Vzhangs

Vzhangs commented on Jul 27, 2024

@Vzhangs

Any updates on this? I want to create a common List TypeHandler for a PostgreSQL composite type array column. But it might not be possible to implement it without getting the actualTypeArguments.

harawata

harawata commented on Jan 3, 2025

@harawata
Member

Hi all,

I have submitted #3379 .
It's still "draft", but I would appreciate if you could test your own usage against #3379 .
If you found a problem, please create/share a test case.

self-assigned this
on Mar 15, 2025
added this to the 3.6.x milestone on Mar 15, 2025
harawata

harawata commented on Mar 15, 2025

@harawata
Member

#3379 is merged.

Please test 3.6.0-SNAPSHOT with your apps and give us feedback.
There have been A LOT of other changes as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @harawata@half-dead@wyl0706@DavidTangWei@la3rence

      Issue actions

        TypeHandler lost information of actualTypeArguments when class is ParameterizedType · Issue #2187 · mybatis/mybatis-3