Closed
Description
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