View Javadoc
1   /**
2    *    Copyright 2009-2019 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.sqlprovider;
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  import static org.junit.jupiter.api.Assertions.assertTrue;
22  import static org.junit.jupiter.api.Assertions.fail;
23  
24  import java.io.Reader;
25  import java.lang.reflect.Method;
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.apache.ibatis.BaseDataTest;
33  import org.apache.ibatis.annotations.DeleteProvider;
34  import org.apache.ibatis.annotations.Param;
35  import org.apache.ibatis.annotations.SelectProvider;
36  import org.apache.ibatis.binding.MapperMethod;
37  import org.apache.ibatis.builder.BuilderException;
38  import org.apache.ibatis.builder.annotation.ProviderContext;
39  import org.apache.ibatis.builder.annotation.ProviderSqlSource;
40  import org.apache.ibatis.io.Resources;
41  import org.apache.ibatis.session.Configuration;
42  import org.apache.ibatis.session.SqlSession;
43  import org.apache.ibatis.session.SqlSessionFactory;
44  import org.apache.ibatis.session.SqlSessionFactoryBuilder;
45  import org.junit.jupiter.api.BeforeAll;
46  import org.junit.jupiter.api.Test;
47  
48  class SqlProviderTest {
49  
50    private static SqlSessionFactory sqlSessionFactory;
51    private static SqlSessionFactory sqlSessionFactoryForDerby;
52  
53    @BeforeAll
54    static void setUp() throws Exception {
55      // create a SqlSessionFactory
56      try (Reader reader = Resources
57          .getResourceAsReader("org/apache/ibatis/submitted/sqlprovider/mybatis-config.xml")) {
58        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
59        sqlSessionFactory.getConfiguration().addMapper(StaticMethodSqlProviderMapper.class);
60        sqlSessionFactory.getConfiguration().addMapper(DatabaseIdMapper.class);
61      }
62      // populate in-memory database
63      BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
64              "org/apache/ibatis/submitted/sqlprovider/CreateDB.sql");
65  
66      // create a SqlSessionFactory
67      try (Reader reader = Resources
68          .getResourceAsReader("org/apache/ibatis/submitted/sqlprovider/mybatis-config.xml")) {
69        sqlSessionFactoryForDerby = new SqlSessionFactoryBuilder().build(reader, "development-derby");
70        sqlSessionFactoryForDerby.getConfiguration().addMapper(DatabaseIdMapper.class);
71      }
72    }
73  
74    // Test for list
75    @Test
76    void shouldGetTwoUsers() {
77      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
78        Mapper mapper = sqlSession.getMapper(Mapper.class);
79        List<Integer> list = new ArrayList<>();
80        list.add(1);
81        list.add(3);
82        List<User> users = mapper.getUsers(list);
83        assertEquals(2, users.size());
84        assertEquals("User1", users.get(0).getName());
85        assertEquals("User3", users.get(1).getName());
86      }
87    }
88  
89    // Test for simple value without @Param
90    @Test
91    void shouldGetOneUser() {
92      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
93        Mapper mapper = sqlSession.getMapper(Mapper.class);
94        {
95          User user = mapper.getUser(4);
96          assertNotNull(user);
97          assertEquals("User4", user.getName());
98        }
99        {
100         User user = mapper.getUser(null);
101         assertNull(user);
102       }
103     }
104   }
105 
106   // Test for empty
107   @Test
108   void shouldGetAllUsers() {
109     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
110       Mapper mapper = sqlSession.getMapper(Mapper.class);
111       List<User> users = mapper.getAllUsers();
112       assertEquals(4, users.size());
113       assertEquals("User1", users.get(0).getName());
114       assertEquals("User2", users.get(1).getName());
115       assertEquals("User3", users.get(2).getName());
116       assertEquals("User4", users.get(3).getName());
117     }
118   }
119 
120   // Test for single JavaBean
121   @Test
122   void shouldGetUsersByCriteria() {
123     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
124       Mapper mapper = sqlSession.getMapper(Mapper.class);
125       {
126         Usered/sqlprovider/User.html#User">User criteria = new User();
127         criteria.setId(1);
128         List<User> users = mapper.getUsersByCriteria(criteria);
129         assertEquals(1, users.size());
130         assertEquals("User1", users.get(0).getName());
131       }
132       {
133         Usered/sqlprovider/User.html#User">User criteria = new User();
134         criteria.setName("User");
135         List<User> users = mapper.getUsersByCriteria(criteria);
136         assertEquals(4, users.size());
137         assertEquals("User1", users.get(0).getName());
138         assertEquals("User2", users.get(1).getName());
139         assertEquals("User3", users.get(2).getName());
140         assertEquals("User4", users.get(3).getName());
141       }
142     }
143   }
144 
145   // Test for single map
146   @Test
147   void shouldGetUsersByCriteriaMap() {
148     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
149       Mapper mapper = sqlSession.getMapper(Mapper.class);
150       {
151         Map<String, Object> criteria = new HashMap<>();
152         criteria.put("id", 1);
153         List<User> users = mapper.getUsersByCriteriaMap(criteria);
154         assertEquals(1, users.size());
155         assertEquals("User1", users.get(0).getName());
156       }
157       {
158         Map<String, Object> criteria = new HashMap<>();
159         criteria.put("name", "User");
160         List<User> users = mapper.getUsersByCriteriaMap(criteria);
161         assertEquals(4, users.size());
162         assertEquals("User1", users.get(0).getName());
163         assertEquals("User2", users.get(1).getName());
164         assertEquals("User3", users.get(2).getName());
165         assertEquals("User4", users.get(3).getName());
166       }
167     }
168   }
169 
170   @Test
171   void shouldGetUsersByCriteriaMapWithParam() {
172     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
173       Mapper mapper = sqlSession.getMapper(Mapper.class);
174       {
175         Map<String, Object> criteria = new HashMap<>();
176         criteria.put("id", 1);
177         List<User> users = mapper.getUsersByCriteriaMapWithParam(criteria);
178         assertEquals(1, users.size());
179         assertEquals("User1", users.get(0).getName());
180       }
181       {
182         Map<String, Object> criteria = new HashMap<>();
183         criteria.put("name", "User");
184         List<User> users = mapper.getUsersByCriteriaMapWithParam(criteria);
185         assertEquals(4, users.size());
186         assertEquals("User1", users.get(0).getName());
187         assertEquals("User2", users.get(1).getName());
188         assertEquals("User3", users.get(2).getName());
189         assertEquals("User4", users.get(3).getName());
190       }
191     }
192   }
193 
194   // Test for multiple parameter without @Param
195   @Test
196   void shouldGetUsersByName() {
197     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
198       Mapper mapper = sqlSession.getMapper(Mapper.class);
199       List<User> users = mapper.getUsersByName("User", "id DESC");
200       assertEquals(4, users.size());
201       assertEquals("User4", users.get(0).getName());
202       assertEquals("User3", users.get(1).getName());
203       assertEquals("User2", users.get(2).getName());
204       assertEquals("User1", users.get(3).getName());
205     }
206   }
207 
208   // Test for map without @Param
209   @Test
210   void shouldGetUsersByNameUsingMap() {
211     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
212       Mapper mapper = sqlSession.getMapper(Mapper.class);
213       List<User> users = mapper.getUsersByNameUsingMap("User", "id DESC");
214       assertEquals(4, users.size());
215       assertEquals("User4", users.get(0).getName());
216       assertEquals("User3", users.get(1).getName());
217       assertEquals("User2", users.get(2).getName());
218       assertEquals("User1", users.get(3).getName());
219     }
220   }
221 
222   // Test for multiple parameter with @Param
223   @Test
224   void shouldGetUsersByNameWithParamNameAndOrderBy() {
225     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
226       Mapper mapper = sqlSession.getMapper(Mapper.class);
227       List<User> users = mapper.getUsersByNameWithParamNameAndOrderBy("User", "id DESC");
228       assertEquals(4, users.size());
229       assertEquals("User4", users.get(0).getName());
230       assertEquals("User3", users.get(1).getName());
231       assertEquals("User2", users.get(2).getName());
232       assertEquals("User1", users.get(3).getName());
233     }
234   }
235 
236   // Test for map with @Param
237   @Test
238   void shouldGetUsersByNameWithParamNameUsingMap() {
239     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
240       Mapper mapper = sqlSession.getMapper(Mapper.class);
241       List<User> users = mapper.getUsersByNameWithParamNameAndOrderBy("User", "id DESC");
242       assertEquals(4, users.size());
243       assertEquals("User4", users.get(0).getName());
244       assertEquals("User3", users.get(1).getName());
245       assertEquals("User2", users.get(2).getName());
246       assertEquals("User1", users.get(3).getName());
247     }
248   }
249 
250   // Test for simple value with @Param
251   @Test
252   void shouldGetUsersByNameWithParamName() {
253     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
254       Mapper mapper = sqlSession.getMapper(Mapper.class);
255       {
256         List<User> users = mapper.getUsersByNameWithParamName("User");
257         assertEquals(4, users.size());
258         assertEquals("User4", users.get(0).getName());
259         assertEquals("User3", users.get(1).getName());
260         assertEquals("User2", users.get(2).getName());
261         assertEquals("User1", users.get(3).getName());
262       }
263       {
264         List<User> users = mapper.getUsersByNameWithParamName(null);
265         assertEquals(4, users.size());
266         assertEquals("User4", users.get(0).getName());
267         assertEquals("User3", users.get(1).getName());
268         assertEquals("User2", users.get(2).getName());
269         assertEquals("User1", users.get(3).getName());
270       }
271     }
272   }
273 
274   @Test
275   void methodNotFound() throws NoSuchMethodException {
276     try {
277       Class<?> mapperType = ErrorMapper.class;
278       Method mapperMethod = mapperType.getMethod("methodNotFound");
279       new ProviderSqlSource(new Configuration(),
280             mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod);
281       fail();
282     } catch (BuilderException e) {
283       assertTrue(e.getMessage().contains("Error creating SqlSource for SqlProvider. Method 'methodNotFound' not found in SqlProvider 'org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorSqlBuilder'."));
284     }
285   }
286 
287   @Test
288   void methodOverload() throws NoSuchMethodException {
289     try {
290       Class<?> mapperType = ErrorMapper.class;
291       Method mapperMethod = mapperType.getMethod("methodOverload", String.class);
292       new ProviderSqlSource(new Configuration(),
293               mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod);
294       fail();
295     } catch (BuilderException e) {
296       assertTrue(e.getMessage().contains("Error creating SqlSource for SqlProvider. Method 'overload' is found multiple in SqlProvider 'org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorSqlBuilder'. Sql provider method can not overload."));
297     }
298   }
299 
300   @Test
301   @SuppressWarnings("deprecation")
302   void notSqlProvider() throws NoSuchMethodException {
303     Object testAnnotation = getClass().getDeclaredMethod("notSqlProvider").getAnnotation(Test.class);
304     try {
305       new ProviderSqlSource(new Configuration(), testAnnotation);
306       fail();
307     } catch (BuilderException e) {
308       assertTrue(e.getMessage().contains("Error creating SqlSource for SqlProvider.  Cause: java.lang.NoSuchMethodException: org.junit.jupiter.api.Test.type()"));
309     }
310   }
311 
312   @Test
313   void omitType() throws NoSuchMethodException {
314     try {
315       Class<?> mapperType = ErrorMapper.class;
316       Method mapperMethod = mapperType.getMethod("omitType");
317       new ProviderSqlSource(new Configuration(),
318           mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod);
319       fail();
320     } catch (BuilderException e) {
321       assertTrue(e.getMessage().contains("Please specify either 'value' or 'type' attribute of @SelectProvider at the 'public abstract void org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorMapper.omitType()'."));
322     }
323   }
324 
325   @Test
326   void differentTypeAndValue() throws NoSuchMethodException {
327     try {
328       Class<?> mapperType = ErrorMapper.class;
329       Method mapperMethod = mapperType.getMethod("differentTypeAndValue");
330       new ProviderSqlSource(new Configuration(),
331           mapperMethod.getAnnotation(DeleteProvider.class), mapperType, mapperMethod);
332       fail();
333     } catch (BuilderException e) {
334       assertTrue(e.getMessage().contains("Cannot specify different class on 'value' and 'type' attribute of @DeleteProvider at the 'public abstract void org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorMapper.differentTypeAndValue()'."));
335     }
336   }
337 
338   @Test
339   void multipleProviderContext() throws NoSuchMethodException {
340     try {
341       Class<?> mapperType = ErrorMapper.class;
342       Method mapperMethod = mapperType.getMethod("multipleProviderContext");
343       new ProviderSqlSource(new Configuration(),
344             mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod);
345       fail();
346     } catch (BuilderException e) {
347       assertTrue(e.getMessage().contains("Error creating SqlSource for SqlProvider. ProviderContext found multiple in SqlProvider method (org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorSqlBuilder.multipleProviderContext). ProviderContext can not define multiple in SqlProvider method argument."));
348     }
349   }
350 
351   @Test
352   void notSupportParameterObjectOnMultipleArguments() throws NoSuchMethodException {
353     try {
354       Class<?> mapperType = Mapper.class;
355       Method mapperMethod = mapperType.getMethod("getUsersByName", String.class, String.class);
356       new ProviderSqlSource(new Configuration(),
357             mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod)
358               .getBoundSql(new Object());
359       fail();
360     } catch (BuilderException e) {
361       assertTrue(e.getMessage().contains("Error invoking SqlProvider method 'public java.lang.String org.apache.ibatis.submitted.sqlprovider.OurSqlBuilder.buildGetUsersByNameQuery(java.lang.String,java.lang.String)' with specify parameter 'class java.lang.Object'.  Cause: java.lang.IllegalArgumentException: wrong number of arguments"));
362     }
363   }
364 
365   @Test
366   void notSupportParameterObjectOnNamedArgument() throws NoSuchMethodException {
367     try {
368       Class<?> mapperType = Mapper.class;
369       Method mapperMethod = mapperType.getMethod("getUsersByNameWithParamName", String.class);
370       new ProviderSqlSource(new Configuration(),
371             mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod)
372               .getBoundSql(new Object());
373       fail();
374     } catch (BuilderException e) {
375       assertTrue(e.getMessage().contains("Error invoking SqlProvider method 'public java.lang.String org.apache.ibatis.submitted.sqlprovider.OurSqlBuilder.buildGetUsersByNameWithParamNameQuery(java.lang.String)' with specify parameter 'class java.lang.Object'.  Cause: java.lang.IllegalArgumentException: argument type mismatch"));
376     }
377   }
378 
379   @Test
380   void invokeError() throws NoSuchMethodException {
381     try {
382       Class<?> mapperType = ErrorMapper.class;
383       Method mapperMethod = mapperType.getMethod("invokeError");
384       new ProviderSqlSource(new Configuration(),
385             mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod)
386               .getBoundSql(new Object());
387       fail();
388     } catch (BuilderException e) {
389       assertTrue(e.getMessage().contains("Error invoking SqlProvider method 'public java.lang.String org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorSqlBuilder.invokeError()' with specify parameter 'class java.lang.Object'.  Cause: java.lang.UnsupportedOperationException: invokeError"));
390     }
391   }
392 
393   @Test
394   void invokeNestedError() throws NoSuchMethodException {
395     try {
396       Class<?> mapperType = ErrorMapper.class;
397       Method mapperMethod = mapperType.getMethod("invokeNestedError");
398       new ProviderSqlSource(new Configuration(),
399         mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod)
400         .getBoundSql(new Object());
401       fail();
402     } catch (BuilderException e) {
403       assertTrue(e.getMessage().contains("Error invoking SqlProvider method 'public java.lang.String org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorSqlBuilder.invokeNestedError()' with specify parameter 'class java.lang.Object'.  Cause: java.lang.UnsupportedOperationException: invokeNestedError"));
404     }
405   }
406 
407   @Test
408   void invalidArgumentsCombination() throws NoSuchMethodException {
409     try {
410       Class<?> mapperType = ErrorMapper.class;
411       Method mapperMethod = mapperType.getMethod("invalidArgumentsCombination", String.class);
412       new ProviderSqlSource(new Configuration(),
413         mapperMethod.getAnnotation(DeleteProvider.class), mapperType, mapperMethod)
414         .getBoundSql("foo");
415       fail();
416     } catch (BuilderException e) {
417       assertTrue(e.getMessage().contains("Cannot invoke SqlProvider method 'public java.lang.String org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorSqlBuilder.invalidArgumentsCombination(org.apache.ibatis.builder.annotation.ProviderContext,java.lang.String,java.lang.String)' with specify parameter 'class java.lang.String' because SqlProvider method arguments for 'public abstract void org.apache.ibatis.submitted.sqlprovider.SqlProviderTest$ErrorMapper.invalidArgumentsCombination(java.lang.String)' is an invalid combination."));
418     }
419   }
420 
421   @Test
422   void shouldInsertUser() {
423     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
424       Mapper mapper = sqlSession.getMapper(Mapper.class);
425       Usermitted/sqlprovider/User.html#User">User user = new User();
426       user.setId(999);
427       user.setName("MyBatis");
428       mapper.insert(user);
429 
430       User loadedUser = mapper.getUser(999);
431       assertEquals("MyBatis", loadedUser.getName());
432     }
433   }
434 
435   @Test
436   void shouldUpdateUser() {
437     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
438       Mapper mapper = sqlSession.getMapper(Mapper.class);
439       Usermitted/sqlprovider/User.html#User">User user = new User();
440       user.setId(999);
441       user.setName("MyBatis");
442       mapper.insert(user);
443 
444       user.setName("MyBatis3");
445       mapper.update(user);
446 
447       User loadedUser = mapper.getUser(999);
448       assertEquals("MyBatis3", loadedUser.getName());
449     }
450   }
451 
452   @Test
453   void shouldDeleteUser() {
454     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
455       Mapper mapper = sqlSession.getMapper(Mapper.class);
456       Usermitted/sqlprovider/User.html#User">User user = new User();
457       user.setId(999);
458       user.setName("MyBatis");
459       mapper.insert(user);
460 
461       user.setName("MyBatis3");
462       mapper.delete(999);
463 
464       User loadedUser = mapper.getUser(999);
465       assertNull(loadedUser);
466     }
467   }
468 
469   @Test
470   void mapperProviderContextOnly() {
471     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
472       Mapper mapper = sqlSession.getMapper(Mapper.class);
473       assertEquals("User4", mapper.selectById(4).getName());
474       assertNull(mapper.selectActiveById(4));
475     }
476   }
477 
478   @Test
479   void mapperOneParamAndProviderContext() {
480     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
481       Mapper mapper = sqlSession.getMapper(Mapper.class);
482       assertEquals(1, mapper.selectByName("User4").size());
483       assertEquals(0, mapper.selectActiveByName("User4").size());
484     }
485   }
486 
487   @Test
488   void mapperMultipleParamAndProviderContextWithAtParam() {
489     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
490       Mapper mapper = sqlSession.getMapper(Mapper.class);
491       assertEquals(1, mapper.selectByIdAndNameWithAtParam(4,"User4").size());
492       assertEquals(0, mapper.selectActiveByIdAndNameWithAtParam(4,"User4").size());
493     }
494   }
495 
496   @Test
497   void mapperMultipleParamAndProviderContext() {
498     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
499       Mapper mapper = sqlSession.getMapper(Mapper.class);
500       assertEquals(1, mapper.selectByIdAndName(4,"User4").size());
501       assertEquals(0, mapper.selectActiveByIdAndName(4,"User4").size());
502     }
503   }
504 
505   @Test
506   void staticMethodNoArgument() {
507     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
508       StaticMethodSqlProviderMapper mapper =
509           sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
510       assertEquals(1, mapper.noArgument());
511     }
512   }
513 
514   @Test
515   void staticMethodOneArgument() {
516     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
517       StaticMethodSqlProviderMapper mapper =
518           sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
519       assertEquals(10, mapper.oneArgument(10));
520     }
521   }
522 
523   @Test
524   void staticMethodOnePrimitiveByteArgument() {
525     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
526       StaticMethodSqlProviderMapper mapper =
527         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
528       assertEquals((byte) 10, mapper.onePrimitiveByteArgument((byte) 10));
529     }
530   }
531 
532   @Test
533   void staticMethodOnePrimitiveShortArgument() {
534     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
535       StaticMethodSqlProviderMapper mapper =
536         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
537       assertEquals((short) 10, mapper.onePrimitiveShortArgument((short) 10));
538     }
539   }
540 
541   @Test
542   void staticMethodOnePrimitiveIntArgument() {
543     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
544       StaticMethodSqlProviderMapper mapper =
545         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
546       assertEquals(10, mapper.onePrimitiveIntArgument(10));
547     }
548   }
549 
550   @Test
551   void staticMethodOnePrimitiveLongArgument() {
552     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
553       StaticMethodSqlProviderMapper mapper =
554         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
555       assertEquals(10L, mapper.onePrimitiveLongArgument(10L));
556     }
557   }
558 
559   @Test
560   void staticMethodOnePrimitiveFloatArgument() {
561     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
562       StaticMethodSqlProviderMapper mapper =
563         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
564       assertEquals(10.1F, mapper.onePrimitiveFloatArgument(10.1F));
565     }
566   }
567 
568   @Test
569   void staticMethodOnePrimitiveDoubleArgument() {
570     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
571       StaticMethodSqlProviderMapper mapper =
572         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
573       assertEquals(10.1D, mapper.onePrimitiveDoubleArgument(10.1D));
574     }
575   }
576 
577   @Test
578   void staticMethodOnePrimitiveBooleanArgument() {
579     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
580       StaticMethodSqlProviderMapper mapper =
581         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
582       assertTrue(mapper.onePrimitiveBooleanArgument(true));
583     }
584   }
585 
586   @Test
587   void staticMethodOnePrimitiveCharArgument() {
588     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
589       StaticMethodSqlProviderMapper mapper =
590         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
591       assertEquals('A', mapper.onePrimitiveCharArgument('A'));
592     }
593   }
594 
595   @Test
596   void boxing() {
597     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
598       StaticMethodSqlProviderMapper mapper =
599         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
600       assertEquals(10, mapper.boxing(10));
601     }
602   }
603 
604   @Test
605   void unboxing() {
606     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
607       StaticMethodSqlProviderMapper mapper =
608         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
609       assertEquals(100, mapper.unboxing(100));
610     }
611   }
612 
613   @Test
614   void staticMethodMultipleArgument() {
615     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
616       StaticMethodSqlProviderMapper mapper =
617           sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
618       assertEquals(2, mapper.multipleArgument(1, 1));
619     }
620   }
621 
622   @Test
623   void staticMethodOnlyProviderContext() {
624     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
625       StaticMethodSqlProviderMapper mapper =
626           sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
627       assertEquals("onlyProviderContext", mapper.onlyProviderContext());
628     }
629   }
630 
631   @Test
632   void staticMethodOneArgumentAndProviderContext() {
633     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
634       StaticMethodSqlProviderMapper mapper =
635           sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
636       assertEquals("oneArgumentAndProviderContext 100", mapper.oneArgumentAndProviderContext(100));
637     }
638   }
639 
640   @Test
641   void mapAndProviderContext() {
642     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
643       StaticMethodSqlProviderMapper mapper =
644         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
645       assertEquals("mybatis", mapper.mapAndProviderContext("mybatis"));
646     }
647   }
648 
649   @Test
650   void multipleMap() {
651     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
652       StaticMethodSqlProviderMapper mapper =
653         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
654       assertEquals("123456", mapper.multipleMap(Collections.singletonMap("value", "123"), Collections.singletonMap("value", "456")));
655     }
656   }
657 
658   @Test
659   void providerContextAndMap() {
660     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
661       StaticMethodSqlProviderMapper mapper =
662         sqlSession.getMapper(StaticMethodSqlProviderMapper.class);
663       assertEquals("mybatis", mapper.providerContextAndParamMap("mybatis"));
664     }
665   }
666 
667   @Test
668   @SuppressWarnings("deprecation")
669   void keepBackwardCompatibilityOnDeprecatedConstructorWithAnnotation() throws NoSuchMethodException {
670     Class<?> mapperType = StaticMethodSqlProviderMapper.class;
671     Method mapperMethod = mapperType.getMethod("noArgument");
672     ProviderSqlSource sqlSource = new ProviderSqlSource(new Configuration(), (Object)mapperMethod.getAnnotation(SelectProvider.class), mapperType, mapperMethod);
673     assertEquals("SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS", sqlSource.getBoundSql(null).getSql());
674   }
675 
676   public interface ErrorMapper {
677     @SelectProvider(type = ErrorSqlBuilder.class, method = "methodNotFound")
678     void methodNotFound();
679 
680     @SelectProvider(type = ErrorSqlBuilder.class, method = "overload")
681     void methodOverload(String value);
682 
683     @SelectProvider(type = ErrorSqlBuilder.class, method = "invokeError")
684     void invokeError();
685 
686     @SelectProvider(type = ErrorSqlBuilder.class, method = "invokeNestedError")
687     void invokeNestedError();
688 
689     @SelectProvider(type = ErrorSqlBuilder.class, method = "multipleProviderContext")
690     void multipleProviderContext();
691 
692     @SelectProvider
693     void omitType();
694 
695     @DeleteProvider(value = String.class, type = Integer.class)
696     void differentTypeAndValue();
697 
698     @DeleteProvider(type = ErrorSqlBuilder.class, method = "invalidArgumentsCombination")
699     void invalidArgumentsCombination(String value);
700 
701   }
702 
703   @SuppressWarnings("unused")
704   public static class ErrorSqlBuilder {
705     public void methodNotFound() {
706       throw new UnsupportedOperationException("methodNotFound");
707     }
708 
709     public String overload() {
710       throw new UnsupportedOperationException("overload");
711     }
712 
713     public String overload(String value) {
714       throw new UnsupportedOperationException("overload");
715     }
716 
717     public String invokeError() {
718       throw new UnsupportedOperationException("invokeError");
719     }
720 
721     public String invokeNestedError() {
722       throw new IllegalStateException(new UnsupportedOperationException("invokeNestedError"));
723     }
724 
725     public String multipleProviderContext(ProviderContext providerContext1, ProviderContext providerContext2) {
726       throw new UnsupportedOperationException("multipleProviderContext");
727     }
728 
729     public String invalidArgumentsCombination(ProviderContext providerContext, String value, String unnecessaryArgument) {
730       return "";
731     }
732   }
733 
734   public interface StaticMethodSqlProviderMapper {
735     @SelectProvider(type = SqlProvider.class, method = "noArgument")
736     int noArgument();
737 
738     @SelectProvider(type = SqlProvider.class, method = "oneArgument")
739     int oneArgument(Integer value);
740 
741     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveByteArgument")
742     byte onePrimitiveByteArgument(byte value);
743 
744     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveShortArgument")
745     short onePrimitiveShortArgument(short value);
746 
747     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveIntArgument")
748     int onePrimitiveIntArgument(int value);
749 
750     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveLongArgument")
751     long onePrimitiveLongArgument(long value);
752 
753     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveFloatArgument")
754     float onePrimitiveFloatArgument(float value);
755 
756     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveDoubleArgument")
757     double onePrimitiveDoubleArgument(double value);
758 
759     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveBooleanArgument")
760     boolean onePrimitiveBooleanArgument(boolean value);
761 
762     @SelectProvider(type = SqlProvider.class, method = "onePrimitiveCharArgument")
763     char onePrimitiveCharArgument(char value);
764 
765     @SelectProvider(type = SqlProvider.class, method = "boxing")
766     int boxing(int value);
767 
768     @SelectProvider(type = SqlProvider.class, method = "unboxing")
769     int unboxing(Integer value);
770 
771     @SelectProvider(type = SqlProvider.class, method = "multipleArgument")
772     int multipleArgument(@Param("value1") Integer value1, @Param("value2") Integer value2);
773 
774     @SelectProvider(type = SqlProvider.class, method = "onlyProviderContext")
775     String onlyProviderContext();
776 
777     @SelectProvider(type = SqlProvider.class, method = "oneArgumentAndProviderContext")
778     String oneArgumentAndProviderContext(Integer value);
779 
780     @SelectProvider(type = SqlProvider.class, method = "mapAndProviderContext")
781     String mapAndProviderContext(@Param("value") String value);
782 
783     @SelectProvider(type = SqlProvider.class, method = "providerContextAndParamMap")
784     String providerContextAndParamMap(@Param("value") String value);
785 
786     @SelectProvider(type = SqlProvider.class, method = "multipleMap")
787     String multipleMap(@Param("map1") Map<String, Object> map1, @Param("map2") Map<String, Object> map2);
788 
789     @SuppressWarnings("unused")
790     class SqlProvider {
791 
792       public static String noArgument() {
793         return "SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS";
794       }
795 
796       public static StringBuilder oneArgument(Integer value) {
797         return new StringBuilder().append("SELECT ").append(value)
798             .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
799       }
800 
801       public static StringBuilder onePrimitiveByteArgument(byte value) {
802         return new StringBuilder().append("SELECT ").append(value)
803           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
804       }
805 
806       public static StringBuilder onePrimitiveShortArgument(short value) {
807         return new StringBuilder().append("SELECT ").append(value)
808           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
809       }
810 
811       public static StringBuilder onePrimitiveIntArgument(int value) {
812         return new StringBuilder().append("SELECT ").append(value)
813           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
814       }
815 
816       public static StringBuilder onePrimitiveLongArgument(long value) {
817         return new StringBuilder().append("SELECT ").append(value)
818           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
819       }
820 
821       public static StringBuilder onePrimitiveFloatArgument(float value) {
822         return new StringBuilder().append("SELECT ").append(value)
823           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
824       }
825 
826       public static StringBuilder onePrimitiveDoubleArgument(double value) {
827         return new StringBuilder().append("SELECT ").append(value)
828           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
829       }
830 
831       public static StringBuilder onePrimitiveBooleanArgument(boolean value) {
832         return new StringBuilder().append("SELECT ").append(value ? 1 : 0)
833           .append(" FROM INFORMATION_SCHEMA.SYSTEM_USERS");
834       }
835 
836       public static StringBuilder onePrimitiveCharArgument(char value) {
837         return new StringBuilder().append("SELECT '").append(value)
838           .append("' FROM INFORMATION_SCHEMA.SYSTEM_USERS");
839       }
840 
841       public static StringBuilder boxing(Integer value) {
842         return new StringBuilder().append("SELECT '").append(value)
843           .append("' FROM INFORMATION_SCHEMA.SYSTEM_USERS");
844       }
845 
846       public static StringBuilder unboxing(int value) {
847         return new StringBuilder().append("SELECT '").append(value)
848           .append("' FROM INFORMATION_SCHEMA.SYSTEM_USERS");
849       }
850 
851       public static CharSequence multipleArgument(@Param("value1") Integer value1,
852           @Param("value2") Integer value2) {
853         return "SELECT " + (value1 + value2) + " FROM INFORMATION_SCHEMA.SYSTEM_USERS";
854       }
855 
856       public static CharSequence onlyProviderContext(ProviderContext context) {
857         return new StringBuilder().append("SELECT '").append(context.getMapperMethod().getName())
858             .append("' FROM INFORMATION_SCHEMA.SYSTEM_USERS");
859       }
860 
861       public static String oneArgumentAndProviderContext(Integer value, ProviderContext context) {
862         return "SELECT '" + context.getMapperMethod().getName() + " " + value
863             + "' FROM INFORMATION_SCHEMA.SYSTEM_USERS";
864       }
865 
866       public static String mapAndProviderContext(Map<String, Object> map, ProviderContext context) {
867         return "SELECT '" + map.get("value") + "' FROM INFORMATION_SCHEMA.SYSTEM_USERS";
868       }
869 
870       public static String providerContextAndParamMap(ProviderContext context, MapperMethod.ParamMap<Object> map) {
871         return "SELECT '" + map.get("value") + "' FROM INFORMATION_SCHEMA.SYSTEM_USERS";
872       }
873 
874       public static String multipleMap(@Param("map1") Map<String, Object> map1, @Param("map2") Map<String, Object> map2) {
875         return "SELECT '" + map1.get("value") + map2.get("value") + "' FROM INFORMATION_SCHEMA.SYSTEM_USERS";
876       }
877 
878     }
879 
880   }
881 
882   @Test
883   void shouldInsertUserSelective() {
884     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
885       Mapper mapper = sqlSession.getMapper(Mapper.class);
886       Usermitted/sqlprovider/User.html#User">User user = new User();
887       user.setId(999);
888       mapper.insertSelective(user);
889 
890       User loadedUser = mapper.getUser(999);
891       assertNull(loadedUser.getName());
892     }
893   }
894 
895 
896   @Test
897   void shouldUpdateUserSelective() {
898     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
899       Mapper mapper = sqlSession.getMapper(Mapper.class);
900       Usermitted/sqlprovider/User.html#User">User user = new User();
901       user.setId(999);
902       user.setName("MyBatis");
903       mapper.insert(user);
904 
905       user.setName(null);
906       mapper.updateSelective(user);
907 
908       User loadedUser = mapper.getUser(999);
909       assertEquals("MyBatis", loadedUser.getName());
910     }
911   }
912 
913   @Test
914   void mapperGetByEntity() {
915     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
916       Mapper mapper = sqlSession.getMapper(Mapper.class);
917       Useritted/sqlprovider/User.html#User">User query = new User();
918       query.setName("User4");
919       assertEquals(1, mapper.getByEntity(query).size());
920       query = new User();
921       query.setId(1);
922       assertEquals(1, mapper.getByEntity(query).size());
923       query = new User();
924       query.setId(1);
925       query.setName("User4");
926       assertEquals(0, mapper.getByEntity(query).size());
927     }
928   }
929 
930   @Test
931   void shouldPassedDatabaseIdToProviderMethod() {
932     try (SqlSession sqlSession = sqlSessionFactory.openSession()){
933       DatabaseIdMapper mapper = sqlSession.getMapper(DatabaseIdMapper.class);
934       assertEquals("hsql", mapper.selectDatabaseId());
935     }
936     try (SqlSession sqlSession = sqlSessionFactoryForDerby.openSession()){
937       DatabaseIdMapper mapper = sqlSession.getMapper(DatabaseIdMapper.class);
938       assertEquals("derby", mapper.selectDatabaseId());
939     }
940   }
941 
942   interface DatabaseIdMapper {
943     @SelectProvider(type = SqlProvider.class)
944     String selectDatabaseId();
945 
946     @SuppressWarnings("unused")
947     class SqlProvider {
948       public static String provideSql(ProviderContext context) {
949         if ("hsql".equals(context.getDatabaseId())) {
950           return "SELECT '" + context.getDatabaseId() + "' FROM INFORMATION_SCHEMA.SYSTEM_USERS";
951         } else {
952           return "SELECT '" + context.getDatabaseId() + "' FROM SYSIBM.SYSDUMMY1";
953         }
954       }
955     }
956   }
957 
958 }