Skip to content

Commit 0177ac1

Browse files
committed
fix for http://code.google.com/p/mybatis/issues/detail?id=506 . Resolve the type inside a Collection Object
1 parent 7dba125 commit 0177ac1

File tree

8 files changed

+348
-5
lines changed

8 files changed

+348
-5
lines changed

src/main/java/org/apache/ibatis/reflection/MetaClass.java

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@
1515
*/
1616
package org.apache.ibatis.reflection;
1717

18+
import java.lang.reflect.Field;
19+
import java.lang.reflect.Method;
20+
import java.lang.reflect.ParameterizedType;
21+
import java.lang.reflect.Type;
22+
import java.util.Collection;
23+
24+
import org.apache.ibatis.reflection.invoker.GetFieldInvoker;
1825
import org.apache.ibatis.reflection.invoker.Invoker;
26+
import org.apache.ibatis.reflection.invoker.MethodInvoker;
1927
import org.apache.ibatis.reflection.property.PropertyTokenizer;
2028

2129
public class MetaClass {
@@ -69,11 +77,55 @@ public Class<?> getSetterType(String name) {
6977
public Class<?> getGetterType(String name) {
7078
PropertyTokenizer prop = new PropertyTokenizer(name);
7179
if (prop.hasNext()) {
72-
MetaClass metaProp = metaClassForProperty(prop.getName());
80+
MetaClass metaProp = metaClassForProperty(prop);
7381
return metaProp.getGetterType(prop.getChildren());
7482
} else {
75-
return reflector.getGetterType(prop.getName());
83+
return getGetterType(prop); // issue #506. Resolve the type inside a Collection Object
84+
}
85+
}
86+
87+
private MetaClass metaClassForProperty(PropertyTokenizer prop) {
88+
Class<?> propType = getGetterType(prop);
89+
return MetaClass.forClass(propType);
90+
}
91+
92+
private Class<?> getGetterType(PropertyTokenizer prop) {
93+
Class<?> type = reflector.getGetterType(prop.getName());
94+
if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
95+
Type returnType = getGenericGetterType(prop.getName());
96+
if (returnType instanceof ParameterizedType) {
97+
Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
98+
if (actualTypeArguments != null && actualTypeArguments.length == 1) {
99+
returnType = actualTypeArguments[0];
100+
if (returnType instanceof Class) {
101+
type = (Class<?>) returnType;
102+
} else if (returnType instanceof ParameterizedType) {
103+
type = (Class<?>) ((ParameterizedType) returnType).getRawType();
104+
}
105+
}
106+
}
107+
}
108+
return type;
109+
}
110+
111+
private Type getGenericGetterType(String propertyName) {
112+
try {
113+
Invoker invoker = reflector.getGetInvoker(propertyName);
114+
if (invoker instanceof MethodInvoker) {
115+
Field _method = MethodInvoker.class.getDeclaredField("method");
116+
_method.setAccessible(true);
117+
Method method = (Method) _method.get(invoker);
118+
return method.getGenericReturnType();
119+
} else if (invoker instanceof GetFieldInvoker) {
120+
Field _field = GetFieldInvoker.class.getDeclaredField("field");
121+
_field.setAccessible(true);
122+
Field field = (Field) _field.get(invoker);
123+
return field.getGenericType();
124+
}
125+
} catch (NoSuchFieldException e) {
126+
} catch (IllegalAccessException e) {
76127
}
128+
return null;
77129
}
78130

79131
public boolean hasSetter(String name) {
@@ -94,7 +146,7 @@ public boolean hasGetter(String name) {
94146
PropertyTokenizer prop = new PropertyTokenizer(name);
95147
if (prop.hasNext()) {
96148
if (reflector.hasGetter(prop.getName())) {
97-
MetaClass metaProp = metaClassForProperty(prop.getName());
149+
MetaClass metaProp = metaClassForProperty(prop);
98150
return metaProp.hasGetter(prop.getChildren());
99151
} else {
100152
return false;
@@ -132,5 +184,3 @@ private StringBuilder buildProperty(String name, StringBuilder builder) {
132184
}
133185

134186
}
135-
136-
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2009-2012 The MyBatis Team
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+
* http://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.simplelistparameter;
17+
18+
import java.util.List;
19+
20+
public class Car {
21+
// the result class doesn't need id for further processing
22+
private String name;
23+
private List<String> doors;
24+
25+
public String getName() {
26+
return name;
27+
}
28+
29+
public void setName(String name) {
30+
this.name = name;
31+
}
32+
33+
public List<String> getCarParts() {
34+
return doors;
35+
}
36+
37+
public void setCarParts(List<String> doors) {
38+
this.doors = doors;
39+
}
40+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2009-2012 The MyBatis Team
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+
* http://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.simplelistparameter;
17+
18+
import java.util.List;
19+
20+
import org.apache.ibatis.annotations.Select;
21+
22+
public interface CarMapper {
23+
24+
@Select({ "select id, name from car where doors = #{doors[1]}" })
25+
List<Car> getCar(Car car);
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--
2+
-- Copyright 2009-2012 The MyBatis Team
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+
-- http://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+
drop table car if exists;
18+
19+
create table car (
20+
id int,
21+
name varchar(20),
22+
doors int
23+
);
24+
25+
insert into car (id, name, doors) values(1, 'Audi', 4);
26+
insert into car (id, name, doors) values(2, 'Ford', 4);
27+
insert into car (id, name, doors) values(3, 'Fiat', 4);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2009-2011 The MyBatis Team
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
-->
19+
<!DOCTYPE mapper
20+
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
21+
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
22+
23+
<mapper namespace="org.apache.ibatis.submitted.simplelistparameter.CarMapper">
24+
25+
<resultMap id="carResult" type="Car">
26+
<id column="id" /> <!-- id missing property attribute -->
27+
<result property="name" column="name" />
28+
<collection property="carParts"
29+
column="id"
30+
javaType="ArrayList"
31+
ofType="Part"
32+
select="getCarPartInfo" />
33+
</resultMap>
34+
35+
<resultMap id="partResult" type="Part">
36+
<constructor>
37+
<arg column="name" javaType="String"/>
38+
</constructor>
39+
<id column="partId" /> <!-- id missing property attribute -->
40+
</resultMap>
41+
42+
<select id="getCarsInfo" resultMap="carResult">
43+
SELECT car_id as "id", name
44+
FROM car where car_id=#{id}
45+
</select>
46+
47+
<select id="getCarPartInfo" resultMap="partResult">
48+
SELECT part_id as "partId", name
49+
FROM part where car_id=#{id}
50+
</select>
51+
52+
</mapper>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!--
3+
4+
Copyright 2009-2011 The MyBatis Team
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
-->
19+
20+
<!DOCTYPE configuration
21+
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
22+
"http://mybatis.org/dtd/mybatis-3-config.dtd">
23+
24+
<configuration>
25+
26+
<settings>
27+
<setting name="mapUnderscoreToCamelCase" value="true" />
28+
</settings>
29+
30+
<typeAliases>
31+
<package name="org/apache/ibatis/submitted/simplelistparameter" />
32+
</typeAliases>
33+
34+
<environments default="development">
35+
<environment id="development">
36+
<transactionManager type="JDBC">
37+
<property name="" value="" />
38+
</transactionManager>
39+
<dataSource type="UNPOOLED">
40+
<property name="driver" value="org.hsqldb.jdbcDriver" />
41+
<property name="url" value="jdbc:hsqldb:mem:simplelistparameter" />
42+
<property name="username" value="sa" />
43+
</dataSource>
44+
</environment>
45+
</environments>
46+
47+
<mappers>
48+
<mapper resource="org/apache/ibatis/submitted/simplelistparameter/Map.xml" />
49+
</mappers>
50+
51+
</configuration>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2009-2012 The MyBatis Team
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+
* http://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.simplelistparameter;
17+
18+
public class Part {
19+
20+
private String name;
21+
22+
public Part(String name) {
23+
this.name = name;
24+
}
25+
public String getName() {
26+
return name;
27+
}
28+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2009-2012 The MyBatis Team
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+
* http://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.simplelistparameter;
17+
18+
import java.io.Reader;
19+
import java.sql.Connection;
20+
import java.util.Arrays;
21+
import java.util.List;
22+
23+
import org.apache.ibatis.io.Resources;
24+
import org.apache.ibatis.jdbc.ScriptRunner;
25+
import org.apache.ibatis.session.SqlSession;
26+
import org.apache.ibatis.session.SqlSessionFactory;
27+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
28+
import org.hsqldb.lib.ArraySort;
29+
import org.junit.Assert;
30+
import org.junit.BeforeClass;
31+
import org.junit.Test;
32+
33+
public class SimpleListParameterTest {
34+
35+
private static SqlSessionFactory sqlSessionFactory;
36+
37+
@BeforeClass
38+
public static void setUp() throws Exception {
39+
// create a SqlSessionFactory
40+
Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/simplelistparameter/MapperConfig.xml");
41+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
42+
reader.close();
43+
44+
// populate in-memory database
45+
SqlSession session = sqlSessionFactory.openSession();
46+
Connection conn = session.getConnection();
47+
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/simplelistparameter/CreateDB.sql");
48+
ScriptRunner runner = new ScriptRunner(conn);
49+
runner.setLogWriter(null);
50+
runner.runScript(reader);
51+
reader.close();
52+
session.close();
53+
}
54+
55+
@Test
56+
public void shouldMapResultsWithoutActuallyWritingIdProperties() throws Exception {
57+
SqlSession sqlSession = sqlSessionFactory.openSession();
58+
try {
59+
CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
60+
Car car = new Car();
61+
car.setCarParts(Arrays.asList(new String[] {"2", "4"}));
62+
List<Car> cars = carMapper.getCar(car);
63+
Assert.assertNotNull(cars);
64+
} finally {
65+
sqlSession.close();
66+
}
67+
}
68+
69+
}

0 commit comments

Comments
 (0)