View Javadoc
1   /*
2    * Copyright 2010-2024 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.mybatis.spring;
17  
18  import static org.assertj.core.api.Assertions.assertThat;
19  import static org.junit.jupiter.api.Assertions.assertThrows;
20  
21  import com.mockrunner.mock.jdbc.MockDataSource;
22  
23  import java.math.BigDecimal;
24  import java.math.BigInteger;
25  import java.sql.CallableStatement;
26  import java.sql.PreparedStatement;
27  import java.sql.ResultSet;
28  import java.sql.SQLException;
29  import java.util.Properties;
30  import java.util.UUID;
31  import java.util.concurrent.atomic.AtomicInteger;
32  import java.util.concurrent.atomic.AtomicLong;
33  import java.util.stream.Collectors;
34  
35  import org.apache.ibatis.cache.impl.PerpetualCache;
36  import org.apache.ibatis.executor.Executor;
37  import org.apache.ibatis.io.JBoss6VFS;
38  import org.apache.ibatis.mapping.MappedStatement;
39  import org.apache.ibatis.plugin.Interceptor;
40  import org.apache.ibatis.plugin.Intercepts;
41  import org.apache.ibatis.plugin.Invocation;
42  import org.apache.ibatis.plugin.Signature;
43  import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
44  import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
45  import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
46  import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
47  import org.apache.ibatis.session.Configuration;
48  import org.apache.ibatis.session.ExecutorType;
49  import org.apache.ibatis.session.SqlSessionFactory;
50  import org.apache.ibatis.transaction.TransactionFactory;
51  import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
52  import org.apache.ibatis.type.BaseTypeHandler;
53  import org.apache.ibatis.type.EnumOrdinalTypeHandler;
54  import org.apache.ibatis.type.JdbcType;
55  import org.apache.ibatis.type.TypeException;
56  import org.apache.ibatis.type.TypeHandler;
57  import org.junit.jupiter.api.Test;
58  import org.mybatis.core.jdk.type.AtomicNumberTypeHandler;
59  import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
60  import org.mybatis.spring.type.DummyTypeAlias;
61  import org.mybatis.spring.type.DummyTypeHandler;
62  import org.mybatis.spring.type.SuperType;
63  import org.mybatis.spring.type.TypeHandlerFactory;
64  import org.springframework.core.io.ClassPathResource;
65  import org.springframework.core.io.Resource;
66  
67  class SqlSessionFactoryBeanTest {
68  
69    private static final class TestObjectFactory extends DefaultObjectFactory {
70      private static final long serialVersionUID = 1L;
71    }
72  
73    private static final class TestObjectWrapperFactory extends DefaultObjectWrapperFactory {
74    }
75  
76    private static MockDataSource dataSource = new MockDataSource();
77  
78    private SqlSessionFactoryBean factoryBean;
79  
80    void setupFactoryBean() {
81      factoryBean = new SqlSessionFactoryBean();
82      factoryBean.setDataSource(dataSource);
83    }
84  
85    @Test
86    void testDefaults() throws Exception {
87      setupFactoryBean();
88  
89      assertDefaultConfig(factoryBean.getObject());
90    }
91  
92    // DataSource is the only required property that does not have a default value, so test for both
93    // not setting it at all and setting it to null
94    @Test
95    void testNullDataSource() {
96      factoryBean = new SqlSessionFactoryBean();
97      assertThrows(IllegalArgumentException.class, factoryBean::getObject);
98    }
99  
100   @Test
101   void testSetNullDataSource() {
102     factoryBean = new SqlSessionFactoryBean();
103     factoryBean.setDataSource(null);
104     assertThrows(IllegalArgumentException.class, factoryBean::getObject);
105   }
106 
107   @Test
108   void testNullSqlSessionFactoryBuilder() {
109     setupFactoryBean();
110     factoryBean.setSqlSessionFactoryBuilder(null);
111     assertThrows(IllegalArgumentException.class, factoryBean::getObject);
112   }
113 
114   @Test
115   void testNullTransactionFactoryClass() throws Exception {
116     setupFactoryBean();
117     factoryBean.setTransactionFactory(null);
118 
119     assertConfig(factoryBean.getObject(), SpringManagedTransactionFactory.class);
120   }
121 
122   @Test
123   void testOtherTransactionFactoryClass() throws Exception {
124     setupFactoryBean();
125     factoryBean.setTransactionFactory(new JdbcTransactionFactory());
126 
127     assertConfig(factoryBean.getObject(), JdbcTransactionFactory.class);
128   }
129 
130   @Test
131   void testEmptyStringEnvironment() throws Exception {
132     setupFactoryBean();
133 
134     factoryBean.setEnvironment("");
135 
136     assertConfig(factoryBean.getObject(), "", org.mybatis.spring.transaction.SpringManagedTransactionFactory.class);
137   }
138 
139   @Test
140   void testDefaultConfiguration() throws Exception {
141     setupFactoryBean();
142 
143     assertDefaultConfig(factoryBean.getObject());
144   }
145 
146   @Test
147   void testDefaultConfigurationWithConfigurationProperties() throws Exception {
148     setupFactoryBean();
149 
150     var configurationProperties = new Properties();
151     configurationProperties.put("username", "dev");
152     factoryBean.setConfigurationProperties(configurationProperties);
153 
154     var factory = factoryBean.getObject();
155     assertConfig(factory, SpringManagedTransactionFactory.class);
156     assertThat(factory.getConfiguration().getVariables().size()).isEqualTo(1);
157     assertThat(factory.getConfiguration().getVariables().get("username")).isEqualTo("dev");
158   }
159 
160   @Test
161   void testSetConfiguration() throws Exception {
162     setupFactoryBean();
163 
164     var customConfiguration = new Configuration();
165     customConfiguration.setCacheEnabled(false);
166     customConfiguration.setUseGeneratedKeys(true);
167     customConfiguration.setDefaultExecutorType(ExecutorType.REUSE);
168     customConfiguration.setVfsImpl(JBoss6VFS.class);
169     factoryBean.setConfiguration(customConfiguration);
170 
171     var factory = factoryBean.getObject();
172 
173     assertThat(factory.getConfiguration().getEnvironment().getId())
174         .isEqualTo(SqlSessionFactoryBean.class.getSimpleName());
175     assertThat(factory.getConfiguration().getEnvironment().getDataSource()).isSameAs(dataSource);
176     assertThat(factory.getConfiguration().getEnvironment().getTransactionFactory().getClass())
177         .isSameAs(SpringManagedTransactionFactory.class);
178     assertThat(factory.getConfiguration().getVfsImpl()).isSameAs(JBoss6VFS.class);
179 
180     assertThat(factory.getConfiguration().isCacheEnabled()).isFalse();
181     assertThat(factory.getConfiguration().isUseGeneratedKeys()).isTrue();
182     assertThat(factory.getConfiguration().getDefaultExecutorType()).isSameAs(ExecutorType.REUSE);
183   }
184 
185   @Test
186   void testSpecifyVariablesOnly() throws Exception {
187     setupFactoryBean();
188 
189     var customConfiguration = new Configuration();
190     var variables = new Properties();
191     variables.put("username", "sa");
192     customConfiguration.setVariables(variables);
193     factoryBean.setConfiguration(customConfiguration);
194 
195     factoryBean.setConfigurationProperties(null);
196 
197     var factory = factoryBean.getObject();
198 
199     assertThat(factory.getConfiguration().getVariables().size()).isEqualTo(1);
200     assertThat(factory.getConfiguration().getVariables().get("username")).isEqualTo("sa");
201   }
202 
203   @Test
204   void testSpecifyVariablesAndConfigurationProperties() throws Exception {
205     setupFactoryBean();
206 
207     var customConfiguration = new Configuration();
208     var variables = new Properties();
209     variables.put("url", "jdbc:localhost/test");
210     variables.put("username", "sa");
211     customConfiguration.setVariables(variables);
212     factoryBean.setConfiguration(customConfiguration);
213 
214     var configurationProperties = new Properties();
215     configurationProperties.put("username", "dev");
216     configurationProperties.put("password", "Passw0rd");
217     factoryBean.setConfigurationProperties(configurationProperties);
218 
219     var factory = factoryBean.getObject();
220 
221     assertThat(factory.getConfiguration().getVariables().size()).isEqualTo(3);
222     assertThat(factory.getConfiguration().getVariables().get("url")).isEqualTo("jdbc:localhost/test");
223     assertThat(factory.getConfiguration().getVariables().get("username")).isEqualTo("dev");
224     assertThat(factory.getConfiguration().getVariables().get("password")).isEqualTo("Passw0rd");
225   }
226 
227   @Test
228   void testSpecifyConfigurationPropertiesOnly() throws Exception {
229     setupFactoryBean();
230 
231     var customConfiguration = new Configuration();
232     customConfiguration.setVariables(null);
233     factoryBean.setConfiguration(customConfiguration);
234 
235     var configurationProperties = new Properties();
236     configurationProperties.put("username", "dev");
237     factoryBean.setConfigurationProperties(configurationProperties);
238 
239     var factory = factoryBean.getObject();
240 
241     assertThat(factory.getConfiguration().getVariables().size()).isEqualTo(1);
242     assertThat(factory.getConfiguration().getVariables().get("username")).isEqualTo("dev");
243   }
244 
245   @Test
246   void testNotSpecifyVariableAndConfigurationProperties() throws Exception {
247     setupFactoryBean();
248 
249     var customConfiguration = new Configuration();
250     customConfiguration.setVariables(null);
251     factoryBean.setConfiguration(customConfiguration);
252 
253     factoryBean.setConfigurationProperties(null);
254 
255     var factory = factoryBean.getObject();
256 
257     assertThat(factory.getConfiguration().getVariables()).isNull();
258   }
259 
260   @Test
261   void testNullConfigLocation() throws Exception {
262     setupFactoryBean();
263     // default should also be null, but test explicitly setting to null
264     factoryBean.setConfigLocation(null);
265 
266     assertDefaultConfig(factoryBean.getObject());
267   }
268 
269   @Test
270   void testSetConfigLocation() throws Exception {
271     setupFactoryBean();
272 
273     factoryBean.setConfigLocation(new ClassPathResource("org/mybatis/spring/mybatis-config.xml"));
274 
275     var factory = factoryBean.getObject();
276 
277     assertThat(factory.getConfiguration().getEnvironment().getId())
278         .isEqualTo(SqlSessionFactoryBean.class.getSimpleName());
279     assertThat(factory.getConfiguration().getEnvironment().getDataSource()).isSameAs(dataSource);
280     assertThat(factory.getConfiguration().getEnvironment().getTransactionFactory().getClass())
281         .isSameAs(org.mybatis.spring.transaction.SpringManagedTransactionFactory.class);
282     assertThat(factory.getConfiguration().getVfsImpl()).isSameAs(JBoss6VFS.class);
283 
284     // properties explicitly set differently than the defaults in the config xml
285     assertThat(factory.getConfiguration().isCacheEnabled()).isFalse();
286     assertThat(factory.getConfiguration().isUseGeneratedKeys()).isTrue();
287     assertThat(factory.getConfiguration().getDefaultExecutorType())
288         .isSameAs(org.apache.ibatis.session.ExecutorType.REUSE);
289 
290     // for each statement in the xml file: org.mybatis.spring.TestMapper.xxx & xxx
291     assertThat(factory.getConfiguration().getMappedStatementNames().size()).isEqualTo(8);
292 
293     assertThat(factory.getConfiguration().getResultMapNames().size()).isEqualTo(0);
294     assertThat(factory.getConfiguration().getParameterMapNames().size()).isEqualTo(0);
295   }
296 
297   @Test
298   void testSpecifyConfigurationAndConfigLocation() throws Exception {
299     setupFactoryBean();
300 
301     factoryBean.setConfiguration(new Configuration());
302     factoryBean.setConfigLocation(new ClassPathResource("org/mybatis/spring/mybatis-config.xml"));
303 
304     Throwable e = assertThrows(IllegalStateException.class, factoryBean::getObject);
305     assertThat(e.getMessage())
306         .isEqualTo("Property 'configuration' and 'configLocation' can not specified with together");
307   }
308 
309   @Test
310   void testFragmentsAreReadWithMapperLocations() throws Exception {
311     setupFactoryBean();
312 
313     factoryBean.setMapperLocations(new ClassPathResource("org/mybatis/spring/TestMapper.xml"));
314 
315     var factory = factoryBean.getObject();
316 
317     // one for 'includedSql' and another for 'org.mybatis.spring.TestMapper.includedSql'
318     assertThat(factory.getConfiguration().getSqlFragments().size()).isEqualTo(2);
319   }
320 
321   @Test
322   void testNullMapperLocations() throws Exception {
323     setupFactoryBean();
324     // default should also be null, but test explicitly setting to null
325     factoryBean.setMapperLocations(null);
326 
327     assertDefaultConfig(factoryBean.getObject());
328   }
329 
330   @Test
331   void testEmptyMapperLocations() throws Exception {
332     setupFactoryBean();
333     factoryBean.setMapperLocations();
334 
335     assertDefaultConfig(factoryBean.getObject());
336   }
337 
338   @Test
339   void testMapperLocationsWithNullEntry() throws Exception {
340     setupFactoryBean();
341     factoryBean.setMapperLocations(new Resource[] { null });
342 
343     assertDefaultConfig(factoryBean.getObject());
344   }
345 
346   @Test
347   void testAddATypeHandler() throws Exception {
348     setupFactoryBean();
349     factoryBean.setTypeHandlers(new DummyTypeHandler());
350 
351     var typeHandlerRegistry = factoryBean.getObject().getConfiguration().getTypeHandlerRegistry();
352     assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
353   }
354 
355   @Test
356   void testAddATypeAlias() throws Exception {
357     setupFactoryBean();
358 
359     factoryBean.setTypeAliases(DummyTypeAlias.class);
360     var typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
361     typeAliasRegistry.resolveAlias("testAlias");
362   }
363 
364   @Test
365   void testSearchATypeAliasPackage() throws Exception {
366     setupFactoryBean();
367     factoryBean.setTypeAliasesPackage("org.mybatis.spring.type, org.mybatis.spring.scan");
368 
369     var typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
370     System.out.println(typeAliasRegistry.getTypeAliases().keySet());
371     assertThat(typeAliasRegistry.getTypeAliases().size()).isEqualTo(89);
372     typeAliasRegistry.resolveAlias("testAlias");
373     typeAliasRegistry.resolveAlias("testAlias2");
374     typeAliasRegistry.resolveAlias("dummyTypeHandler");
375     typeAliasRegistry.resolveAlias("dummyTypeHandler2");
376     typeAliasRegistry.resolveAlias("superType");
377     typeAliasRegistry.resolveAlias("dummyMapperFactoryBean");
378     typeAliasRegistry.resolveAlias("scanclass1");
379     typeAliasRegistry.resolveAlias("scanclass2");
380     typeAliasRegistry.resolveAlias("scanenum");
381   }
382 
383   @Test
384   void testSearchATypeAliasPackageWithSuperType() throws Exception {
385     setupFactoryBean();
386     factoryBean.setTypeAliasesSuperType(SuperType.class);
387     factoryBean.setTypeAliasesPackage("org.mybatis.*.type");
388 
389     var typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
390     typeAliasRegistry.resolveAlias("testAlias2");
391     typeAliasRegistry.resolveAlias("superType");
392 
393     assertThrows(TypeException.class, () -> typeAliasRegistry.resolveAlias("testAlias"));
394     assertThrows(TypeException.class, () -> typeAliasRegistry.resolveAlias("dummyTypeHandler"));
395   }
396 
397   @Test
398   void testSearchATypeAliasPackageWithSamePackage() throws Exception {
399     setupFactoryBean();
400     factoryBean.setTypeAliasesPackage("org.mybatis.spring.type, org.*.spring.type");
401 
402     var typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
403     typeAliasRegistry.resolveAlias("testAlias");
404     typeAliasRegistry.resolveAlias("testAlias2");
405     typeAliasRegistry.resolveAlias("dummyTypeHandler");
406     typeAliasRegistry.resolveAlias("superType");
407   }
408 
409   @Test
410   void testSearchATypeHandlerPackage() throws Exception {
411     setupFactoryBean();
412     factoryBean.setTypeHandlersPackage("org.mybatis.**.type");
413 
414     var typeHandlerRegistry = factoryBean.getObject().getConfiguration().getTypeHandlerRegistry();
415     assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
416     assertThat(typeHandlerRegistry.hasTypeHandler(BigDecimal.class)).isTrue();
417     assertThat(typeHandlerRegistry.getTypeHandler(UUID.class)).isInstanceOf(TypeHandlerFactory.InnerTypeHandler.class);
418     assertThat(typeHandlerRegistry.getTypeHandler(AtomicInteger.class)).isInstanceOf(AtomicNumberTypeHandler.class);
419     assertThat(typeHandlerRegistry.getTypeHandler(AtomicLong.class)).isInstanceOf(AtomicNumberTypeHandler.class);
420   }
421 
422   @Test
423   void testSearchATypeHandlerPackageWithSamePackage() throws Exception {
424     setupFactoryBean();
425     factoryBean.setTypeHandlersPackage("org.mybatis.spring.type, org.mybatis.*.type");
426 
427     var typeHandlerRegistry = factoryBean.getObject().getConfiguration().getTypeHandlerRegistry();
428     assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
429     assertThat(typeHandlerRegistry.hasTypeHandler(BigDecimal.class)).isTrue();
430   }
431 
432   @Test
433   void testDefaultEnumTypeHandler() throws Exception {
434     setupFactoryBean();
435     factoryBean.setDefaultEnumTypeHandler(EnumOrdinalTypeHandler.class);
436 
437     var typeHandlerRegistry = factoryBean.getObject().getConfiguration().getTypeHandlerRegistry();
438     assertThat(typeHandlerRegistry.getTypeHandler(MyEnum.class)).isInstanceOf(EnumOrdinalTypeHandler.class);
439   }
440 
441   @Test
442   void testSetObjectFactory() throws Exception {
443     setupFactoryBean();
444     factoryBean.setObjectFactory(new TestObjectFactory());
445 
446     var objectFactory = factoryBean.getObject().getConfiguration().getObjectFactory();
447     assertThat(objectFactory).isInstanceOf(TestObjectFactory.class);
448   }
449 
450   @Test
451   void testSetObjectWrapperFactory() throws Exception {
452     setupFactoryBean();
453     factoryBean.setObjectWrapperFactory(new TestObjectWrapperFactory());
454 
455     var objectWrapperFactory = factoryBean.getObject().getConfiguration().getObjectWrapperFactory();
456     assertThat(objectWrapperFactory).isInstanceOf(TestObjectWrapperFactory.class);
457   }
458 
459   @Test
460   void testAddCache() {
461     setupFactoryBean();
462     var cache = new PerpetualCache("test-cache");
463     this.factoryBean.setCache(cache);
464     assertThat(this.factoryBean.getCache().getId()).isEqualTo("test-cache");
465   }
466 
467   @Test
468   void testScriptingLanguageDriverEmpty() throws Exception {
469     setupFactoryBean();
470     this.factoryBean.setScriptingLanguageDrivers();
471     var registry = this.factoryBean.getObject().getConfiguration().getLanguageRegistry();
472     assertThat(registry.getDefaultDriver()).isInstanceOf(XMLLanguageDriver.class);
473     assertThat(registry.getDefaultDriverClass()).isEqualTo(XMLLanguageDriver.class);
474   }
475 
476   @Test
477   void testScriptingLanguageDriver() throws Exception {
478     setupFactoryBean();
479     this.factoryBean.setScriptingLanguageDrivers(new MyLanguageDriver1(), new MyLanguageDriver2());
480     var registry = this.factoryBean.getObject().getConfiguration().getLanguageRegistry();
481     assertThat(registry.getDefaultDriver()).isInstanceOf(XMLLanguageDriver.class);
482     assertThat(registry.getDefaultDriverClass()).isEqualTo(XMLLanguageDriver.class);
483     assertThat(registry.getDriver(MyLanguageDriver1.class)).isNotNull();
484     assertThat(registry.getDriver(MyLanguageDriver2.class)).isNotNull();
485     assertThat(registry.getDriver(XMLLanguageDriver.class)).isNotNull();
486     assertThat(registry.getDriver(RawLanguageDriver.class)).isNotNull();
487   }
488 
489   @Test
490   void testScriptingLanguageDriverWithDefault() throws Exception {
491     setupFactoryBean();
492     this.factoryBean.setScriptingLanguageDrivers(new MyLanguageDriver1(), new MyLanguageDriver2());
493     this.factoryBean.setDefaultScriptingLanguageDriver(MyLanguageDriver1.class);
494     var registry = this.factoryBean.getObject().getConfiguration().getLanguageRegistry();
495     assertThat(registry.getDefaultDriver()).isInstanceOf(MyLanguageDriver1.class);
496     assertThat(registry.getDefaultDriverClass()).isEqualTo(MyLanguageDriver1.class);
497     assertThat(registry.getDriver(MyLanguageDriver1.class)).isNotNull();
498     assertThat(registry.getDriver(MyLanguageDriver2.class)).isNotNull();
499     assertThat(registry.getDriver(XMLLanguageDriver.class)).isNotNull();
500     assertThat(registry.getDriver(RawLanguageDriver.class)).isNotNull();
501   }
502 
503   @Test
504   void testAppendableMethod() throws Exception {
505     setupFactoryBean();
506     // add values
507     this.factoryBean.addScriptingLanguageDrivers(new MyLanguageDriver1());
508     this.factoryBean.addScriptingLanguageDrivers(new MyLanguageDriver2());
509     this.factoryBean.addPlugins(new MyPlugin1(), new MyPlugin2());
510     this.factoryBean.addPlugins(new MyPlugin3());
511     this.factoryBean.addTypeHandlers(new MyTypeHandler1());
512     this.factoryBean.addTypeHandlers(new MyTypeHandler2(), new MyTypeHandler3());
513     this.factoryBean.addTypeAliases(MyTypeHandler1.class, MyTypeHandler2.class, MyTypeHandler3.class);
514     this.factoryBean.addTypeAliases(MyPlugin1.class);
515     this.factoryBean.addMapperLocations(new ClassPathResource("org/mybatis/spring/TestMapper.xml"),
516         new ClassPathResource("org/mybatis/spring/TestMapper2.xml"));
517     this.factoryBean.addMapperLocations(new ClassPathResource("org/mybatis/spring/TestMapper3.xml"));
518     // ignore null value
519     this.factoryBean.addScriptingLanguageDrivers(null);
520     this.factoryBean.addPlugins(null);
521     this.factoryBean.addTypeHandlers(null);
522     this.factoryBean.addTypeAliases(null);
523     this.factoryBean.addMapperLocations(null);
524     var factory = this.factoryBean.getObject();
525     var languageDriverRegistry = factory.getConfiguration().getLanguageRegistry();
526     var typeHandlerRegistry = factory.getConfiguration().getTypeHandlerRegistry();
527     var typeAliasRegistry = factory.getConfiguration().getTypeAliasRegistry();
528     assertThat(languageDriverRegistry.getDriver(MyLanguageDriver1.class)).isNotNull();
529     assertThat(languageDriverRegistry.getDriver(MyLanguageDriver2.class)).isNotNull();
530     assertThat(typeHandlerRegistry.getTypeHandlers().stream().map(TypeHandler::getClass).map(Class::getSimpleName)
531         .collect(Collectors.toSet())).contains(MyTypeHandler1.class.getSimpleName(),
532             MyTypeHandler2.class.getSimpleName(), MyTypeHandler3.class.getSimpleName());
533     assertThat(typeAliasRegistry.getTypeAliases()).containsKeys(MyTypeHandler1.class.getSimpleName().toLowerCase(),
534         MyTypeHandler2.class.getSimpleName().toLowerCase(), MyTypeHandler3.class.getSimpleName().toLowerCase(),
535         MyPlugin1.class.getSimpleName().toLowerCase());
536     assertThat(factory.getConfiguration().getMappedStatement("org.mybatis.spring.TestMapper.findFail")).isNotNull();
537     assertThat(factory.getConfiguration().getMappedStatement("org.mybatis.spring.TestMapper2.selectOne")).isNotNull();
538     assertThat(factory.getConfiguration().getMappedStatement("org.mybatis.spring.TestMapper3.selectOne")).isNotNull();
539     assertThat(
540         factory.getConfiguration().getInterceptors().stream().map(Interceptor::getClass).map(Class::getSimpleName))
541             .contains(MyPlugin1.class.getSimpleName(), MyPlugin2.class.getSimpleName(),
542                 MyPlugin3.class.getSimpleName());
543   }
544 
545   @Test
546   void testAppendableMethodWithEmpty() throws Exception {
547     setupFactoryBean();
548     this.factoryBean.addScriptingLanguageDrivers();
549     this.factoryBean.addPlugins();
550     this.factoryBean.addTypeHandlers();
551     this.factoryBean.addTypeAliases();
552     this.factoryBean.addMapperLocations();
553     var factory = this.factoryBean.getObject();
554     var languageDriverRegistry = factory.getConfiguration().getLanguageRegistry();
555     var typeHandlerRegistry = factory.getConfiguration().getTypeHandlerRegistry();
556     var typeAliasRegistry = factory.getConfiguration().getTypeAliasRegistry();
557     assertThat(languageDriverRegistry.getDriver(MyLanguageDriver1.class)).isNull();
558     assertThat(languageDriverRegistry.getDriver(MyLanguageDriver2.class)).isNull();
559     assertThat(typeHandlerRegistry.getTypeHandlers()).hasSize(40);
560     assertThat(typeAliasRegistry.getTypeAliases()).hasSize(80);
561     assertThat(factory.getConfiguration().getMappedStatementNames()).isEmpty();
562     assertThat(factory.getConfiguration().getInterceptors()).isEmpty();
563   }
564 
565   @Test
566   void testAppendableMethodWithNull() throws Exception {
567     setupFactoryBean();
568     this.factoryBean.addScriptingLanguageDrivers(null);
569     this.factoryBean.addPlugins(null);
570     this.factoryBean.addTypeHandlers(null);
571     this.factoryBean.addTypeAliases(null);
572     this.factoryBean.addMapperLocations(null);
573     var factory = this.factoryBean.getObject();
574     var languageDriverRegistry = factory.getConfiguration().getLanguageRegistry();
575     var typeHandlerRegistry = factory.getConfiguration().getTypeHandlerRegistry();
576     var typeAliasRegistry = factory.getConfiguration().getTypeAliasRegistry();
577     assertThat(languageDriverRegistry.getDriver(MyLanguageDriver1.class)).isNull();
578     assertThat(languageDriverRegistry.getDriver(MyLanguageDriver2.class)).isNull();
579     assertThat(typeHandlerRegistry.getTypeHandlers()).hasSize(40);
580     assertThat(typeAliasRegistry.getTypeAliases()).hasSize(80);
581     assertThat(factory.getConfiguration().getMappedStatementNames()).isEmpty();
582     assertThat(factory.getConfiguration().getInterceptors()).isEmpty();
583   }
584 
585   private void assertDefaultConfig(SqlSessionFactory factory) {
586     assertConfig(factory, SqlSessionFactoryBean.class.getSimpleName(),
587         org.mybatis.spring.transaction.SpringManagedTransactionFactory.class);
588     assertThat(factory.getConfiguration().getVariables().size()).isEqualTo(0);
589   }
590 
591   private void assertConfig(SqlSessionFactory factory, Class<? extends TransactionFactory> transactionFactoryClass) {
592     assertConfig(factory, SqlSessionFactoryBean.class.getSimpleName(), transactionFactoryClass);
593   }
594 
595   private void assertConfig(SqlSessionFactory factory, String environment,
596       Class<? extends TransactionFactory> transactionFactoryClass) {
597     assertThat(factory.getConfiguration().getEnvironment().getId()).isEqualTo(environment);
598     assertThat(factory.getConfiguration().getEnvironment().getDataSource()).isSameAs(dataSource);
599     assertThat(factory.getConfiguration().getEnvironment().getTransactionFactory().getClass())
600         .isSameAs(transactionFactoryClass);
601 
602     // no mappers configured => no mapped statements or other parsed elements
603     assertThat(factory.getConfiguration().getMappedStatementNames().size()).isEqualTo(0);
604     assertThat(factory.getConfiguration().getResultMapNames().size()).isEqualTo(0);
605     assertThat(factory.getConfiguration().getParameterMapNames().size()).isEqualTo(0);
606     assertThat(factory.getConfiguration().getSqlFragments().size()).isEqualTo(0);
607   }
608 
609   private static class MyLanguageDriver1 extends RawLanguageDriver {
610   }
611 
612   private static class MyLanguageDriver2 extends RawLanguageDriver {
613   }
614 
615   private static class MyBasePlugin implements Interceptor {
616 
617     @Override
618     public Object intercept(Invocation invocation) throws Throwable {
619       return null;
620     }
621 
622     @Override
623     public Object plugin(Object target) {
624       return Interceptor.super.plugin(target);
625     }
626 
627     @Override
628     public void setProperties(Properties properties) {
629       Interceptor.super.setProperties(properties);
630     }
631   }
632 
633   @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
634   private static class MyPlugin1 extends MyBasePlugin {
635 
636   }
637 
638   @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
639   private static class MyPlugin2 extends MyBasePlugin {
640 
641   }
642 
643   @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
644   private static class MyPlugin3 extends MyBasePlugin {
645 
646   }
647 
648   private static class MyBaseTypeHandler extends BaseTypeHandler<String> {
649 
650     @Override
651     public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
652         throws SQLException {
653     }
654 
655     @Override
656     public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
657       return null;
658     }
659 
660     @Override
661     public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
662       return null;
663     }
664 
665     @Override
666     public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
667       return null;
668     }
669   }
670 
671   private static class MyTypeHandler1 extends MyBaseTypeHandler {
672   }
673 
674   private static class MyTypeHandler2 extends MyBaseTypeHandler {
675   }
676 
677   private static class MyTypeHandler3 extends MyBaseTypeHandler {
678   }
679 
680   private enum MyEnum {
681   }
682 
683 }