Skip to content

Commit c29ce33

Browse files
committed
Fix IndexOutOfBoundsException
1 parent 884da7a commit c29ce33

File tree

10 files changed

+525
-0
lines changed

10 files changed

+525
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,14 @@ private Object applyConstructorAutomapping(ResultSetWrapper rsw, ResultMap resul
783783
private boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw, List<Class<?>> constructorArgTypes,
784784
List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues) throws SQLException {
785785
Class<?>[] parameterTypes = constructor.getParameterTypes();
786+
787+
// constructor parameter is allowed to be less than or equal to the number of result set columns, but not greater than
788+
if (parameterTypes.length > rsw.getClassNames().size()) {
789+
throw new ExecutorException(MessageFormat.format(
790+
"Column order based constructor auto-mapping of ''{0}'' failed. Because result set type is ''{1}''.",
791+
constructor, rsw.getClassNames()));
792+
}
793+
786794
for (int i = 0; i < parameterTypes.length; i++) {
787795
Class<?> parameterType = parameterTypes[i];
788796
String columnName = rsw.getColumnNames().get(i);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2009-2024 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+
package org.apache.ibatis.submitted.column_order_based_constructor_automapping;
17+
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertNotNull;
20+
import static org.junit.jupiter.api.Assertions.assertNull;
21+
import static org.junit.jupiter.api.Assertions.assertThrows;
22+
import static org.junit.jupiter.api.Assertions.assertTrue;
23+
import java.io.Reader;
24+
import java.util.List;
25+
import org.apache.ibatis.BaseDataTest;
26+
import org.apache.ibatis.exceptions.PersistenceException;
27+
import org.apache.ibatis.io.Resources;
28+
import org.apache.ibatis.session.SqlSession;
29+
import org.apache.ibatis.session.SqlSessionFactory;
30+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
31+
import org.junit.jupiter.api.BeforeAll;
32+
import org.junit.jupiter.api.Test;
33+
34+
class ColumnOrderBasedConstructorAutomappingTest {
35+
36+
private static SqlSessionFactory sqlSessionFactory;
37+
38+
@BeforeAll
39+
static void setUp() throws Exception {
40+
// create an SqlSessionFactory
41+
try (Reader reader = Resources.getResourceAsReader(
42+
"org/apache/ibatis/submitted/column_order_based_constructor_automapping/mybatis-config.xml")) {
43+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
44+
sqlSessionFactory.getConfiguration().setArgNameBasedConstructorAutoMapping(false);
45+
}
46+
47+
// populate in-memory database
48+
BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
49+
"org/apache/ibatis/submitted/column_order_based_constructor_automapping/CreateDB.sql");
50+
}
51+
52+
@Test
53+
void shouldHandleNoArgsConstructor() {
54+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
55+
Mapper mapper = sqlSession.getMapper(Mapper.class);
56+
List<UserNoArgsConstructor> userList = mapper.finaAllByNoArgsConstructor();
57+
58+
assertEquals(2, userList.size());
59+
UserNoArgsConstructor user1 = userList.get(0);
60+
UserNoArgsConstructor user2 = userList.get(1);
61+
62+
assertEquals(1, user1.getId());
63+
assertEquals("Tom", user1.getName());
64+
assertEquals(7, user1.getAge());
65+
assertNull(user1.getEmail());
66+
67+
assertEquals(2, user2.getId());
68+
assertEquals("Cat", user2.getName());
69+
assertEquals(3, user2.getAge());
70+
assertNull(user2.getEmail());
71+
}
72+
}
73+
74+
@Test
75+
void shouldHandleConstructorEqualsResultSet() {
76+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
77+
Mapper mapper = sqlSession.getMapper(Mapper.class);
78+
List<UserConstructorEqualsResultSet> userList = mapper.finaAllByConstructorEqualsResultSet();
79+
80+
assertEquals(2, userList.size());
81+
UserConstructorEqualsResultSet user1 = userList.get(0);
82+
UserConstructorEqualsResultSet user2 = userList.get(1);
83+
84+
assertEquals(1, user1.getId());
85+
assertEquals("Tom", user1.getName());
86+
assertEquals(7, user1.getAge());
87+
assertNull(user1.getEmail());
88+
89+
assertEquals(2, user2.getId());
90+
assertEquals("Cat", user2.getName());
91+
assertEquals(3, user2.getAge());
92+
assertNull(user2.getEmail());
93+
}
94+
}
95+
96+
@Test
97+
void shouldHandleConstructorLessThanResultSet() {
98+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
99+
Mapper mapper = sqlSession.getMapper(Mapper.class);
100+
List<UserConstructorLessThanResultSet> userList = mapper.finaAllByConstructorLessThanResultSet();
101+
102+
assertEquals(2, userList.size());
103+
UserConstructorLessThanResultSet user1 = userList.get(0);
104+
UserConstructorLessThanResultSet user2 = userList.get(1);
105+
106+
assertEquals(1, user1.getId());
107+
assertEquals("Tom", user1.getName());
108+
assertEquals(7, user1.getAge());
109+
assertNull(user1.getEmail());
110+
111+
assertEquals(2, user2.getId());
112+
assertEquals("Cat", user2.getName());
113+
assertEquals(3, user2.getAge());
114+
assertNull(user2.getEmail());
115+
}
116+
}
117+
118+
@Test
119+
void shouldNotHandleConstructorGreaterThanResultSet() {
120+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
121+
Mapper mapper = sqlSession.getMapper(Mapper.class);
122+
123+
PersistenceException persistenceException = assertThrows(PersistenceException.class, mapper::finaAllByConstructorGreaterThanResultSet);
124+
assertNotNull(persistenceException);
125+
assertNotNull(persistenceException.getMessage());
126+
assertTrue(persistenceException.getMessage().contains("Column order based constructor auto-mapping of"));
127+
}
128+
}
129+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2009-2024 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+
package org.apache.ibatis.submitted.column_order_based_constructor_automapping;
17+
18+
import java.util.List;
19+
20+
public interface Mapper {
21+
22+
List<UserNoArgsConstructor> finaAllByNoArgsConstructor();
23+
24+
List<UserConstructorEqualsResultSet> finaAllByConstructorEqualsResultSet();
25+
26+
List<UserConstructorLessThanResultSet> finaAllByConstructorLessThanResultSet();
27+
28+
List<UserConstructorGreaterThanResultSet> finaAllByConstructorGreaterThanResultSet();
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2009-2024 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+
package org.apache.ibatis.submitted.column_order_based_constructor_automapping;
17+
18+
public class UserConstructorEqualsResultSet {
19+
20+
private Integer id;
21+
private String name;
22+
private Integer age;
23+
private String email;
24+
25+
public UserConstructorEqualsResultSet(Integer id, String name, Integer age) {
26+
this.id = id;
27+
this.name = name;
28+
this.age = age;
29+
}
30+
31+
public Integer getId() {
32+
return id;
33+
}
34+
35+
public void setId(Integer id) {
36+
this.id = id;
37+
}
38+
39+
public String getName() {
40+
return name;
41+
}
42+
43+
public void setName(String name) {
44+
this.name = name;
45+
}
46+
47+
public Integer getAge() {
48+
return age;
49+
}
50+
51+
public void setAge(Integer age) {
52+
this.age = age;
53+
}
54+
55+
public String getEmail() {
56+
return email;
57+
}
58+
59+
public void setEmail(String email) {
60+
this.email = email;
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2009-2024 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+
package org.apache.ibatis.submitted.column_order_based_constructor_automapping;
17+
18+
public class UserConstructorGreaterThanResultSet {
19+
20+
private Integer id;
21+
private String name;
22+
private Integer age;
23+
private String email;
24+
25+
public UserConstructorGreaterThanResultSet(Integer id, String name, Integer age, String email) {
26+
this.id = id;
27+
this.name = name;
28+
this.age = age;
29+
this.email = email;
30+
}
31+
32+
public Integer getId() {
33+
return id;
34+
}
35+
36+
public void setId(Integer id) {
37+
this.id = id;
38+
}
39+
40+
public String getName() {
41+
return name;
42+
}
43+
44+
public void setName(String name) {
45+
this.name = name;
46+
}
47+
48+
public Integer getAge() {
49+
return age;
50+
}
51+
52+
public void setAge(Integer age) {
53+
this.age = age;
54+
}
55+
56+
public String getEmail() {
57+
return email;
58+
}
59+
60+
public void setEmail(String email) {
61+
this.email = email;
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2009-2024 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+
package org.apache.ibatis.submitted.column_order_based_constructor_automapping;
17+
18+
public class UserConstructorLessThanResultSet {
19+
20+
private Integer id;
21+
private String name;
22+
private Integer age;
23+
private String email;
24+
25+
public UserConstructorLessThanResultSet(Integer id, String name) {
26+
this.id = id;
27+
this.name = name;
28+
}
29+
30+
public Integer getId() {
31+
return id;
32+
}
33+
34+
public void setId(Integer id) {
35+
this.id = id;
36+
}
37+
38+
public String getName() {
39+
return name;
40+
}
41+
42+
public void setName(String name) {
43+
this.name = name;
44+
}
45+
46+
public Integer getAge() {
47+
return age;
48+
}
49+
50+
public void setAge(Integer age) {
51+
this.age = age;
52+
}
53+
54+
public String getEmail() {
55+
return email;
56+
}
57+
58+
public void setEmail(String email) {
59+
this.email = email;
60+
}
61+
}

0 commit comments

Comments
 (0)