View Javadoc
1   /*
2    *    Copyright 2009-2021 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.keygen;
17  
18  import static com.googlecode.catchexception.apis.BDDCatchException.*;
19  import static org.assertj.core.api.BDDAssertions.then;
20  import static org.junit.jupiter.api.Assertions.*;
21  
22  import java.io.Reader;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.ibatis.BaseDataTest;
32  import org.apache.ibatis.exceptions.PersistenceException;
33  import org.apache.ibatis.io.Resources;
34  import org.apache.ibatis.session.ExecutorType;
35  import org.apache.ibatis.session.SqlSession;
36  import org.apache.ibatis.session.SqlSessionFactory;
37  import org.apache.ibatis.session.SqlSessionFactoryBuilder;
38  import org.junit.jupiter.api.BeforeAll;
39  import org.junit.jupiter.api.Test;
40  
41  /**
42   * @author liuzh
43   */
44  class Jdbc3KeyGeneratorTest {
45  
46    private static SqlSessionFactory sqlSessionFactory;
47  
48    @BeforeAll
49    static void setUp() throws Exception {
50      // create an SqlSessionFactory
51      try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/keygen/MapperConfig.xml")) {
52        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
53      }
54  
55      // populate in-memory database
56      BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
57          "org/apache/ibatis/submitted/keygen/CreateDB.sql");
58    }
59  
60    @Test
61    void shouldAssignKeyToBean() {
62      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
63        try {
64          CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
65          Country country = new Country("China", "CN");
66          mapper.insertBean(country);
67          assertNotNull(country.getId());
68        } finally {
69          sqlSession.rollback();
70        }
71      }
72    }
73  
74    @Test
75    void shouldAssignKeyToBean_batch() {
76      try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
77        try {
78          CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
79          Country country1 = new Country("China", "CN");
80          mapper.insertBean(country1);
81          Country country2 = new Country("Canada", "CA");
82          mapper.insertBean(country2);
83          sqlSession.flushStatements();
84          sqlSession.clearCache();
85          assertNotNull(country1.getId());
86          assertNotNull(country2.getId());
87        } finally {
88          sqlSession.rollback();
89        }
90      }
91    }
92  
93    @Test
94    void shouldAssignKeyToNamedBean() {
95      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
96        try {
97          CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
98          Country country = new Country("China", "CN");
99          mapper.insertNamedBean(country);
100         assertNotNull(country.getId());
101       } finally {
102         sqlSession.rollback();
103       }
104     }
105   }
106 
107   @Test
108   void shouldAssignKeyToNamedBean_batch() {
109     try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
110       try {
111         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
112         Country country1 = new Country("China", "CN");
113         mapper.insertNamedBean(country1);
114         Country country2 = new Country("Canada", "CA");
115         mapper.insertNamedBean(country2);
116         sqlSession.flushStatements();
117         sqlSession.clearCache();
118         assertNotNull(country1.getId());
119         assertNotNull(country2.getId());
120       } finally {
121         sqlSession.rollback();
122       }
123     }
124   }
125 
126   @Test
127   void shouldAssignKeyToNamedBean_keyPropertyWithParamName() {
128     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
129       try {
130         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
131         Country country = new Country("China", "CN");
132         mapper.insertNamedBean_keyPropertyWithParamName(country);
133         assertNotNull(country.getId());
134       } finally {
135         sqlSession.rollback();
136       }
137     }
138   }
139 
140   @Test
141   void shouldAssignKeyToNamedBean_keyPropertyWithParamName_batch() {
142     try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
143       try {
144         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
145         Country country1 = new Country("China", "CN");
146         mapper.insertNamedBean_keyPropertyWithParamName(country1);
147         Country country2 = new Country("Canada", "CA");
148         mapper.insertNamedBean_keyPropertyWithParamName(country2);
149         sqlSession.flushStatements();
150         sqlSession.clearCache();
151         assertNotNull(country1.getId());
152         assertNotNull(country2.getId());
153       } finally {
154         sqlSession.rollback();
155       }
156     }
157   }
158 
159   @Test
160   void shouldAssignKeysToList() {
161     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
162       try {
163         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
164         List<Country> countries = new ArrayList<>();
165         countries.add(new Country("China", "CN"));
166         countries.add(new Country("United Kiongdom", "GB"));
167         countries.add(new Country("United States of America", "US"));
168         mapper.insertList(countries);
169         for (Country country : countries) {
170           assertNotNull(country.getId());
171         }
172       } finally {
173         sqlSession.rollback();
174       }
175     }
176   }
177 
178   @Test
179   void shouldAssignKeysToNamedList() {
180     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
181       try {
182         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
183         List<Country> countries = new ArrayList<>();
184         countries.add(new Country("China", "CN"));
185         countries.add(new Country("United Kiongdom", "GB"));
186         countries.add(new Country("United States of America", "US"));
187         mapper.insertNamedList(countries);
188         for (Country country : countries) {
189           assertNotNull(country.getId());
190         }
191       } finally {
192         sqlSession.rollback();
193       }
194     }
195   }
196 
197   @Test
198   void shouldAssingKeysToCollection() {
199     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
200       try {
201         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
202         Set<Country> countries = new HashSet<>();
203         countries.add(new Country("China", "CN"));
204         countries.add(new Country("United Kiongdom", "GB"));
205         mapper.insertSet(countries);
206         for (Country country : countries) {
207           assertNotNull(country.getId());
208         }
209       } finally {
210         sqlSession.rollback();
211       }
212     }
213   }
214 
215   @Test
216   void shouldAssingKeysToNamedCollection() {
217     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
218       try {
219         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
220         Set<Country> countries = new HashSet<>();
221         countries.add(new Country("China", "CN"));
222         countries.add(new Country("United Kiongdom", "GB"));
223         mapper.insertNamedSet(countries);
224         for (Country country : countries) {
225           assertNotNull(country.getId());
226         }
227       } finally {
228         sqlSession.rollback();
229       }
230     }
231   }
232 
233   @Test
234   void shouldAssingKeysToArray() {
235     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
236       try {
237         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
238         Country[] countries = new Country[2];
239         countries[0] = new Country("China", "CN");
240         countries[1] = new Country("United Kiongdom", "GB");
241         mapper.insertArray(countries);
242         for (Country country : countries) {
243           assertNotNull(country.getId());
244         }
245       } finally {
246         sqlSession.rollback();
247       }
248     }
249   }
250 
251   @Test
252   void shouldAssingKeysToNamedArray() {
253     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
254       try {
255         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
256         Country[] countries = new Country[2];
257         countries[0] = new Country("China", "CN");
258         countries[1] = new Country("United Kiongdom", "GB");
259         mapper.insertNamedArray(countries);
260         for (Country country : countries) {
261           assertNotNull(country.getId());
262         }
263       } finally {
264         sqlSession.rollback();
265       }
266     }
267   }
268 
269   @Test
270   void shouldAssignKeyToBean_MultiParams() {
271     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
272       try {
273         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
274         Country country = new Country("China", "CN");
275         mapper.insertMultiParams(country, 1);
276         assertNotNull(country.getId());
277       } finally {
278         sqlSession.rollback();
279       }
280     }
281   }
282 
283   @Test
284   void shouldFailIfKeyPropertyIsInvalid_NoParamName() {
285     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
286       try {
287         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
288         Country country = new Country("China", "CN");
289         when(() -> mapper.insertMultiParams_keyPropertyWithoutParamName(country, 1));
290         then(caughtException()).isInstanceOf(PersistenceException.class)
291             .hasMessageContaining("Could not determine which parameter to assign generated keys to. "
292                 + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
293                 + "Specified key properties are [id] and available parameters are [");
294       } finally {
295         sqlSession.rollback();
296       }
297     }
298   }
299 
300   @Test
301   void shouldFailIfKeyPropertyIsInvalid_WrongParamName() {
302     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
303       try {
304         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
305         Country country = new Country("China", "CN");
306         when(() -> mapper.insertMultiParams_keyPropertyWithWrongParamName(country, 1));
307         then(caughtException()).isInstanceOf(PersistenceException.class)
308             .hasMessageContaining("Could not find parameter 'bogus'. "
309                 + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
310                 + "Specified key properties are [bogus.id] and available parameters are [");
311       } finally {
312         sqlSession.rollback();
313       }
314     }
315   }
316 
317   @Test
318   void shouldAssignKeysToNamedList_MultiParams() {
319     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
320       try {
321         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
322         List<Country> countries = new ArrayList<>();
323         countries.add(new Country("China", "CN"));
324         countries.add(new Country("United Kiongdom", "GB"));
325         mapper.insertList_MultiParams(countries, 1);
326         for (Country country : countries) {
327           assertNotNull(country.getId());
328         }
329       } finally {
330         sqlSession.rollback();
331       }
332     }
333   }
334 
335   @Test
336   void shouldAssignKeysToNamedCollection_MultiParams() {
337     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
338       try {
339         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
340         Set<Country> countries = new HashSet<>();
341         countries.add(new Country("China", "CN"));
342         countries.add(new Country("United Kiongdom", "GB"));
343         mapper.insertSet_MultiParams(countries, 1);
344         for (Country country : countries) {
345           assertNotNull(country.getId());
346         }
347       } finally {
348         sqlSession.rollback();
349       }
350     }
351   }
352 
353   @Test
354   void shouldAssignKeysToNamedArray_MultiParams() {
355     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
356       try {
357         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
358         Country[] countries = new Country[2];
359         countries[0] = new Country("China", "CN");
360         countries[1] = new Country("United Kiongdom", "GB");
361         mapper.insertArray_MultiParams(countries, 1);
362         for (Country country : countries) {
363           assertNotNull(country.getId());
364         }
365       } finally {
366         sqlSession.rollback();
367       }
368     }
369   }
370 
371   @Test
372   void shouldAssignMultipleGeneratedKeysToABean() {
373     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
374       try {
375         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
376         Planet planet = new Planet();
377         planet.setName("pluto");
378         mapper.insertPlanet(planet);
379         assertEquals("pluto-" + planet.getId(), planet.getCode());
380       } finally {
381         sqlSession.rollback();
382       }
383     }
384   }
385 
386   @Test
387   void shouldAssignMultipleGeneratedKeysToBeans() {
388     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
389       try {
390         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
391         Planet planet1 = new Planet();
392         planet1.setName("pluto");
393         Planet planet2 = new Planet();
394         planet2.setName("neptune");
395         List<Planet> planets = Arrays.asList(planet1, planet2);
396         mapper.insertPlanets(planets);
397         assertEquals("pluto-" + planet1.getId(), planet1.getCode());
398         assertEquals("neptune-" + planet2.getId(), planet2.getCode());
399       } finally {
400         sqlSession.rollback();
401       }
402     }
403   }
404 
405   @Test
406   void shouldAssignMultipleGeneratedKeysToABean_MultiParams() {
407     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
408       try {
409         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
410         Planet planet = new Planet();
411         planet.setName("pluto");
412         mapper.insertPlanet_MultiParams(planet, 1);
413         assertEquals("pluto-" + planet.getId(), planet.getCode());
414       } finally {
415         sqlSession.rollback();
416       }
417     }
418   }
419 
420   @Test
421   void shouldAssignMultipleGeneratedKeysToABean_MultiParams_batch() {
422     try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
423       try {
424         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
425         Planet planet1 = new Planet();
426         planet1.setName("pluto");
427         mapper.insertPlanet_MultiParams(planet1, 1);
428         Planet planet2 = new Planet();
429         planet2.setName("neptune");
430         mapper.insertPlanet_MultiParams(planet2, 1);
431         sqlSession.flushStatements();
432         sqlSession.clearCache();
433         assertEquals("pluto-" + planet1.getId(), planet1.getCode());
434         assertEquals("neptune-" + planet2.getId(), planet2.getCode());
435       } finally {
436         sqlSession.rollback();
437       }
438     }
439   }
440 
441   @Test
442   void shouldAssignMultipleGeneratedKeysToBeans_MultiParams() {
443     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
444       try {
445         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
446         Planet planet1 = new Planet();
447         planet1.setName("pluto");
448         Planet planet2 = new Planet();
449         planet2.setName("neptune");
450         List<Planet> planets = Arrays.asList(planet1, planet2);
451         mapper.insertPlanets_MultiParams(planets, 1);
452         assertEquals("pluto-" + planet1.getId(), planet1.getCode());
453         assertEquals("neptune-" + planet2.getId(), planet2.getCode());
454       } finally {
455         sqlSession.rollback();
456       }
457     }
458   }
459 
460   @Test
461   void assigningMultipleKeysToDifferentParams() {
462     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
463       try {
464         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
465         Planet planet = new Planet();
466         planet.setName("pluto");
467         Map<String, Object> map = new HashMap<>();
468         mapper.insertAssignKeysToTwoParams(planet, map);
469         assertNotNull(planet.getId());
470         assertNotNull(map.get("code"));
471       } finally {
472         sqlSession.rollback();
473       }
474     }
475   }
476 
477   @Test
478   void assigningMultipleKeysToDifferentParams_batch() {
479     try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
480       try {
481         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
482         Planet planet1 = new Planet();
483         planet1.setName("pluto");
484         Map<String, Object> map1 = new HashMap<>();
485         mapper.insertAssignKeysToTwoParams(planet1, map1);
486         Planet planet2 = new Planet();
487         planet2.setName("pluto");
488         Map<String, Object> map2 = new HashMap<>();
489         mapper.insertAssignKeysToTwoParams(planet2, map2);
490         sqlSession.flushStatements();
491         sqlSession.clearCache();
492         assertNotNull(planet1.getId());
493         assertNotNull(map1.get("code"));
494         assertNotNull(planet2.getId());
495         assertNotNull(map2.get("code"));
496       } finally {
497         sqlSession.rollback();
498       }
499     }
500   }
501 
502   @Test
503   void shouldErrorUndefineProperty() {
504     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
505       try {
506         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
507 
508         when(() -> mapper.insertUndefineKeyProperty(new Country("China", "CN")));
509         then(caughtException()).isInstanceOf(PersistenceException.class).hasMessageContaining(
510             "### Error updating database.  Cause: org.apache.ibatis.executor.ExecutorException: Error getting generated key or setting result to parameter object. Cause: org.apache.ibatis.executor.ExecutorException: No setter found for the keyProperty 'country_id' in 'org.apache.ibatis.submitted.keygen.Country'.");
511       } finally {
512         sqlSession.rollback();
513       }
514     }
515   }
516 
517   @Test
518   void shouldFailIfTooManyGeneratedKeys() {
519     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
520       try {
521         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
522         when(() -> mapper.tooManyGeneratedKeys(new Country()));
523         then(caughtException()).isInstanceOf(PersistenceException.class)
524             .hasMessageContaining("Too many keys are generated. There are only 1 target objects.");
525       } finally {
526         sqlSession.rollback();
527       }
528     }
529   }
530 
531   @Test
532   void shouldFailIfTooManyGeneratedKeys_ParamMap() {
533     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
534       try {
535         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
536         when(() -> mapper.tooManyGeneratedKeysParamMap(new Country(), 1));
537         then(caughtException()).isInstanceOf(PersistenceException.class)
538             .hasMessageContaining("Too many keys are generated. There are only 1 target objects.");
539       } finally {
540         sqlSession.rollback();
541       }
542     }
543   }
544 
545   @Test
546   void shouldFailIfTooManyGeneratedKeys_Batch() {
547     try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
548       try {
549         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
550         mapper.tooManyGeneratedKeysParamMap(new Country(), 1);
551         mapper.tooManyGeneratedKeysParamMap(new Country(), 1);
552         when(sqlSession::flushStatements);
553         then(caughtException()).isInstanceOf(PersistenceException.class)
554             .hasMessageContaining("Too many keys are generated. There are only 2 target objects.");
555       } finally {
556         sqlSession.rollback();
557       }
558     }
559   }
560 
561   @Test
562   void shouldAssignKeysToListWithoutInvokingEqualsNorHashCode() {
563     // gh-1719
564     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
565       try {
566         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
567         List<NpeCountry> countries = new ArrayList<>();
568         countries.add(new NpeCountry("China", "CN"));
569         countries.add(new NpeCountry("United Kiongdom", "GB"));
570         countries.add(new NpeCountry("United States of America", "US"));
571         mapper.insertWeirdCountries(countries);
572         for (NpeCountry country : countries) {
573           assertNotNull(country.getId());
574         }
575       } finally {
576         sqlSession.rollback();
577       }
578     }
579   }
580 
581   @Test
582   void shouldAssignKeyToAParamWithTrickyName() {
583     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
584       try {
585         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
586         Country country = new Country("China", "CN");
587         mapper.singleParamWithATrickyName(country);
588         assertNotNull(country.getId());
589       } finally {
590         sqlSession.rollback();
591       }
592     }
593   }
594 
595   @Test
596   void shouldAssingKeysToAMap() {
597     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
598       try {
599         CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
600         Map<String, Object> map = new HashMap<>();
601         map.put("countrycode", "CN");
602         map.put("countryname", "China");
603         mapper.insertMap(map);
604         assertNotNull(map.get("id"));
605       } finally {
606         sqlSession.rollback();
607       }
608     }
609   }
610 }