Skip to content

Commit fa95122

Browse files
authored
Merge pull request #1389 from harawata/complex-mapper-resolution
Improve complex mapper element resolution
2 parents 8800351 + f96dd27 commit fa95122

26 files changed

+949
-13
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.apache.ibatis.binding.BindingException;
6363
import org.apache.ibatis.binding.MapperMethod.ParamMap;
6464
import org.apache.ibatis.builder.BuilderException;
65+
import org.apache.ibatis.builder.CacheRefResolver;
6566
import org.apache.ibatis.builder.IncompleteElementException;
6667
import org.apache.ibatis.builder.MapperBuilderAssistant;
6768
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
@@ -217,7 +218,11 @@ private void parseCacheRef() {
217218
throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef");
218219
}
219220
String namespace = (refType != void.class) ? refType.getName() : refName;
220-
assistant.useCacheRef(namespace);
221+
try {
222+
assistant.useCacheRef(namespace);
223+
} catch (IncompleteElementException e) {
224+
configuration.addIncompleteCacheRef(new CacheRefResolver(assistant, namespace));
225+
}
221226
}
222227
}
223228

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

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Collection;
2020
import java.util.HashMap;
2121
import java.util.HashSet;
22+
import java.util.Iterator;
2223
import java.util.LinkedList;
2324
import java.util.List;
2425
import java.util.Map;
@@ -27,6 +28,7 @@
2728

2829
import org.apache.ibatis.binding.MapperRegistry;
2930
import org.apache.ibatis.builder.CacheRefResolver;
31+
import org.apache.ibatis.builder.IncompleteElementException;
3032
import org.apache.ibatis.builder.ResultMapResolver;
3133
import org.apache.ibatis.builder.annotation.MethodResolver;
3234
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
@@ -770,28 +772,53 @@ public void addCacheRef(String namespace, String referencedNamespace) {
770772
* statement validation.
771773
*/
772774
protected void buildAllStatements() {
773-
if (!incompleteResultMaps.isEmpty()) {
774-
synchronized (incompleteResultMaps) {
775-
// This always throws a BuilderException.
776-
incompleteResultMaps.iterator().next().resolve();
777-
}
778-
}
775+
parsePendingResultMaps();
779776
if (!incompleteCacheRefs.isEmpty()) {
780777
synchronized (incompleteCacheRefs) {
781-
// This always throws a BuilderException.
782-
incompleteCacheRefs.iterator().next().resolveCacheRef();
778+
incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
783779
}
784780
}
785781
if (!incompleteStatements.isEmpty()) {
786782
synchronized (incompleteStatements) {
787-
// This always throws a BuilderException.
788-
incompleteStatements.iterator().next().parseStatementNode();
783+
incompleteStatements.removeIf(x -> {
784+
x.parseStatementNode();
785+
return true;
786+
});
789787
}
790788
}
791789
if (!incompleteMethods.isEmpty()) {
792790
synchronized (incompleteMethods) {
793-
// This always throws a BuilderException.
794-
incompleteMethods.iterator().next().resolve();
791+
incompleteMethods.removeIf(x -> {
792+
x.resolve();
793+
return true;
794+
});
795+
}
796+
}
797+
}
798+
799+
private void parsePendingResultMaps() {
800+
if (incompleteResultMaps.isEmpty()) {
801+
return;
802+
}
803+
synchronized (incompleteResultMaps) {
804+
boolean resolved;
805+
IncompleteElementException ex = null;
806+
do {
807+
resolved = false;
808+
Iterator<ResultMapResolver> iterator = incompleteResultMaps.iterator();
809+
while (iterator.hasNext()) {
810+
try {
811+
iterator.next().resolve();
812+
iterator.remove();
813+
resolved = true;
814+
} catch (IncompleteElementException e) {
815+
ex = e;
816+
}
817+
}
818+
} while (resolved);
819+
if (!incompleteResultMaps.isEmpty() && ex != null) {
820+
// At least one result map is unresolvable.
821+
throw ex;
795822
}
796823
}
797824
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--
2+
-- Copyright 2009-2018 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+
-- 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 users if exists;
18+
19+
create table users (
20+
id int,
21+
name varchar(20)
22+
);
23+
24+
insert into users (id, name) values
25+
(1, 'User1'),
26+
(2, 'User2');
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright 2009-2018 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+
* 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.resolution;
17+
18+
import java.io.Serializable;
19+
20+
public class User implements Serializable {
21+
private static final long serialVersionUID = 1L;
22+
private Integer id;
23+
private String name;
24+
25+
public Integer getId() {
26+
return id;
27+
}
28+
29+
public void setId(Integer id) {
30+
this.id = id;
31+
}
32+
33+
public String getName() {
34+
return name;
35+
}
36+
37+
public void setName(String name) {
38+
this.name = name;
39+
}
40+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright 2009-2018 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+
* 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.resolution.cachereffromxml;
17+
18+
import java.io.Reader;
19+
20+
import org.apache.ibatis.BaseDataTest;
21+
import org.apache.ibatis.io.Resources;
22+
import org.apache.ibatis.session.SqlSession;
23+
import org.apache.ibatis.session.SqlSessionFactory;
24+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
25+
import org.apache.ibatis.submitted.resolution.User;
26+
import org.junit.Assert;
27+
import org.junit.BeforeClass;
28+
import org.junit.Test;
29+
30+
public class CacheRefFromXmlTest {
31+
32+
private static SqlSessionFactory sqlSessionFactory;
33+
34+
@BeforeClass
35+
public static void setUp() throws Exception {
36+
// create an SqlSessionFactory
37+
try (Reader reader = Resources
38+
.getResourceAsReader("org/apache/ibatis/submitted/resolution/cachereffromxml/mybatis-config.xml")) {
39+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
40+
}
41+
42+
// populate in-memory database
43+
BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
44+
"org/apache/ibatis/submitted/resolution/CreateDB.sql");
45+
}
46+
47+
@Test
48+
public void shouldGetAUser() {
49+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
50+
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
51+
User user = mapper.getUser(1);
52+
Assert.assertEquals(Integer.valueOf(1), user.getId());
53+
Assert.assertEquals("User1", user.getName());
54+
}
55+
}
56+
57+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Copyright 2009-2018 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+
* 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.resolution.cachereffromxml;
17+
18+
import org.apache.ibatis.annotations.CacheNamespace;
19+
import org.apache.ibatis.submitted.resolution.User;
20+
21+
@CacheNamespace
22+
public interface UserMapper {
23+
User getUser(Integer id);
24+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2009-2018 the original author or authors.
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
24+
namespace="org.apache.ibatis.submitted.resolution.cachereffromxml.UserMapper">
25+
26+
<cache-ref
27+
namespace="org.apache.ibatis.submitted.resolution.cachereffromxml.UserMapper" />
28+
29+
<select id="getUser"
30+
resultType="org.apache.ibatis.submitted.resolution.User">
31+
select *
32+
from users where id = #{id}
33+
</select>
34+
35+
</mapper>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!--
3+
4+
Copyright 2009-2018 the original author or authors.
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 configuration
20+
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
21+
"http://mybatis.org/dtd/mybatis-3-config.dtd">
22+
23+
<configuration>
24+
25+
<environments default="development">
26+
<environment id="development">
27+
<transactionManager type="JDBC">
28+
<property name="" value="" />
29+
</transactionManager>
30+
<dataSource type="UNPOOLED">
31+
<property name="driver" value="org.hsqldb.jdbcDriver" />
32+
<property name="url"
33+
value="jdbc:hsqldb:mem:cachereffromxml" />
34+
<property name="username" value="sa" />
35+
</dataSource>
36+
</environment>
37+
</environments>
38+
39+
<mappers>
40+
<mapper
41+
class="org.apache.ibatis.submitted.resolution.cachereffromxml.UserMapper" />
42+
</mappers>
43+
44+
</configuration>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright 2009-2018 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+
* 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.resolution.cacherefs;
17+
18+
import java.io.Reader;
19+
20+
import org.apache.ibatis.BaseDataTest;
21+
import org.apache.ibatis.io.Resources;
22+
import org.apache.ibatis.session.SqlSession;
23+
import org.apache.ibatis.session.SqlSessionFactory;
24+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
25+
import org.apache.ibatis.submitted.resolution.User;
26+
import org.junit.Assert;
27+
import org.junit.BeforeClass;
28+
import org.junit.Test;
29+
30+
public class CacheRefsTest {
31+
32+
private static SqlSessionFactory sqlSessionFactory;
33+
34+
@BeforeClass
35+
public static void setUp() throws Exception {
36+
// create an SqlSessionFactory
37+
try (Reader reader = Resources
38+
.getResourceAsReader("org/apache/ibatis/submitted/resolution/cacherefs/mybatis-config.xml")) {
39+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
40+
}
41+
42+
// populate in-memory database
43+
BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
44+
"org/apache/ibatis/submitted/resolution/CreateDB.sql");
45+
}
46+
47+
@Test
48+
public void shouldGetAUser() {
49+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
50+
MapperB mapper = sqlSession.getMapper(MapperB.class);
51+
User user = mapper.getUser(1);
52+
Assert.assertEquals(Integer.valueOf(1), user.getId());
53+
Assert.assertEquals("User1", user.getName());
54+
}
55+
}
56+
57+
}

0 commit comments

Comments
 (0)