diff --git a/src/main/java/org/apache/ibatis/executor/result/DefaultMapResultHandler.java b/src/main/java/org/apache/ibatis/executor/result/DefaultMapResultHandler.java index f2ee92bcc02..1ebdaa143e5 100644 --- a/src/main/java/org/apache/ibatis/executor/result/DefaultMapResultHandler.java +++ b/src/main/java/org/apache/ibatis/executor/result/DefaultMapResultHandler.java @@ -31,26 +31,36 @@ public class DefaultMapResultHandler implements ResultHandler { private final Map mappedResults; private final String mapKey; + private final String mapValue; private final ObjectFactory objectFactory; private final ObjectWrapperFactory objectWrapperFactory; private final ReflectorFactory reflectorFactory; @SuppressWarnings("unchecked") public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, + ReflectorFactory reflectorFactory) { + this(mapKey, null, objectFactory, objectWrapperFactory, reflectorFactory); + } + + @SuppressWarnings("unchecked") + public DefaultMapResultHandler(String mapKey, String mapValue, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; this.reflectorFactory = reflectorFactory; this.mappedResults = objectFactory.create(Map.class); this.mapKey = mapKey; + this.mapValue = mapValue; } @Override - public void handleResult(ResultContext context) { - final V value = context.getResultObject(); - final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory); + public void handleResult(ResultContext context) { + final Object resultObject = context.getResultObject(); + final MetaObject mo = MetaObject.forObject(resultObject, objectFactory, objectWrapperFactory, reflectorFactory); // TODO is that assignment always true? final K key = (K) mo.getValue(mapKey); + // TODO is that assignment always true? + final V value = mapValue == null || mapValue.isEmpty() ? (V) resultObject : (V) mo.getValue(mapValue); mappedResults.put(key, value); } diff --git a/src/main/java/org/apache/ibatis/session/SqlSession.java b/src/main/java/org/apache/ibatis/session/SqlSession.java index bb0f85932dc..299bf0e329b 100644 --- a/src/main/java/org/apache/ibatis/session/SqlSession.java +++ b/src/main/java/org/apache/ibatis/session/SqlSession.java @@ -156,6 +156,69 @@ public interface SqlSession extends Closeable { */ Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); + /** + * The selectMap is a special case in that it is designed to convert a list of results into a Map based on one of the + * properties as key and one of the properties as value in the resulting objects. Eg. Return a Map[Integer,String] + * for selectMap("selectAuthors","id","username") + * + * @param + * the returned Map keys type + * @param + * the returned Map values type + * @param statement + * Unique identifier matching the statement to use. + * @param mapKey + * The property to use as key for each value in the list. + * @param mapValue + * The property to use as value for each key in the list. + * + * @return Map containing key pair data. + */ + Map selectMap(String statement, String mapKey, String mapValue); + + /** + * The selectMap is a special case in that it is designed to convert a list of results into a Map based on one of the + * properties as key and one of the properties as value in the resulting objects. + * + * @param + * the returned Map keys type + * @param + * the returned Map values type + * @param statement + * Unique identifier matching the statement to use. + * @param parameter + * A parameter object to pass to the statement. + * @param mapKey + * The property to use as key for each value in the list. + * @param mapValue + * The property to use as value for each key in the list. + * @return Map containing key pair data. + */ + Map selectMap(String statement, Object parameter, String mapKey, String mapValue); + + /** + * The selectMap is a special case in that it is designed to convert a list of results into a Map based on one of the + * properties as key and one of the properties as value in the resulting objects. + * + * @param + * the returned Map keys type + * @param + * the returned Map values type + * @param statement + * Unique identifier matching the statement to use. + * @param parameter + * A parameter object to pass to the statement. + * @param mapKey + * The property to use as key for each value in the list. + * @param mapValue + * The property to use as value for each key in the list. + * @param rowBounds + * Bounds to limit object retrieval + * + * @return Map containing key pair data. + */ + Map selectMap(String statement, Object parameter, String mapKey, String mapValue, RowBounds rowBounds); + /** * A Cursor offers the same results as a List, except it fetches data lazily using an Iterator. * diff --git a/src/main/java/org/apache/ibatis/session/SqlSessionManager.java b/src/main/java/org/apache/ibatis/session/SqlSessionManager.java index 183aa878f9c..0e6a2c8e87a 100644 --- a/src/main/java/org/apache/ibatis/session/SqlSessionManager.java +++ b/src/main/java/org/apache/ibatis/session/SqlSessionManager.java @@ -179,6 +179,21 @@ public Map selectMap(String statement, Object parameter, String map return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds); } + @Override + public Map selectMap(String statement, String mapKey, String mapValue) { + return sqlSessionProxy.selectMap(statement, mapKey, mapValue); + } + + @Override + public Map selectMap(String statement, Object parameter, String mapKey, String mapValue) { + return sqlSessionProxy.selectMap(statement, parameter, mapKey, mapValue); + } + + @Override + public Map selectMap(String statement, Object parameter, String mapKey, String mapValue, RowBounds rowBounds) { + return sqlSessionProxy.selectMap(statement, parameter, mapKey, mapValue, rowBounds); + } + @Override public Cursor selectCursor(String statement) { return sqlSessionProxy.selectCursor(statement); diff --git a/src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java b/src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java index 62b39becea5..726d0d18d48 100644 --- a/src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java +++ b/src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java @@ -107,6 +107,29 @@ public Map selectMap(String statement, Object parameter, String map return mapResultHandler.getMappedResults(); } + @Override + public Map selectMap(String statement, String mapKey, String mapValue) { + return this.selectMap(statement, null, mapKey, mapValue, RowBounds.DEFAULT); + } + + @Override + public Map selectMap(String statement, Object parameter, String mapKey, String mapValue) { + return this.selectMap(statement, parameter, mapKey, mapValue, RowBounds.DEFAULT); + } + + @Override + public Map selectMap(String statement, Object parameter, String mapKey, String mapValue, RowBounds rowBounds) { + final List list = selectList(statement, parameter, rowBounds); + final DefaultMapResultHandler mapResultHandler = new DefaultMapResultHandler<>(mapKey, mapValue, + configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory()); + final DefaultResultContext context = new DefaultResultContext<>(); + for (Object o : list) { + context.nextResultObject(o); + mapResultHandler.handleResult(context); + } + return mapResultHandler.getMappedResults(); + } + @Override public Cursor selectCursor(String statement) { return selectCursor(statement, null); diff --git a/src/test/java/org/apache/ibatis/session/SqlSessionTest.java b/src/test/java/org/apache/ibatis/session/SqlSessionTest.java index 0b72e1d385e..5ac75a8c7e1 100644 --- a/src/test/java/org/apache/ibatis/session/SqlSessionTest.java +++ b/src/test/java/org/apache/ibatis/session/SqlSessionTest.java @@ -180,6 +180,21 @@ void shouldSelectAllAuthorsAsMap() { } } + @Test + void shouldSelectAllAuthorsAsSpecifiedKeyValueMap() { + try (SqlSession session = sqlMapper.openSession(TransactionIsolationLevel.SERIALIZABLE)) { + final Map authors = session + .selectMap("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAllAuthors", "id"); + final Map authorsMap = session + .selectMap("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAllAuthors", "id", "username"); + assertEquals(2, authorsMap.size()); + for (Map.Entry authorEntry : authorsMap.entrySet()) { + assertEquals(authorEntry.getKey(), authors.get(authorEntry.getKey()).getId()); + assertEquals(authorEntry.getValue(), authors.get(authorEntry.getKey()).getUsername()); + } + } + } + @Test void shouldSelectCountOfPosts() { try (SqlSession session = sqlMapper.openSession()) {