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
.
```java
//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
Comment From: DavidTangWei
@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!
Comment From: harawata
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.
Comment From: 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
Comment From: harawata
@wyl0706 There will be a new comment when/if there is any news. :)
Comment From: half-dead
@harawata any update on this issue?
Comment From: FlyInWind1
I am trying to work on this https://github.com/FlyInWind1/mybatis-3
Comment From: FlyInWind1
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
Comment From: bunnyblueair
any update on this issue?
Comment From: gr0l
Any updates on this issue?
Comment From: la3rence
Any update on this?
Comment From: Jasonyou-boy
Is there any update?I had the same problem
Comment From: 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.
Comment From: harawata
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.