diff --git a/src/main/java/org/apache/ibatis/annotations/Many.java b/src/main/java/org/apache/ibatis/annotations/Many.java index 800acb3f071..564809a0870 100644 --- a/src/main/java/org/apache/ibatis/annotations/Many.java +++ b/src/main/java/org/apache/ibatis/annotations/Many.java @@ -33,6 +33,13 @@ @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Many { + /** + * Returns the result map id used to map collection. + * + * @return the result map id + */ + String resultMap() default ""; + /** * Returns the statement id that retrieves collection. * diff --git a/src/main/java/org/apache/ibatis/annotations/One.java b/src/main/java/org/apache/ibatis/annotations/One.java index 7ca298afa42..e2b27143f93 100644 --- a/src/main/java/org/apache/ibatis/annotations/One.java +++ b/src/main/java/org/apache/ibatis/annotations/One.java @@ -33,6 +33,13 @@ @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface One { + /** + * Returns the result map id used to map single object. + * + * @return the result map id + */ + String resultMap() default ""; + /** * Returns the statement id that retrieves single object. * diff --git a/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java b/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java index 20b14e69557..2af92659c0f 100644 --- a/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java +++ b/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java @@ -552,7 +552,7 @@ private void applyResults(Result[] results, Class resultType, List resultType, List 0 && result.many().resultMap().length() > 0) { + throw new BuilderException("Cannot use both @One and @Many annotations in the same @Result"); + } + return result.one().resultMap().length() > 0 || result.many().resultMap().length() > 0; + } + private String nestedSelectId(Result result) { String nestedSelect = result.one().select(); if (nestedSelect.length() < 1) { diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/CreateDB.sql b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/CreateDB.sql new file mode 100644 index 00000000000..c6841bdbc0d --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/CreateDB.sql @@ -0,0 +1,77 @@ +-- +-- Copyright 2009-2019 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +-- ---------------------------- +-- Table structure for role +-- ---------------------------- +CREATE TABLE role ( +id int, +role_name varchar(10) +); + +-- ---------------------------- +-- Records of role +-- ---------------------------- +INSERT INTO role (id,role_name) +VALUES ('1', 'teacher'); +INSERT INTO role (id,role_name) +VALUES ('2', 'student'); +INSERT INTO role (id,role_name) +VALUES ('3', 'Headmaster'); +INSERT INTO role (id,role_name) +VALUES ('4', 'Learning-commissary'); + +CREATE TABLE user ( +id int, +username varchar(32), +); + +-- ---------------------------- +-- Records of user +-- ---------------------------- +INSERT INTO user (id,username) +VALUES ('1', 'James Gosling'); +INSERT INTO user (id,username) +VALUES ('2', 'Doug Lea'); +INSERT INTO user (id,username) +VALUES ('3', 'Rod johnson'); +INSERT INTO user (id,username) +VALUES ('4', 'Juergen Hoeller'); + +-- ---------------------------- +-- Table structure for `user_role` +-- ---------------------------- +CREATE TABLE user_role ( + id int, + role_id int, + user_id int +); + +-- ---------------------------- +-- Records of user_role +-- ---------------------------- +INSERT INTO user_role (id,role_id,user_id) +VALUES ('1', '2', '4'); +INSERT INTO user_role (id,role_id,user_id) +VALUES ('2', '3', '1'); +INSERT INTO user_role (id,role_id,user_id) +VALUES ('3', '1', '2'); +INSERT INTO user_role (id,role_id,user_id) +VALUES ('4', '2', '3'); +INSERT INTO user_role (id,role_id,user_id) +VALUES ('5', '4', '4'); +INSERT INTO user_role (id,role_id,user_id) +VALUES ('6', '1', '1'); diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/OneManyResultMapTest.java b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/OneManyResultMapTest.java new file mode 100644 index 00000000000..623f9876d8c --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/OneManyResultMapTest.java @@ -0,0 +1,93 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.annotion_many_one_add_resultmapid; + +import org.apache.ibatis.BaseDataTest; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.Reader; +import java.util.List; + +class OneManyResultMapTest { + + private static SqlSessionFactory sqlSessionFactory; + + @BeforeAll + static void setUp() throws Exception { + // create an SqlSessionFactory + try (Reader reader = Resources + .getResourceAsReader("org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/SqlMapConfig.xml")) { + sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); + } + + // populate in-memory database + BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), + "org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/CreateDB.sql"); + } + + @Test + void shouldUseResultMapWithMany() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + UserDao mapper = sqlSession.getMapper(UserDao.class); + List users = mapper.findAll(); + assertNotNull(users); + assertEquals(4, users.size()); + assertEquals(2, users.get(0).getRoles().size()); + } + } + + @Test + void shouldUseResultMapInXmlWithMany() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + UserDao mapper = sqlSession.getMapper(UserDao.class); + List users = mapper.findAll2(); + assertNotNull(users); + assertEquals(4, users.size()); + assertEquals(2, users.get(0).getRoles().size()); + } + } + + @Test + void shouldUseResultMapWithOne() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + UserDao mapper = sqlSession.getMapper(UserDao.class); + List users = mapper.findAll3(); + assertNotNull(users); + assertEquals(2, users.size()); + assertNotNull(users.get(0).getRole()); + assertEquals("teacher", users.get(0).getRole().getRoleName()); + } + } + + @Test + void shouldResolveResultMapInTheSameNamespace() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + UserDao mapper = sqlSession.getMapper(UserDao.class); + User headmaster = mapper.findHeadmaster(); + assertNotNull(headmaster); + assertEquals(3, headmaster.getTeachers().size()); + assertEquals("Doug Lea", headmaster.getTeachers().get(0).getUsername()); + } + } + +} diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/Role.java b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/Role.java new file mode 100644 index 00000000000..8cfd2eb091f --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/Role.java @@ -0,0 +1,46 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.annotion_many_one_add_resultmapid; + +public class Role { + private Integer id; + + @Override + public String toString() { + return "Role{" + + "id=" + id + + ", roleName='" + roleName + '\'' + + '}'; + } + + private String roleName; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } +} diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/RoleDao.java b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/RoleDao.java new file mode 100644 index 00000000000..dbed8568347 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/RoleDao.java @@ -0,0 +1,34 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.annotion_many_one_add_resultmapid; + +import org.apache.ibatis.annotations.Result; +import org.apache.ibatis.annotations.Results; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * @author lvyang + */ +public interface RoleDao { + @Select("select * from role") + @Results(id = "roleMap1", value = { + @Result(id = true, column = "role_id", property = "id"), + @Result(column = "role_name", property = "roleName") + }) + public List findAll(); +} diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/RoleDao.xml b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/RoleDao.xml new file mode 100644 index 00000000000..3b748d6afa2 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/RoleDao.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/SqlMapConfig.xml b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/SqlMapConfig.xml new file mode 100644 index 00000000000..277b1872fe8 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/SqlMapConfig.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/User.java b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/User.java new file mode 100644 index 00000000000..835bca7a612 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/User.java @@ -0,0 +1,75 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.annotion_many_one_add_resultmapid; + +import java.util.List; + +public class User { + private Integer id; + private String username; + private List teachers; + private Role role; + private List roles; + + public Role getRole() { + return role; + } + + public void setRole(Role role) { + this.role = role; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", username='" + username + '\'' + + ", roles=" + roles + + '}'; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public List getTeachers() { + return teachers; + } + + public void setTeachers(List teachers) { + this.teachers = teachers; + } +} diff --git a/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/UserDao.java b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/UserDao.java new file mode 100644 index 00000000000..af3266771e7 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/annotion_many_one_add_resultmapid/UserDao.java @@ -0,0 +1,83 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.annotion_many_one_add_resultmapid; + +import org.apache.ibatis.annotations.*; + +import java.util.List; + +/** + * @author lvyang + */ +public interface UserDao { + @Select({ "select", + " u.id, u.username, r.id role_id, r.role_name", + " from user u", + " left join user_role ur on u.id = ur.user_id", + " left join role r on ur.role_id = r.id" }) + @Results({ + @Result(id = true, column = "id", property = "id"), + @Result(column = "username", property = "username"), + @Result(property = "roles", many = @Many(resultMap = "org.apache.ibatis.submitted.annotion_many_one_add_resultmapid.RoleDao.roleMap1")) + }) + public List findAll(); + + @Select({ "select", + " u.id, u.username, r.id role_id, r.role_name", + " from user u", + " left join user_role ur on u.id = ur.user_id", + " left join role r on ur.role_id = r.id" }) + @Results({ + @Result(id = true, column = "id", property = "id"), + @Result(column = "username", property = "username"), + @Result(property = "roles", many = @Many(resultMap = "org.apache.ibatis.submitted.annotion_many_one_add_resultmapid.RoleDao.roleMap2")) + }) + public List findAll2(); + + @Select({ "select", + " u.id, u.username, r.id role_id, r.role_name", + " from user u", + " left join user_role ur on u.id = ur.user_id", + " left join role r on ur.role_id = r.id where u.id in (2, 3)" }) + @Results({ + @Result(id = true, column = "id", property = "id"), + @Result(column = "username", property = "username"), + @Result(property = "role", one = @One(resultMap = "org.apache.ibatis.submitted.annotion_many_one_add_resultmapid.RoleDao.roleMap2")) + }) + public List findAll3(); + + @Select("select id teacher_id, username teacher_name from user") + @Results(id = "userMap", value = { + @Result(id = true, column = "teacher_id", property = "id"), + @Result(column = "teacher_name", property = "username") + }) + public List justUseResult(); + + @Select({ "select", + "u.id, u.username, r.id role_id, r.role_name, ut.id teacher_id, ut.username teacher_name", + "from user u", + "left join user_role ur on u.id = ur.user_id", + "left join role r on ur.role_id = r.id", + "left join user ut on ut.id != u.id", + "where role_id = 3" }) + @Results({ + @Result(id = true, column = "id", property = "id"), + @Result(column = "username", property = "username"), + @Result(property = "role", one = @One(resultMap = "org.apache.ibatis.submitted.annotion_many_one_add_resultmapid.RoleDao.roleMap2")), + @Result(property = "teachers", many = @Many(resultMap = "userMap")) + }) + public User findHeadmaster(); +}