Skip to content

Commit a38d06c

Browse files
committed
Type handler should be applied to args for nested select
For "composite keys", the behavior changes depending on the existence of `parameterType` When `parameterType` is not specified, parameter values are stored in a `Map` and custom type handler is not used. When `parameterType="User"` is specified, `User` instance is created and properties are set using type handlers. Related to gh-114 For "simple key", `parameterType` is ignored and custom type handler is not used at all. I can think of some corner cases caused by these behaviors, but will deal with them when/if they come up.
1 parent 881cf64 commit a38d06c

File tree

5 files changed

+95
-5
lines changed

5 files changed

+95
-5
lines changed

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,21 +1087,23 @@ private Object prepareParameterForNestedQuery(ResultSetWrapper rsw, ResultMappin
10871087

10881088
private Object prepareSimpleKeyParameter(ResultSetWrapper rsw, ResultMapping resultMapping, Class<?> parameterType,
10891089
String columnPrefix) throws SQLException {
1090+
// parameterType is ignored in this case
10901091
final String columnName = prependPrefix(resultMapping.getColumn(), columnPrefix);
10911092
final TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
10921093
return typeHandler.getResult(rsw.getResultSet(), columnName);
10931094
}
10941095

10951096
private Object prepareCompositeKeyParameter(ResultSetWrapper rsw, ResultMapping resultMapping, Class<?> parameterType,
10961097
String columnPrefix) throws SQLException {
1098+
// Map is used if parameterType is not specified
10971099
final Object parameterObject = instantiateParameterObject(parameterType);
10981100
final MetaObject metaObject = configuration.newMetaObject(parameterObject);
10991101
boolean foundValues = false;
11001102
for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
1101-
final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
1102-
final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
1103-
final Object propValue = typeHandler.getResult(rsw.getResultSet(),
1104-
prependPrefix(innerResultMapping.getColumn(), columnPrefix));
1103+
final String columnName = prependPrefix(innerResultMapping.getColumn(), columnPrefix);
1104+
final TypeHandler<?> typeHandler = resolvePropertyTypeHandler(rsw, metaObject, innerResultMapping.getColumn(),
1105+
columnPrefix);
1106+
final Object propValue = typeHandler.getResult(rsw.getResultSet(), columnName);
11051107
// issue #353 & #560 do not execute nested query if key is null
11061108
if (propValue != null) {
11071109
metaObject.setValue(innerResultMapping.getProperty(), propValue);

src/test/java/org/apache/ibatis/submitted/typebasedtypehandlerresolution/GloballyRegisteredHandlerMapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@ public interface GloballyRegisteredHandlerMapper {
4545

4646
@Select("select id, strvalue, intvalue, strings, integers from users where strvalue = #{p1} and intvalue = #{p2}")
4747
User getUserByFuzzyBeans(FuzzyBean<String> p1, FuzzyBean<Integer> p2);
48+
49+
ParentBean selectNestedUser_SingleParam(Integer id);
50+
51+
ParentBean selectNestedUser_MultiParam(Integer id);
4852
}

src/test/java/org/apache/ibatis/submitted/typebasedtypehandlerresolution/GloballyRegisteredTypeHandlerResolutionTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,22 @@ void shouldHandlerBeAppliedToMultiParams() {
201201
assertEquals(1, user.getId());
202202
}
203203
}
204+
205+
@Test
206+
void shouldHandlerAppliedToNestedSelectSingleParam() {
207+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
208+
GloballyRegisteredHandlerMapper mapper = sqlSession.getMapper(GloballyRegisteredHandlerMapper.class);
209+
ParentBean bean = mapper.selectNestedUser_SingleParam(1);
210+
assertEquals(1, bean.getUser().getId());
211+
}
212+
}
213+
214+
@Test
215+
void shouldHandlerAppliedToNestedSelectMultiParam() {
216+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
217+
GloballyRegisteredHandlerMapper mapper = sqlSession.getMapper(GloballyRegisteredHandlerMapper.class);
218+
ParentBean bean = mapper.selectNestedUser_MultiParam(1);
219+
assertEquals(1, bean.getUser().getId());
220+
}
221+
}
204222
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2009-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.ibatis.submitted.typebasedtypehandlerresolution;
18+
19+
public class ParentBean {
20+
private Integer id;
21+
private User user;
22+
23+
public Integer getId() {
24+
return id;
25+
}
26+
27+
public void setId(Integer id) {
28+
this.id = id;
29+
}
30+
31+
public User getUser() {
32+
return user;
33+
}
34+
35+
public void setUser(User user) {
36+
this.user = user;
37+
}
38+
}

src/test/resources/org/apache/ibatis/submitted/typebasedtypehandlerresolution/GloballyRegisteredHandlerMapper.xml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
4-
Copyright 2009-2022 the original author or authors.
4+
Copyright 2009-2025 the original author or authors.
55
66
Licensed under the Apache License, Version 2.0 (the "License");
77
you may not use this file except in compliance with the License.
@@ -48,4 +48,32 @@
4848
(#{id}, #{strvalue}, #{intvalue}, #{strings}, #{integers})
4949
]]></insert>
5050

51+
<resultMap id="parentBeanRM_SingleParam" type="org.apache.ibatis.submitted.typebasedtypehandlerresolution.ParentBean">
52+
<id property="id" column="id" />
53+
<association property="user" column="strvalue" select="selectUserByStrvalue" />
54+
</resultMap>
55+
56+
<select id="selectNestedUser_SingleParam" resultMap="parentBeanRM_SingleParam">
57+
select id, strvalue, intvalue from users where id = #{id}
58+
</select>
59+
60+
<select id="selectUserByStrvalue" parameterType="org.apache.ibatis.submitted.typebasedtypehandlerresolution.User" resultMap="userRM">
61+
select id, strvalue, intvalue, strings, integers from users
62+
where strvalue = #{strvalue}
63+
</select>
64+
65+
<resultMap id="parentBeanRM_MultiParam" type="org.apache.ibatis.submitted.typebasedtypehandlerresolution.ParentBean">
66+
<id property="id" column="id" />
67+
<association property="user" column="{strvalue=strvalue,intvalue=intvalue}" select="selectUserByStrvalueAndIntvalue" />
68+
</resultMap>
69+
70+
<select id="selectNestedUser_MultiParam" resultMap="parentBeanRM_MultiParam">
71+
select id, strvalue, intvalue from users where id = #{id}
72+
</select>
73+
74+
<select id="selectUserByStrvalueAndIntvalue" parameterType="org.apache.ibatis.submitted.typebasedtypehandlerresolution.User" resultMap="userRM">
75+
select id, strvalue, intvalue, strings, integers from users
76+
where strvalue = #{strvalue} and intvalue = #{intvalue}
77+
</select>
78+
5179
</mapper>

0 commit comments

Comments
 (0)