MyBatis version
mybatis:3.4.6 mybatis-spring-boot-starter:1.3.2
Database vendor and version
mysql:5.7
Test case or example project
git: https://gitee.com/jervain_y/demo-mybatis.git
Steps to reproduce
run testcase
Expected result
when we use @Param
annotation, like this param.field
, that cause my custom TypeHandler
dosen't work
Actual result
this is run log
2019-01-15 14:15:05.393 DEBUG 6460 --- [ main] com.example.demo2.AMapper.updateMyOne : ==> Preparing: update a set demo=? where id = ?
2019-01-15 14:15:05.417 DEBUG 6460 --- [ main] com.example.demo2.AMapper.updateMyOne : ==> Parameters: [](ArrayList), 1(Integer)
expect Parameters: [](String), 1(Integer)
Comment From: kazuki43zoo
@jervainy
In this case, the MyBatis uses the UnknownTypeHandler
. It delegate to a TypeHandler
that associate with actual value type(e.g. ArrayList
).
Therefore, you can resolve this issue by specify the @MappedTypes
on the ListTypeHandler
as follow:
@MappedTypes({List.class, ArrayList.class})
public class ListTypeHandler extends BaseTypeHandler<List> {
// ...
}
Please try above solution.
Comment From: jervainy
@kazuki43zoo List
is the parent class of ArrayList
. Why do I need to declare ArrayList
in MappedTypes
? Sometimes I define a List
or Map
variable. I don't know the specific type of it.
Comment From: kazuki43zoo
@jervainy
Why do I need to declare ArrayList in MappedTypes?
In current implementation, the MyBatis does not support for searching a TypeHandler
that associate with interface (NOTE: Can be search a TypeHander
that associate with super class) when use together with @Param
.
@harawata
Is better consider to support for searching a TypeHandler
that associate with interface?
Comment From: harawata
I don't think so.
The posted type handler would not support other List
implementations like LinkedList
(note that ObjectMapper creates an ArrayList).
TypeHandler has to know the concrete type to instantiate a result.
Comment From: jervainy
Most of the time we declare variables based on interfaces. We can't accurately determine their specific type during the run. A List
may be ArrayList
, LinkList
or a list we define. If we declare all the variables in MappedType
, the code will not be so elegant.
Comment From: harawata
I think I misunderstood @kazuki43zoo 's comment. Let me check.
Comment From: harawata
Hi all,
I'm sorry for a late reply. My conclusion is that the problem (it seems more like a limitation rather than a bug) is in the property type resolution during the parsing phase, and type handler resolution works as expected.
To map type handler, MyBatis has to know the type of the property.
For a parameter, MyBatis first tries to resolve the property type in the parsing phase.
This resolution, however, is not very thorough and the property type is not correctly resolved in some cases.
It is usually not a problem because type resolution is performed again using the actual parameter instance.
In this case, however, the actual property type is different (e.g. ArrayList
, etc.) and the ListTypeHandler
which is registered against List
is not returned.
This would explain why adding ArrayList
to @MappedType
resolves the problem.
And specifying type handler explicitly in the parameter expression should work as well (e.g. #{a.demo,typeHandler=....ListTypeHandler}
).
The test in a portable form is here, but I won't be able to work on it anytime soon (it's a corner case with workarounds, so the priority is low).