Skip to content

Commit 50afa69

Browse files
committed
Added selectMap functionality for selecting Maps of results keyed by a property
1 parent 37915c4 commit 50afa69

File tree

10 files changed

+156
-12
lines changed

10 files changed

+156
-12
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.apache.ibatis.annotations;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.METHOD)
10+
public @interface MapKey {
11+
12+
String value();
13+
14+
}

src/main/java/org/apache/ibatis/binding/MapperMethod.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.List;
77
import java.util.Map;
88

9+
import org.apache.ibatis.annotations.MapKey;
910
import org.apache.ibatis.annotations.Param;
1011
import org.apache.ibatis.mapping.MappedStatement;
1112
import org.apache.ibatis.mapping.SqlCommandType;
@@ -25,6 +26,8 @@ public class MapperMethod {
2526
private Method method;
2627

2728
private boolean returnsList;
29+
private boolean returnsMap;
30+
private String mapKey;
2831

2932
private Integer rowBoundsIndex;
3033
private List<String> paramNames;
@@ -60,6 +63,8 @@ public Object execute(Object[] args) {
6063
} else if (SqlCommandType.SELECT == type) {
6164
if (returnsList) {
6265
result = executeForList(args);
66+
} else if (returnsMap) {
67+
result = executeForMap(args);
6368
} else {
6469
Object param = getParam(args);
6570
result = sqlSession.selectOne(commandName, param);
@@ -70,19 +75,30 @@ public Object execute(Object[] args) {
7075
return result;
7176
}
7277

73-
private Object executeForList(Object[] args) {
74-
Object result;
78+
private List executeForList(Object[] args) {
79+
List result;
80+
Object param = getParam(args);
7581
if (rowBoundsIndex != null) {
76-
Object param = getParam(args);
7782
RowBounds rowBounds = (RowBounds) args[rowBoundsIndex];
7883
result = sqlSession.selectList(commandName, param, rowBounds);
7984
} else {
80-
Object param = getParam(args);
8185
result = sqlSession.selectList(commandName, param);
8286
}
8387
return result;
8488
}
8589

90+
private Map executeForMap(Object[] args) {
91+
Map result;
92+
Object param = getParam(args);
93+
if (rowBoundsIndex != null) {
94+
RowBounds rowBounds = (RowBounds) args[rowBoundsIndex];
95+
result = sqlSession.selectMap(commandName, param, mapKey, rowBounds);
96+
} else {
97+
result = sqlSession.selectMap(commandName, param, mapKey);
98+
}
99+
return result;
100+
}
101+
86102
private Object getParam(Object[] args) {
87103
final int paramCount = paramPositions.size();
88104
if (args == null || paramCount == 0) {
@@ -108,6 +124,14 @@ private void setupMethodSignature() {
108124
if (List.class.isAssignableFrom(method.getReturnType())) {
109125
returnsList = true;
110126
}
127+
if (Map.class.isAssignableFrom(method.getReturnType())) {
128+
final MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
129+
if (mapKeyAnnotation != null) {
130+
mapKey = mapKeyAnnotation.value();
131+
returnsMap = true;
132+
}
133+
}
134+
111135
final Class<?>[] argTypes = method.getParameterTypes();
112136
for (int i = 0; i < argTypes.length; i++) {
113137
if (RowBounds.class.isAssignableFrom(argTypes[i])) {

src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,19 @@ private Class<?> getReturnType(Method method) {
278278
}
279279
}
280280
}
281+
} else if (Map.class.isAssignableFrom(returnType)) {
282+
Type returnTypeParameter = method.getGenericReturnType();
283+
if (returnTypeParameter instanceof ParameterizedType) {
284+
Type[] actualTypeArguments = ((ParameterizedType) returnTypeParameter).getActualTypeArguments();
285+
if (actualTypeArguments != null && actualTypeArguments.length == 2) {
286+
returnTypeParameter = actualTypeArguments[1];
287+
if (returnTypeParameter instanceof Class) {
288+
returnType = (Class<?>) returnTypeParameter;
289+
}
290+
}
291+
}
281292
}
293+
282294
return returnType;
283295
}
284296

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.apache.ibatis.executor.result;
2+
3+
import org.apache.ibatis.reflection.MetaObject;
4+
import org.apache.ibatis.session.ResultContext;
5+
import org.apache.ibatis.session.ResultHandler;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
public class DefaultMapResultHandler implements ResultHandler {
11+
12+
private final Map mappedResults = new HashMap();
13+
private final String mapKey;
14+
15+
public DefaultMapResultHandler(String mapKey) {
16+
this.mapKey = mapKey;
17+
}
18+
19+
public void handleResult(ResultContext context) {
20+
final Object value = context.getResultObject();
21+
final MetaObject mo = MetaObject.forObject(value);
22+
final Object key = mo.getValue(mapKey);
23+
mappedResults.put(key, value);
24+
}
25+
26+
public Map getMappedResults() {
27+
return mappedResults;
28+
}
29+
}

src/main/java/org/apache/ibatis/session/SqlSession.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.sql.Connection;
44
import java.util.List;
5+
import java.util.Map;
56

67
public interface SqlSession {
78

@@ -15,6 +16,12 @@ public interface SqlSession {
1516

1617
List selectList(String statement, Object parameter, RowBounds rowBounds);
1718

19+
Map selectMap(String statement, String mapKey);
20+
21+
Map selectMap(String statement, Object parameter, String mapKey);
22+
23+
Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
24+
1825
void select(String statement, Object parameter, ResultHandler handler);
1926

2027
void select(String statement, ResultHandler handler);

src/main/java/org/apache/ibatis/session/SqlSessionManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.lang.reflect.Proxy;
99
import java.sql.Connection;
1010
import java.util.List;
11+
import java.util.Map;
1112
import java.util.Properties;
1213

1314
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
@@ -121,6 +122,18 @@ public Object selectOne(String statement, Object parameter) {
121122
return sqlSessionProxy.selectOne(statement, parameter);
122123
}
123124

125+
public Map selectMap(String statement, String mapKey) {
126+
return sqlSessionProxy.selectMap(statement, mapKey);
127+
}
128+
129+
public Map selectMap(String statement, Object parameter, String mapKey) {
130+
return sqlSessionProxy.selectMap(statement, parameter, mapKey);
131+
}
132+
133+
public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
134+
return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
135+
}
136+
124137
public List selectList(String statement) {
125138
return sqlSessionProxy.selectList(statement);
126139
}

src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.apache.ibatis.exceptions.TooManyResultsException;
55
import org.apache.ibatis.executor.Executor;
66
import org.apache.ibatis.executor.ErrorContext;
7+
import org.apache.ibatis.executor.result.DefaultMapResultHandler;
78
import org.apache.ibatis.mapping.MappedStatement;
89
import org.apache.ibatis.session.Configuration;
910
import org.apache.ibatis.session.ResultHandler;
@@ -13,6 +14,7 @@
1314
import java.sql.Connection;
1415
import java.util.HashMap;
1516
import java.util.List;
17+
import java.util.Map;
1618

1719
public class DefaultSqlSession implements SqlSession {
1820

@@ -45,6 +47,20 @@ public Object selectOne(String statement, Object parameter) {
4547
}
4648
}
4749

50+
public Map selectMap(String statement, String mapKey) {
51+
return selectMap(statement, null, mapKey, RowBounds.DEFAULT);
52+
}
53+
54+
public Map selectMap(String statement, Object parameter, String mapKey) {
55+
return selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
56+
}
57+
58+
public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
59+
final DefaultMapResultHandler mapResultHandler = new DefaultMapResultHandler(mapKey);
60+
select(statement, parameter, rowBounds, mapResultHandler);
61+
return mapResultHandler.getMappedResults();
62+
}
63+
4864
public List selectList(String statement) {
4965
return selectList(statement, null);
5066
}

src/test/java/org/apache/ibatis/binding/BindingTest.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
import org.junit.BeforeClass;
99
import org.junit.Test;
1010

11-
import java.util.ArrayList;
12-
import java.util.HashMap;
13-
import java.util.List;
14-
import java.util.Map;
11+
import java.util.*;
1512

1613
public class BindingTest {
1714
private static SqlSessionFactory sqlSessionFactory;
@@ -122,6 +119,21 @@ public void shouldExecuteBoundSelectListOfBlogsStatement() {
122119
}
123120
}
124121

122+
@Test
123+
public void shouldExecuteBoundSelectMapOfBlogsById() {
124+
SqlSession session = sqlSessionFactory.openSession();
125+
try {
126+
BoundBlogMapper mapper = session.getMapper(BoundBlogMapper.class);
127+
Map<Integer,Blog> blogs = mapper.selectBlogsAsMapById();
128+
assertEquals(2, blogs.size());
129+
for(Map.Entry<Integer,Blog> blogEntry : blogs.entrySet()) {
130+
assertEquals(blogEntry.getKey(), blogEntry.getValue().getId());
131+
}
132+
} finally {
133+
session.close();
134+
}
135+
}
136+
125137
@Test
126138
public void shouldSelectListOfBlogsUsingXMLConfig() {
127139
SqlSession session = sqlSessionFactory.openSession();

src/test/java/org/apache/ibatis/binding/BoundBlogMapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ public interface BoundBlogMapper {
2222

2323
//======================================================
2424

25+
@Select({ "SELECT * FROM blog"})
26+
@MapKey("id")
27+
Map<Integer,Blog> selectBlogsAsMapById();
28+
29+
//======================================================
30+
2531
@Select({
2632
"SELECT *",
2733
"FROM blog"

src/test/java/org/apache/ibatis/session/SqlSessionTest.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
import org.junit.Test;
1212

1313
import java.io.Reader;
14-
import java.util.ArrayList;
15-
import java.util.HashMap;
16-
import java.util.List;
17-
import java.util.Map;
14+
import java.util.*;
1815

1916
public class SqlSessionTest extends BaseDataTest {
2017
private static SqlSessionFactory sqlMapper;
@@ -100,6 +97,20 @@ public void shouldSelectAllAuthors() throws Exception {
10097
}
10198
}
10299

100+
@Test
101+
public void shouldSelectAllAuthorsAsMap() throws Exception {
102+
SqlSession session = sqlMapper.openSession(TransactionIsolationLevel.SERIALIZABLE);
103+
try {
104+
final Map<Integer,Author> authors = session.selectMap("domain.blog.mappers.AuthorMapper.selectAllAuthors", "id");
105+
assertEquals(2, authors.size());
106+
for(Map.Entry<Integer,Author> authorEntry : authors.entrySet()) {
107+
assertEquals(authorEntry.getKey(), authorEntry.getValue().getId());
108+
}
109+
} finally {
110+
session.close();
111+
}
112+
}
113+
103114
@Test
104115
public void shouldSelectCountOfPosts() throws Exception {
105116
SqlSession session = sqlMapper.openSession();

0 commit comments

Comments
 (0)