Map.Entry和Map.entrySet()的集合上的MyBatis错误 [英] MyBatis Error on Collection of Map.Entry and Map.entrySet()
问题描述
; select id =testSelectparameterType =mapresultType =Integer>
从double选择1,其中
< foreach collection =propertiesindex =indexitem =itemseparator =and>
1 =#{id} AND'a'=#{item.key,jdbcType = VARCHAR} AND'b'=#{item.value,jdbcType = VARCHAR}
< / foreach>
< / select>
(应该简单的返回1,如果给定的id为1,该集合是a和所有值b)
...这使得一个简单的 TestMapper
接口方法...
整数testSelect(Map< String,Object>参数);
...我们使用此测试方法测试...
@Test
public void test_for_bug(){
final Map< String,Object> parameters = new HashMap<>();
parameters.put(id,1);
final Map< String,String> entries = new HashMap<>();
entries.put(a,b);
parameters.put(properties,entries.entrySet());
final整数结果= this.testMapper.testSelect(parameters);
assertThat(result).isEqualTo(1);
}
...我们会收到以下错误...
属性
'__frch_item_0.value'的参数映射类型处理程序为空。没有指定和/或不能为指定的javaType / jdbcType组合找到
。
这似乎是调用 item.value
导致String本身的值
属性的调用。不幸的是,我不知道为什么。
将 entries.entrySet()
替换为集合
定制条目
对象(含键
和值
属性) 工作正常。也奇怪的是:这只是在一个< collection>
中发生,直接作为一个参数给出一个 Map.Entry
,如...
< select id =testSelectparameterType =mapresultType =Integer>
从double选择1,其中'b'=#{entry.value,jdbcType = VARCHAR}
< / select>
...和...
@Test
public void test_for_bug(){
final Map< String,String> entries = new HashMap<>();
entries.put(a,b);
final Map< String,Object> parameters = new HashMap<>();
parameters.put(entry,entries.entrySet()。iterator()。next());
final整数结果= this.testMapper.testSelect(parameters);
assertThat(result).isEqualTo(1);
}
...工作。
$ b $有没有人知道Map.EntrySet的问题在这里?有机会得到它固定不知何故?当然,创建一个解决方法很简单,但是不应该需要它。看起来正确的方法来处理这个(已经提交的文档更新)如下(由于开发人员在几个版本之前进行了一些更改):
< select id =testSelectparameterType =mapresultType =Integer>
从double选择1,其中
< foreach collection =propertiesindex =indexitem =itemseparator =and>
1 =#{id} AND'a'=#{index,jdbcType = VARCHAR} AND'b'=#{item,jdbcType = VARCHAR}
< / foreach>
< / select>
原因是,< foreach>
Iterables
/ 数组
和地图
(和 Iteratable< Map.Entry>
对象):
- code> Iterable 或
Array
,index
是当前迭代的编号和项目
是在此迭代中从Iterable检索的元素。 - 对于
Map
(或Iterable< Map.Entry>
)index
是当前条目的关键字,项目是当前条目的价值
这就解释了为什么 item.value
for Map< String,String>
实际上导致 String.value
( value
已经是一个 String
- 它有一个私人的 char数组
称为值
,所以MyBatis试图访问 String.value
并且失败,因为 char数组
不是映射类型)。
assuming we have MyBatis 3.3.0 and MyBatis-Spring 1.2.3 and a simple select query...
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where
<foreach collection="properties" index="index" item="item" separator=" and ">
1 = #{id} AND 'a' = #{item.key,jdbcType=VARCHAR} AND 'b' = #{item.value,jdbcType=VARCHAR}
</foreach>
</select>
(should simple return 1, if the id given is 1 and all key properties given in the collection are "a" and all values "b")
...which makes a simple TestMapper
interface method...
Integer testSelect(Map<String, Object> arguments);
...and we test it with this test method...
@Test
public void test_for_bug() {
final Map<String, Object> parameters = new HashMap<>();
parameters.put("id", 1);
final Map<String, String> entries = new HashMap<>();
entries.put("a", "b");
parameters.put("properties", entries.entrySet());
final Integer result = this.testMapper.testSelect(parameters);
assertThat(result).isEqualTo(1);
}
...we will get the following error....
Type handler was null on parameter mapping for property '__frch_item_0.value'. It was either not specified and/or could not be found for the javaType / jdbcType combination specified.
The reason for that seems to be that the call to item.value
results in a call of the value
property of the String itself. Unfortunately, I have no clue, why.
Replacing the entries.entrySet()
with a Collection
of custom Entry
objects (with key
and value
property) works fine. Also strange: This only seems to happen inside a <collection>
, giving a Map.Entry
directly as a parameter, like...
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where 'b' = #{entry.value,jdbcType=VARCHAR}
</select>
...and...
@Test
public void test_for_bug() {
final Map<String, String> entries = new HashMap<>();
entries.put("a", "b");
final Map<String, Object> parameters = new HashMap<>();
parameters.put("entry", entries.entrySet().iterator().next());
final Integer result = this.testMapper.testSelect(parameters);
assertThat(result).isEqualTo(1);
}
...works.
Has anyone an idea what the problem with Map.EntrySet is here? Any chance to get it fixed somehow? Of course creating a workaround is easy enough, but imho it should not be needed.
Seems that the correct way to handle this (documentation update already submitted) is the following (since the developers made some changes a few versions ago):
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where
<foreach collection="properties" index="index" item="item" separator=" and ">
1 = #{id} AND 'a' = #{index,jdbcType=VARCHAR} AND 'b' = #{item,jdbcType=VARCHAR}
</foreach>
</select>
The reason is, that <foreach>
behaves a little bit different for Iterables
/Arrays
and Maps
(and Iteratable<Map.Entry>
Objects):
- For an
Iterable
orArray
,index
is the number of the current iteration anditem
is the element retrieved from the Iterable in this iteration. - For a
Map
(orIterable<Map.Entry>
)index
is the current entry's key and item is the current entry'svalue
This explains why item.value
for a Map<String, String>
leads actually to String.value
(the value
is already a String
- which has a private char array
member called value
, so MyBatis is trying to access String.value
- and fails, because a char array
is not a mapped type).
这篇关于Map.Entry和Map.entrySet()的集合上的MyBatis错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!