Skip to content

Commit bc53e84

Browse files
committed
mybatis#101: Add test which violates equals contract
- Use identity hashmap to check relations for creations
1 parent e163a91 commit bc53e84

File tree

6 files changed

+215
-2
lines changed

6 files changed

+215
-2
lines changed

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Collection;
2828
import java.util.HashMap;
2929
import java.util.HashSet;
30+
import java.util.IdentityHashMap;
3031
import java.util.List;
3132
import java.util.Locale;
3233
import java.util.Map;
@@ -92,7 +93,7 @@ public class DefaultResultSetHandler implements ResultSetHandler {
9293
private final ReflectorFactory reflectorFactory;
9394

9495
// pending creations property tracker
95-
private final Map<Object, PendingRelation> pendingPccRelations = new HashMap<>();
96+
private final Map<Object, PendingRelation> pendingPccRelations = new IdentityHashMap<>();
9697

9798
// nested resultmaps
9899
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();

src/test/java/org/apache/ibatis/submitted/collection_in_constructor/CollectionInConstructorTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,40 @@ void testImmutableNestedObjects() {
181181
container.getStores());
182182
}
183183
}
184+
185+
@Test
186+
void testImmutableNestedObjectsWithBadEquals() {
187+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
188+
Mapper mapper = sqlSession.getMapper(Mapper.class);
189+
List<Container1> containers = mapper.getContainers();
190+
191+
Container1 expectedContainer1 = new Container1();
192+
expectedContainer1.setNum(1);
193+
expectedContainer1.setType("storesWithClerks");
194+
expectedContainer1.setStores(Arrays.asList(
195+
new Store9(1, "Store 1",
196+
Arrays.asList(new Clerk(1001, "Clerk 1001"), new Clerk(1003, "Clerk 1003"),
197+
new Clerk(1004, "Clerk 1004"))),
198+
new Store9(2, "Store 2", Arrays.asList()), new Store9(3, "Store 3", Arrays.asList())));
199+
200+
Container1 expectedContainer2 = new Container1();
201+
expectedContainer2.setNum(1);
202+
expectedContainer2.setType("storesWithManagers");
203+
expectedContainer2.setStores(Arrays.asList(
204+
new Store9(1, "Store 1", Arrays.asList(new Clerk(1002, "Clerk 1002"), new Clerk(1005, "Clerk 1005")))));
205+
206+
// cannot use direct equals as we overwrote it with a bad impl on purpose
207+
org.assertj.core.api.Assertions.assertThat(containers).isNotNull().hasSize(2);
208+
assertContainer1(containers.get(0), expectedContainer1);
209+
assertContainer1(containers.get(1), expectedContainer2);
210+
}
211+
}
212+
213+
private static void assertContainer1(Container1 container1, Container1 expectedContainer1) {
214+
org.assertj.core.api.Assertions.assertThat(container1).isNotNull().satisfies(c -> {
215+
org.assertj.core.api.Assertions.assertThat(c.getNum()).isEqualTo(expectedContainer1.getNum());
216+
org.assertj.core.api.Assertions.assertThat(c.getType()).isEqualTo(expectedContainer1.getType());
217+
org.assertj.core.api.Assertions.assertThat(c.getStores()).isEqualTo(expectedContainer1.getStores());
218+
});
219+
}
184220
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2009-2024 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+
* https://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+
package org.apache.ibatis.submitted.collection_in_constructor;
18+
19+
import java.util.List;
20+
import java.util.Objects;
21+
22+
public class Container1 {
23+
24+
private Integer num;
25+
private String type;
26+
private List<Store9> stores;
27+
28+
public Integer getNum() {
29+
return num;
30+
}
31+
32+
public void setNum(Integer num) {
33+
this.num = num;
34+
}
35+
36+
public List<Store9> getStores() {
37+
return stores;
38+
}
39+
40+
public void setStores(List<Store9> stores) {
41+
this.stores = stores;
42+
}
43+
44+
public String getType() {
45+
return type;
46+
}
47+
48+
public void setType(String type) {
49+
this.type = type;
50+
}
51+
52+
@Override
53+
// simulate a misbehaving object with a bad equals override
54+
public boolean equals(Object o) {
55+
if (this == o)
56+
return true;
57+
if (o == null || getClass() != o.getClass())
58+
return false;
59+
Container1 that = (Container1) o;
60+
return Objects.equals(num, that.num);
61+
}
62+
63+
@Override
64+
public int hashCode() {
65+
return Objects.hash(num);
66+
}
67+
}

src/test/java/org/apache/ibatis/submitted/collection_in_constructor/Mapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@ public interface Mapper {
3939

4040
Container getAContainer();
4141

42+
List<Container1> getContainers();
43+
4244
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2009-2024 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+
* https://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.collection_in_constructor;
17+
18+
import java.util.List;
19+
import java.util.Objects;
20+
21+
public class Store9 {
22+
23+
private final Integer id;
24+
private final String name;
25+
private final List<Clerk> clerks;
26+
27+
public Store9(Integer id, String name, List<Clerk> clerks) {
28+
this.id = id;
29+
this.name = name;
30+
this.clerks = clerks;
31+
}
32+
33+
public Integer getId() {
34+
return id;
35+
}
36+
37+
public String getName() {
38+
return name;
39+
}
40+
41+
public List<Clerk> getClerks() {
42+
return clerks;
43+
}
44+
45+
@Override
46+
public int hashCode() {
47+
return Objects.hash(id);
48+
}
49+
50+
@Override
51+
public boolean equals(Object obj) {
52+
if (this == obj) {
53+
return true;
54+
}
55+
if (!(obj instanceof Store9)) {
56+
return false;
57+
}
58+
Store9 other = (Store9) obj;
59+
return Objects.equals(id, other.id);
60+
}
61+
62+
@Override
63+
public String toString() {
64+
return "Store9 [id=" + id + ", name=" + name + ", clerks=" + clerks + "]";
65+
}
66+
}

src/test/resources/org/apache/ibatis/submitted/collection_in_constructor/Mapper.xml

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,45 @@
236236
order by s.id, i.id
237237
]]></select>
238238

239-
</mapper>
239+
<resultMap
240+
type="org.apache.ibatis.submitted.collection_in_constructor.Clerk"
241+
id="immutableClerkRM">
242+
<constructor>
243+
<idArg column="id" javaType="int" />
244+
<arg column="name" javaType="string" />
245+
</constructor>
246+
</resultMap>
247+
248+
<resultMap
249+
type="org.apache.ibatis.submitted.collection_in_constructor.Store9"
250+
id="store9RM">
251+
<constructor>
252+
<idArg column="id" javaType="int" />
253+
<arg column="name" javaType="string" />
254+
<arg javaType="list" resultMap="immutableClerkRM" columnPrefix="clerk_" />
255+
</constructor>
256+
</resultMap>
257+
258+
<resultMap
259+
type="org.apache.ibatis.submitted.collection_in_constructor.Container1"
260+
id="container1RM">
261+
<id column="type" property="type"/>
262+
<result column="num" property="num" />
263+
<collection property="stores" resultMap="store9RM"/>
264+
</resultMap>
265+
266+
<select id="getContainers" resultMap="container1RM"
267+
resultOrdered="true"><![CDATA[
268+
select
269+
1 num
270+
, casewhen(c.is_manager, rtrim('storesWithManagers'), rtrim('storesWithClerks')) as type
271+
, s.id
272+
, s.name
273+
, c.id clerk_id
274+
, c.name clerk_name
275+
from store s
276+
left join clerk c on c.store_id = s.id
277+
order by type, s.id, c.id
278+
]]></select>
279+
280+
</mapper>

0 commit comments

Comments
 (0)