View Javadoc
1   /*
2    *    Copyright 2009-2023 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.sptests;
17  
18  import static org.junit.jupiter.api.Assertions.assertEquals;
19  import static org.junit.jupiter.api.Assertions.assertNotNull;
20  import static org.junit.jupiter.api.Assertions.assertNull;
21  
22  import java.io.Reader;
23  import java.sql.Array;
24  import java.sql.SQLException;
25  import java.util.Date;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.apache.ibatis.BaseDataTest;
31  import org.apache.ibatis.io.Resources;
32  import org.apache.ibatis.jdbc.ScriptRunner;
33  import org.apache.ibatis.session.SqlSession;
34  import org.apache.ibatis.session.SqlSessionFactory;
35  import org.apache.ibatis.session.SqlSessionFactoryBuilder;
36  import org.junit.jupiter.api.BeforeAll;
37  import org.junit.jupiter.api.Test;
38  
39  class SPTest {
40    private static SqlSessionFactory sqlSessionFactory;
41  
42    @BeforeAll
43    static void initDatabase() throws Exception {
44      try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/sptests/MapperConfig.xml")) {
45        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
46      }
47  
48      ScriptRunner runner = new ScriptRunner(
49          sqlSessionFactory.getConfiguration().getEnvironment().getDataSource().getConnection());
50      runner.setDelimiter("go");
51      runner.setLogWriter(null);
52      runner.setErrorLogWriter(null);
53      BaseDataTest.runScript(runner, "org/apache/ibatis/submitted/sptests/CreateDB.sql");
54    }
55  
56    /**
57     * This test shows how to use input and output parameters in a stored procedure. This procedure does not return a
58     * result set.
59     * <p>
60     * This test shows using a multi-property parameter.
61     */
62    @Test
63    void testAdderAsSelect() {
64      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
65        Parameter parameter = new Parameter();
66        parameter.setAddend1(2);
67        parameter.setAddend2(3);
68  
69        SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
70        spMapper.adderAsSelect(parameter);
71  
72        assertEquals((Integer) 5, parameter.getSum());
73      }
74    }
75  
76    /**
77     * This test shows how to use input and output parameters in a stored procedure. This procedure does not return a
78     * result set.
79     * <p>
80     * This test shows using a multi-property parameter.
81     */
82    @Test
83    void testAdderAsSelectDoubleCall1() {
84      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
85        Parameter parameter = new Parameter();
86        parameter.setAddend1(2);
87        parameter.setAddend2(3);
88  
89        SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
90  
91        spMapper.adderAsSelect(parameter);
92        assertEquals((Integer) 5, parameter.getSum());
93  
94        parameter = new Parameter();
95        parameter.setAddend1(2);
96        parameter.setAddend2(3);
97        spMapper.adderAsSelect(parameter);
98        assertEquals((Integer) 5, parameter.getSum());
99      }
100   }
101 
102   /**
103    * This test shows how to use input and output parameters in a stored procedure. This procedure does not return a
104    * result set. This test also demonstrates session level cache for output parameters.
105    * <p>
106    * This test shows using a multi-property parameter.
107    */
108   @Test
109   void testAdderAsSelectDoubleCall2() {
110     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
111       Parameter parameter = new Parameter();
112       parameter.setAddend1(2);
113       parameter.setAddend2(3);
114 
115       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
116 
117       spMapper.adderAsSelect(parameter);
118       assertEquals((Integer) 5, parameter.getSum());
119 
120       parameter = new Parameter();
121       parameter.setAddend1(4);
122       parameter.setAddend2(5);
123       spMapper.adderAsSelect(parameter);
124       assertEquals((Integer) 9, parameter.getSum());
125     }
126   }
127 
128   /**
129    * This test shows how to call a stored procedure defined as <update> rather then <select>. Of course, this only works
130    * if you are not returning a result set.
131    * <p>
132    * This test shows using a multi-property parameter.
133    */
134   @Test
135   void testAdderAsUpdate() {
136     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
137       Parameter parameter = new Parameter();
138       parameter.setAddend1(2);
139       parameter.setAddend2(3);
140 
141       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
142 
143       spMapper.adderAsUpdate(parameter);
144       assertEquals((Integer) 5, parameter.getSum());
145 
146       parameter = new Parameter();
147       parameter.setAddend1(2);
148       parameter.setAddend2(3);
149       spMapper.adderAsUpdate(parameter);
150       assertEquals((Integer) 5, parameter.getSum());
151     }
152   }
153 
154   // issue #145
155   @Test
156   void testEchoDate() {
157     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
158       HashMap<String, Object> parameter = new HashMap<>();
159       Date now = new Date();
160       parameter.put("input date", now);
161 
162       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
163       spMapper.echoDate(parameter);
164 
165       java.sql.Date outDate = new java.sql.Date(now.getTime());
166       assertEquals(outDate.toString(), parameter.get("output date").toString());
167     }
168   }
169 
170   /**
171    * This test shows the use of a declared parameter map. We generally prefer inline parameters, because the syntax is
172    * more intuitive (no pesky question marks), but a parameter map will work.
173    */
174   @Test
175   void testAdderAsUpdateWithParameterMap() {
176     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
177       Map<String, Object> parms = new HashMap<>();
178       parms.put("addend1", 3);
179       parms.put("addend2", 4);
180 
181       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
182 
183       spMapper.adderWithParameterMap(parms);
184       assertEquals(7, parms.get("sum"));
185 
186       parms = new HashMap<>();
187       parms.put("addend1", 2);
188       parms.put("addend2", 3);
189       spMapper.adderWithParameterMap(parms);
190       assertEquals(5, parms.get("sum"));
191     }
192   }
193 
194   /**
195    * This test shows how to use an input parameter and return a result set from a stored procedure.
196    * <p>
197    * This test shows using a single value parameter.
198    */
199   @Test
200   void testCallWithResultSet1() {
201     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
202       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
203 
204       Name name = spMapper.getName(1);
205       assertNotNull(name);
206       assertEquals("Wilma", name.getFirstName());
207     }
208   }
209 
210   /**
211    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
212    * <p>
213    * This test shows using a single value parameter.
214    */
215   @Test
216   void testCallWithResultSet2() {
217     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
218       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
219 
220       Map<String, Object> parms = new HashMap<>();
221       parms.put("lowestId", 1);
222       List<Name> names = spMapper.getNames(parms);
223       assertEquals(3, names.size());
224       assertEquals(3, parms.get("totalRows"));
225     }
226   }
227 
228   /**
229    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
230    * <p>
231    * This test shows using a Map parameter.
232    */
233   @Test
234   void testCallWithResultSet3() {
235     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
236       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
237 
238       Map<String, Object> parms = new HashMap<>();
239       parms.put("lowestId", 2);
240       List<Name> names = spMapper.getNames(parms);
241       assertEquals(2, parms.get("totalRows"));
242       assertEquals(2, names.size());
243 
244       parms = new HashMap<>();
245       parms.put("lowestId", 3);
246       names = spMapper.getNames(parms);
247       assertEquals(1, names.size());
248       assertEquals(1, parms.get("totalRows"));
249     }
250   }
251 
252   /**
253    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
254    * <p>
255    * This test shows using a Map parameter.
256    */
257   @Test
258   void testCallWithResultSet4() {
259     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
260       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
261 
262       Map<String, Object> parms = new HashMap<>();
263       parms.put("lowestId", 2);
264       List<Name> names = spMapper.getNames(parms);
265       assertEquals(2, parms.get("totalRows"));
266       assertEquals(2, names.size());
267 
268       parms = new HashMap<>();
269       parms.put("lowestId", 2);
270       names = spMapper.getNames(parms);
271       assertEquals(2, names.size());
272       assertEquals(2, parms.get("totalRows"));
273     }
274   }
275 
276   /**
277    * This test shows how to use the ARRAY JDBC type with MyBatis.
278    *
279    * @throws SQLException
280    */
281   @Test
282   void testGetNamesWithArray() throws SQLException {
283     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
284       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
285 
286       Array array = sqlSession.getConnection().createArrayOf("int", new Integer[] { 1, 2, 5 });
287 
288       Map<String, Object> parms = new HashMap<>();
289       parms.put("ids", array);
290       List<Name> names = spMapper.getNamesWithArray(parms);
291       Object[] returnedIds = (Object[]) parms.get("returnedIds");
292       assertEquals(4, returnedIds.length);
293       assertEquals(3, parms.get("requestedRows"));
294       assertEquals(2, names.size());
295     }
296   }
297 
298   /**
299    * This test shows how to call procedures that return multiple result sets
300    *
301    * @throws SQLException
302    */
303   @Test
304   void testGetNamesAndItems() {
305     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
306       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
307 
308       List<List<?>> results = spMapper.getNamesAndItems();
309       assertEquals(2, results.size());
310       assertEquals(4, results.get(0).size());
311       assertEquals(3, results.get(1).size());
312     }
313   }
314 
315   /**
316    * This test shows how to use input and output parameters in a stored procedure. This procedure does not return a
317    * result set. This test shows using a multi-property parameter.
318    * <p>
319    * This test shows using annotations for stored procedures.
320    */
321   @Test
322   void testAdderAsSelectAnnotated() {
323     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
324       Parameter parameter = new Parameter();
325       parameter.setAddend1(2);
326       parameter.setAddend2(3);
327 
328       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
329       spMapper.adderAsSelectAnnotated(parameter);
330 
331       assertEquals((Integer) 5, parameter.getSum());
332     }
333   }
334 
335   /**
336    * This test shows how to use input and output parameters in a stored procedure. This procedure does not return a
337    * result set. This test shows using a multi-property parameter.
338    * <p>
339    * This test shows using annotations for stored procedures.
340    */
341   @Test
342   void testAdderAsSelectDoubleCallAnnotated1() {
343     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
344       Parameter parameter = new Parameter();
345       parameter.setAddend1(2);
346       parameter.setAddend2(3);
347 
348       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
349 
350       spMapper.adderAsSelectAnnotated(parameter);
351       assertEquals((Integer) 5, parameter.getSum());
352 
353       parameter = new Parameter();
354       parameter.setAddend1(2);
355       parameter.setAddend2(3);
356       spMapper.adderAsSelectAnnotated(parameter);
357       assertEquals((Integer) 5, parameter.getSum());
358     }
359   }
360 
361   /**
362    * This test shows how to use input and output parameters in a stored procedure. This procedure does not return a
363    * result set.
364    * <p>
365    * This test also demonstrates session level cache for output parameters.
366    * <p>
367    * This test shows using a multi-property parameter.
368    * <p>
369    * This test shows using annotations for stored procedures.
370    */
371   @Test
372   void testAdderAsSelectDoubleCallAnnotated2() {
373     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
374       Parameter parameter = new Parameter();
375       parameter.setAddend1(2);
376       parameter.setAddend2(3);
377 
378       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
379 
380       spMapper.adderAsSelectAnnotated(parameter);
381       assertEquals((Integer) 5, parameter.getSum());
382 
383       parameter = new Parameter();
384       parameter.setAddend1(4);
385       parameter.setAddend2(5);
386       spMapper.adderAsSelectAnnotated(parameter);
387       assertEquals((Integer) 9, parameter.getSum());
388     }
389   }
390 
391   /**
392    * This test shows how to call a stored procedure defined as <update> rather then <select>. Of course, this only works
393    * if you are not returning a result set.
394    * <p>
395    * This test shows using a multi-property parameter.
396    * <p>
397    * This test shows using annotations for stored procedures.
398    */
399   @Test
400   void testAdderAsUpdateAnnotated() {
401     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
402       Parameter parameter = new Parameter();
403       parameter.setAddend1(2);
404       parameter.setAddend2(3);
405 
406       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
407 
408       spMapper.adderAsUpdateAnnotated(parameter);
409       assertEquals((Integer) 5, parameter.getSum());
410 
411       parameter = new Parameter();
412       parameter.setAddend1(2);
413       parameter.setAddend2(3);
414       spMapper.adderAsUpdateAnnotated(parameter);
415       assertEquals((Integer) 5, parameter.getSum());
416     }
417   }
418 
419   /**
420    * This test shows how to use an input parameter and return a result set from a stored procedure.
421    * <p>
422    * This test shows using a single value parameter.
423    * <p>
424    * This test shows using annotations for stored procedures.
425    */
426   @Test
427   void testCallWithResultSet1Annotated() {
428     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
429       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
430 
431       Name name = spMapper.getNameAnnotated(1);
432       assertNotNull(name);
433       assertEquals("Wilma", name.getFirstName());
434     }
435   }
436 
437   /**
438    * This test shows how to use an input parameter and return a result set from a stored procedure.
439    * <p>
440    * This test shows using a single value parameter.
441    * <p>
442    * This test shows using annotations for stored procedures and using a resultMap in XML.
443    */
444   @Test
445   void testCallWithResultSet1_a2() {
446     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
447       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
448 
449       Name name = spMapper.getNameAnnotatedWithXMLResultMap(1);
450       assertNotNull(name);
451       assertEquals("Wilma", name.getFirstName());
452     }
453   }
454 
455   /**
456    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
457    * <p>
458    * This test shows using a single value parameter.
459    * <p>
460    * This test shows using annotations for stored procedures.
461    */
462   @Test
463   void testCallWithResultSet2_a1() {
464     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
465       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
466 
467       Map<String, Object> parms = new HashMap<>();
468       parms.put("lowestId", 1);
469       List<Name> names = spMapper.getNamesAnnotated(parms);
470       assertEquals(3, names.size());
471       assertEquals(3, parms.get("totalRows"));
472     }
473   }
474 
475   /**
476    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
477    * <p>
478    * This test shows using a single value parameter.
479    * <p>
480    * This test shows using annotations for stored procedures and using a resultMap in XML.
481    */
482   @Test
483   void testCallWithResultSet2_a2() {
484     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
485       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
486 
487       Map<String, Object> parms = new HashMap<>();
488       parms.put("lowestId", 1);
489       List<Name> names = spMapper.getNamesAnnotatedWithXMLResultMap(parms);
490       assertEquals(3, names.size());
491       assertEquals(3, parms.get("totalRows"));
492     }
493   }
494 
495   /**
496    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
497    * <p>
498    * This test shows using a Map parameter.
499    * <p>
500    * This test shows using annotations for stored procedures.
501    */
502   @Test
503   void testCallWithResultSet3_a1() {
504     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
505       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
506 
507       Map<String, Object> parms = new HashMap<>();
508       parms.put("lowestId", 2);
509       List<Name> names = spMapper.getNamesAnnotated(parms);
510       assertEquals(2, parms.get("totalRows"));
511       assertEquals(2, names.size());
512 
513       parms = new HashMap<>();
514       parms.put("lowestId", 3);
515       names = spMapper.getNamesAnnotated(parms);
516       assertEquals(1, names.size());
517       assertEquals(1, parms.get("totalRows"));
518     }
519   }
520 
521   /**
522    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
523    * <p>
524    * This test shows using a Map parameter.
525    * <p>
526    * This test shows using annotations for stored procedures and using a resultMap in XML.
527    */
528   @Test
529   void testCallWithResultSet3_a2() {
530     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
531       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
532 
533       Map<String, Object> parms = new HashMap<>();
534       parms.put("lowestId", 2);
535       List<Name> names = spMapper.getNamesAnnotatedWithXMLResultMap(parms);
536       assertEquals(2, parms.get("totalRows"));
537       assertEquals(2, names.size());
538 
539       parms = new HashMap<>();
540       parms.put("lowestId", 3);
541       names = spMapper.getNamesAnnotatedWithXMLResultMap(parms);
542       assertEquals(1, names.size());
543       assertEquals(1, parms.get("totalRows"));
544     }
545   }
546 
547   /**
548    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
549    * <p>
550    * This test shows using a Map parameter.
551    * <p>
552    * This test shows using annotations for stored procedures.
553    */
554   @Test
555   void testCallWithResultSet4_a1() {
556     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
557       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
558 
559       Map<String, Object> parms = new HashMap<>();
560       parms.put("lowestId", 2);
561       List<Name> names = spMapper.getNamesAnnotated(parms);
562       assertEquals(2, parms.get("totalRows"));
563       assertEquals(2, names.size());
564 
565       parms = new HashMap<>();
566       parms.put("lowestId", 2);
567       names = spMapper.getNamesAnnotated(parms);
568       assertEquals(2, names.size());
569       assertEquals(2, parms.get("totalRows"));
570     }
571   }
572 
573   /**
574    * This test shows how to use an input and output parameters and return a result set from a stored procedure.
575    * <p>
576    * This test shows using a Map parameter.
577    * <p>
578    * This test shows using annotations for stored procedures and using a resultMap in XML.
579    */
580   @Test
581   void testCallWithResultSet4_a2() {
582     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
583       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
584 
585       Map<String, Object> parms = new HashMap<>();
586       parms.put("lowestId", 2);
587       List<Name> names = spMapper.getNamesAnnotatedWithXMLResultMap(parms);
588       assertEquals(2, parms.get("totalRows"));
589       assertEquals(2, names.size());
590 
591       parms = new HashMap<>();
592       parms.put("lowestId", 2);
593       names = spMapper.getNamesAnnotatedWithXMLResultMap(parms);
594       assertEquals(2, names.size());
595       assertEquals(2, parms.get("totalRows"));
596     }
597   }
598 
599   /**
600    * This test shows using a two named parameters.
601    * <p>
602    * This test shows using annotations for stored procedures and using a resultMap in XML
603    */
604   @Test
605   void testCallLowHighWithResultSet() {
606     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
607       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
608       List<Name> names = spMapper.getNamesAnnotatedLowHighWithXMLResultMap(1, 1);
609       assertEquals(1, names.size());
610     }
611   }
612 
613   /**
614    * This test shows how to use the ARRAY JDBC type with MyBatis.
615    * <p>
616    * This test shows using annotations for stored procedures.
617    *
618    * @throws SQLException
619    */
620   @Test
621   void testGetNamesWithArray_a1() throws SQLException {
622     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
623       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
624 
625       Array array = sqlSession.getConnection().createArrayOf("int", new Integer[] { 1, 2, 5 });
626 
627       Map<String, Object> parms = new HashMap<>();
628       parms.put("ids", array);
629       List<Name> names = spMapper.getNamesWithArrayAnnotated(parms);
630       Object[] returnedIds = (Object[]) parms.get("returnedIds");
631       assertEquals(4, returnedIds.length);
632       assertEquals(3, parms.get("requestedRows"));
633       assertEquals(2, names.size());
634     }
635   }
636 
637   /**
638    * This test shows how to use the ARRAY JDBC type with MyBatis.
639    * <p>
640    * This test shows using annotations for stored procedures and using a resultMap in XML.
641    *
642    * @throws SQLException
643    */
644   @Test
645   void testGetNamesWithArray_a2() throws SQLException {
646     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
647       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
648 
649       Array array = sqlSession.getConnection().createArrayOf("int", new Integer[] { 1, 2, 5 });
650 
651       Map<String, Object> parms = new HashMap<>();
652       parms.put("ids", array);
653       List<Name> names = spMapper.getNamesWithArrayAnnotatedWithXMLResultMap(parms);
654       Object[] returnedIds = (Object[]) parms.get("returnedIds");
655       assertEquals(4, returnedIds.length);
656       assertEquals(3, parms.get("requestedRows"));
657       assertEquals(2, names.size());
658     }
659   }
660 
661   /**
662    * This test shows how to call procedures that return multiple result sets.
663    * <p>
664    * This test shows using annotations for stored procedures and referring to multiple resultMaps in XML.
665    *
666    * @throws SQLException
667    */
668   @Test
669   void testGetNamesAndItems_a2() {
670     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
671       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
672 
673       List<List<?>> results = spMapper.getNamesAndItemsAnnotatedWithXMLResultMap();
674       assertEquals(2, results.size());
675       assertEquals(4, results.get(0).size());
676       assertEquals(3, results.get(1).size());
677     }
678   }
679 
680   @Test
681   void testGetNamesAndItems_a3() {
682     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
683       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
684 
685       List<List<?>> results = spMapper.getNamesAndItemsAnnotatedWithXMLResultMapArray();
686       assertEquals(2, results.size());
687       assertEquals(4, results.get(0).size());
688       assertEquals(3, results.get(1).size());
689     }
690   }
691 
692   @Test
693   void testGetNamesAndItemsLinked() {
694     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
695       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
696 
697       List<Name> names = spMapper.getNamesAndItemsLinked();
698       assertEquals(4, names.size());
699       assertEquals(2, names.get(0).getItems().size());
700       assertEquals(1, names.get(1).getItems().size());
701       assertNull(names.get(2).getItems());
702       assertNull(names.get(3).getItems());
703     }
704   }
705 
706   @Test
707   void testGetNamesAndItemsLinkedWithNoMatchingInfo() {
708     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
709       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
710 
711       List<Name> names = spMapper.getNamesAndItemsLinkedById(0);
712       assertEquals(1, names.size());
713       assertEquals(2, names.get(0).getItems().size());
714     }
715   }
716 
717   @Test
718   void testMultipleForeignKeys() {
719     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
720       SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
721       List<Book> books = spMapper.getBookAndGenre();
722       assertEquals("Book1", books.get(0).getName());
723       assertEquals("Genre1", books.get(0).getGenre().getName());
724       assertEquals("Book2", books.get(1).getName());
725       assertEquals("Genre2", books.get(1).getGenre().getName());
726       assertEquals("Book3", books.get(2).getName());
727       assertEquals("Genre1", books.get(2).getGenre().getName());
728     }
729   }
730 }