1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.spring.boot.autoconfigure;
17
18 import static org.assertj.core.api.Assertions.assertThat;
19
20 import com.example.mapper.DateTimeMapper;
21
22 import java.math.BigInteger;
23 import java.sql.CallableStatement;
24 import java.sql.PreparedStatement;
25 import java.sql.ResultSet;
26 import java.util.Map;
27 import java.util.Properties;
28 import java.util.UUID;
29 import java.util.concurrent.atomic.AtomicInteger;
30 import java.util.concurrent.atomic.AtomicLong;
31
32 import javax.sql.DataSource;
33
34 import org.apache.ibatis.cache.impl.PerpetualCache;
35 import org.apache.ibatis.mapping.Environment;
36 import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
37 import org.apache.ibatis.plugin.Interceptor;
38 import org.apache.ibatis.plugin.Intercepts;
39 import org.apache.ibatis.plugin.Invocation;
40 import org.apache.ibatis.plugin.Plugin;
41 import org.apache.ibatis.plugin.Signature;
42 import org.apache.ibatis.scripting.LanguageDriver;
43 import org.apache.ibatis.scripting.LanguageDriverRegistry;
44 import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
45 import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
46 import org.apache.ibatis.session.ExecutorType;
47 import org.apache.ibatis.session.SqlSessionFactory;
48 import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
49 import org.apache.ibatis.type.BaseTypeHandler;
50 import org.apache.ibatis.type.JdbcType;
51 import org.apache.ibatis.type.TypeHandlerRegistry;
52 import org.flywaydb.core.Flyway;
53 import org.junit.jupiter.api.Test;
54 import org.mockito.Mockito;
55 import org.mybatis.scripting.freemarker.FreeMarkerLanguageDriver;
56 import org.mybatis.scripting.thymeleaf.ThymeleafLanguageDriver;
57 import org.mybatis.scripting.velocity.VelocityLanguageDriver;
58 import org.mybatis.spring.SqlSessionFactoryBean;
59 import org.mybatis.spring.SqlSessionTemplate;
60 import org.mybatis.spring.annotation.MapperScan;
61 import org.mybatis.spring.boot.autoconfigure.handler.AtomicNumberTypeHandler;
62 import org.mybatis.spring.boot.autoconfigure.handler.DummyTypeHandler;
63 import org.mybatis.spring.boot.autoconfigure.mapper.CityMapper;
64 import org.mybatis.spring.boot.autoconfigure.repository.CityMapperImpl;
65 import org.mybatis.spring.mapper.MapperFactoryBean;
66 import org.mybatis.spring.mapper.MapperScannerConfigurer;
67 import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
68 import org.springframework.aop.scope.ScopedProxyFactoryBean;
69 import org.springframework.beans.BeansException;
70 import org.springframework.beans.factory.BeanCreationException;
71 import org.springframework.beans.factory.annotation.Qualifier;
72 import org.springframework.beans.factory.config.BeanDefinition;
73 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
74 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
75 import org.springframework.beans.factory.config.PropertiesFactoryBean;
76 import org.springframework.beans.factory.config.RuntimeBeanReference;
77 import org.springframework.boot.autoconfigure.AutoConfigurations;
78 import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
79 import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
80 import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
81 import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
82 import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
83 import org.springframework.boot.test.context.runner.ApplicationContextRunner;
84 import org.springframework.context.annotation.Bean;
85 import org.springframework.context.annotation.Configuration;
86 import org.springframework.context.annotation.Primary;
87 import org.springframework.context.support.SimpleThreadScope;
88 import org.springframework.core.Ordered;
89 import org.springframework.core.annotation.Order;
90
91 import liquibase.integration.spring.SpringLiquibase;
92
93
94
95
96
97
98
99
100 class MybatisAutoConfigurationTest {
101
102 private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
103 .withConfiguration(AutoConfigurations.of(MybatisAutoConfiguration.class));
104
105 @Test
106 void testNoDataSource() {
107 this.contextRunner.withUserConfiguration(PropertyPlaceholderAutoConfiguration.class).run(context -> {
108 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).isEmpty();
109 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).isEmpty();
110 assertThat(context.getBeanNamesForType(MybatisProperties.class)).isEmpty();
111 });
112 }
113
114 @Test
115 void testMultipleDataSource() {
116 this.contextRunner
117 .withUserConfiguration(MultipleDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
118 .run(context -> {
119 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).isEmpty();
120 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).isEmpty();
121 assertThat(context.getBeanNamesForType(MybatisProperties.class)).isEmpty();
122 });
123 }
124
125 @Test
126 void testSingleCandidateDataSource() {
127 this.contextRunner
128 .withUserConfiguration(SingleCandidateDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
129 .run(context -> {
130 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
131 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
132 assertThat(context.getBeanNamesForType(MybatisProperties.class)).hasSize(1);
133 });
134 }
135
136 @Test
137 void testDefaultConfiguration() {
138 this.contextRunner
139 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisLanguageDriverAutoConfiguration.class,
140 MybatisScanMapperConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
141 .run(context -> {
142 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
143 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
144 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
145 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
146 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
147 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
148 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
149 .isFalse();
150 Map<String, LanguageDriver> languageDriverBeans = context.getBeansOfType(LanguageDriver.class);
151 assertThat(languageDriverBeans).hasSize(3).containsKeys("freeMarkerLanguageDriver", "velocityLanguageDriver",
152 "thymeleafLanguageDriver");
153 assertThat(languageDriverBeans.get("freeMarkerLanguageDriver")).isInstanceOf(FreeMarkerLanguageDriver.class);
154 assertThat(languageDriverBeans.get("velocityLanguageDriver")).isInstanceOf(VelocityLanguageDriver.class);
155 assertThat(languageDriverBeans.get("thymeleafLanguageDriver")).isInstanceOf(ThymeleafLanguageDriver.class);
156 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
157 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(XMLLanguageDriver.class);
158 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(XMLLanguageDriver.class);
159 assertThat(languageDriverRegistry.getDriver(XMLLanguageDriver.class)).isNotNull();
160 assertThat(languageDriverRegistry.getDriver(RawLanguageDriver.class)).isNotNull();
161 assertThat(languageDriverRegistry.getDriver(FreeMarkerLanguageDriver.class)).isNotNull();
162 assertThat(languageDriverRegistry.getDriver(VelocityLanguageDriver.class)).isNotNull();
163 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
164 });
165 }
166
167 @Test
168 void testScanWithLazy() {
169 this.contextRunner
170 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
171 PropertyPlaceholderAutoConfiguration.class)
172 .withPropertyValues("mybatis.lazy-initialization:true").run(context -> {
173 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
174 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(0);
175 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
176 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
177 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
178 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
179 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
180 .isFalse();
181 context.getBean(DateTimeMapper.class);
182 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
183 });
184 }
185
186 @Test
187 void testAutoScanWithDefault() {
188 this.contextRunner
189 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
190 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
191 .run(context -> {
192 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
193 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
194 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
195 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
196 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
197 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
198 .isFalse();
199 context.getBean(CityMapper.class);
200 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
201 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
202 .getPropertyValues().getPropertyValue("sqlSessionTemplate").getValue()).getBeanName())
203 .isEqualTo("sqlSessionTemplate");
204 assertThat(context.getBeanFactory()
205 .getBeanDefinition(context.getBeanNamesForType(MapperScannerConfigurer.class)[0]).getRole())
206 .isEqualTo(BeanDefinition.ROLE_INFRASTRUCTURE);
207 });
208 }
209
210 @Test
211 void testAutoScanWithInjectSqlSessionOnMapperScanIsFalse() {
212 this.contextRunner
213 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
214 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
215 .withPropertyValues("mybatis.inject-sql-session-on-mapper-scan:false").run(context -> {
216 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
217 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
218 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
219 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
220 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
221 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
222 .isFalse();
223 context.getBean(CityMapper.class);
224 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
225 assertThat(context.getBeanFactory().getBeanDefinition("cityMapper").getPropertyValues()
226 .getPropertyValue("sqlSessionTemplate")).isNull();
227 assertThat(context.getBeanFactory().getBeanDefinition("cityMapper").getPropertyValues()
228 .getPropertyValue("sqlSessionFactory")).isNull();
229 });
230 }
231
232 @Test
233 void testAutoScanWithLazy() {
234 this.contextRunner
235 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
236 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
237 .withPropertyValues("mybatis.lazy-initialization:true").run(context -> {
238 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
239 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(0);
240 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
241 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
242 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
243 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
244 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
245 .isFalse();
246 context.getBean(CityMapper.class);
247 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
248 });
249 }
250
251 @Test
252 void testAutoScanWithDefaultScope() {
253 this.contextRunner
254 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
255 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
256 .withPropertyValues("mybatis.mapper-default-scope:thread").run(context -> {
257 context.getBean(CityMapper.class);
258 BeanDefinition bd = context.getBeanFactory().getBeanDefinition("cityMapper");
259 assertThat(bd.getBeanClassName()).isEqualTo(ScopedProxyFactoryBean.class.getName());
260 BeanDefinition spbd = context.getBeanFactory().getBeanDefinition("scopedTarget.cityMapper");
261 assertThat(spbd.getBeanClassName()).isEqualTo(MapperFactoryBean.class.getName());
262 assertThat(spbd.getScope()).isEqualTo("thread");
263 });
264 }
265
266 @Test
267 void testAutoScanWithoutDefaultScope() {
268 this.contextRunner
269 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
270 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
271 .run(context -> {
272 context.getBean(CityMapper.class);
273 BeanDefinition df = context.getBeanFactory().getBeanDefinition("cityMapper");
274 assertThat(df.getBeanClassName()).isEqualTo(MapperFactoryBean.class.getName());
275 assertThat(df.getScope()).isEqualTo("singleton");
276 });
277 }
278
279 @Test
280 void testWithConfigLocation() {
281 this.contextRunner
282 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisMapperConfiguration.class,
283 PropertyPlaceholderAutoConfiguration.class)
284 .withPropertyValues("mybatis.config-location:mybatis-config.xml").run(context -> {
285 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
286 assertThat(context.getBeanNamesForType(CityMapperImpl.class)).hasSize(1);
287 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
288 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase()).isTrue();
289 });
290 }
291
292 @Test
293 void testWithCheckConfigLocationFileExists() {
294 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisAutoConfiguration.class)
295 .withPropertyValues("mybatis.config-location:mybatis-config.xml", "mybatis.check-config-location=true")
296 .run(context -> assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1));
297 }
298
299 @Test
300 void testWithCheckConfigLocationFileNotSpecify() {
301 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
302 .withPropertyValues("mybatis.check-config-location=true")
303 .run(context -> assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1));
304 }
305
306 @Test
307 void testWithCheckConfigLocationFileDoesNotExists() {
308 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
309 .withPropertyValues("mybatis.config-location:foo.xml", "mybatis.check-config-location=true")
310 .run(context -> assertThat(context).getFailure().isInstanceOf(BeanCreationException.class)
311 .hasMessageContainingAll("Error creating bean with name 'mybatisAutoConfiguration':",
312 "Cannot find config location: class path resource [foo.xml] (please add config file or check your Mybatis configuration)"));
313 }
314
315 @Test
316 void testWithTypeHandlersPackage() {
317 this.contextRunner
318 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
319 .withPropertyValues("mybatis.type-handlers-package:org.mybatis.spring.boot.autoconfigure.handler")
320 .run(context -> {
321 TypeHandlerRegistry typeHandlerRegistry = context.getBean(SqlSessionFactory.class).getConfiguration()
322 .getTypeHandlerRegistry();
323 assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
324 assertThat(typeHandlerRegistry.hasTypeHandler(AtomicInteger.class)).isTrue();
325 assertThat(typeHandlerRegistry.hasTypeHandler(AtomicLong.class)).isTrue();
326 });
327 }
328
329 @Test
330 void testWithMapperLocation() {
331 this.contextRunner
332 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
333 .withPropertyValues("mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
334 "mybatis.mapper-locations:classpath:org/mybatis/spring/boot/autoconfigure/repository/CityMapper.xml")
335 .run(
336 context -> assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getMappedStatementNames())
337 .hasSize(2));
338 }
339
340 @Test
341 void testWithExecutorType() {
342 this.contextRunner
343 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisMapperConfiguration.class,
344 PropertyPlaceholderAutoConfiguration.class)
345 .withPropertyValues("mybatis.config-location:mybatis-config.xml", "mybatis.executor-type:REUSE")
346 .run(context -> assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType())
347 .isEqualTo(ExecutorType.REUSE));
348 }
349
350 @Test
351 void testDefaultBootConfiguration() {
352 this.contextRunner
353 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
354 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
355 .run(context -> {
356 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
357 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
358 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
359 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
360 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
361 });
362 }
363
364 @Test
365 void testWithInterceptorsOrder1() {
366 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
367 MybatisInterceptorConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
368 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
369 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
370 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors()).hasSize(2);
371 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(0))
372 .isInstanceOf(MyInterceptor2.class);
373 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(1))
374 .isInstanceOf(MyInterceptor.class);
375 });
376 }
377
378 @Test
379 void testWithInterceptorsOrder2() {
380 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
381 MybatisInterceptorConfiguration2.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
382 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
383 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
384 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors()).hasSize(2);
385 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(0))
386 .isInstanceOf(MyInterceptor.class);
387 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(1))
388 .isInstanceOf(MyInterceptor2.class);
389 });
390 }
391
392 @Test
393 void testWithTypeHandlers() {
394 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
395 MybatisTypeHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
396 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
397 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
398 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getTypeHandlerRegistry()
399 .getTypeHandler(UUID.class)).isInstanceOf(MyTypeHandler.class);
400 });
401 }
402
403 @Test
404 void testWithDatabaseIdProvider() {
405 this.contextRunner
406 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, DatabaseProvidersConfiguration.class,
407 PropertyPlaceholderAutoConfiguration.class)
408 .run(context -> assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getDatabaseId())
409 .isEqualTo("h2"));
410 }
411
412 @Test
413 void testMixedWithConfigurationFileAndInterceptor() {
414 this.contextRunner
415 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisInterceptorConfiguration.class,
416 CityMapperRepositoryConfiguration.class)
417 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml").run(context -> {
418 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
419 .getConfiguration();
420 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
421 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
422 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
423 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
424 assertThat(configuration.getInterceptors()).hasSize(2);
425 assertThat(configuration.getInterceptors().get(0)).isInstanceOf(MyInterceptor2.class);
426 assertThat(configuration.getInterceptors().get(1)).isInstanceOf(MyInterceptor.class);
427 });
428 }
429
430 @Test
431 void testMixedWithConfigurationFileAndDatabaseIdProvider() {
432 this.contextRunner
433 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
434 DatabaseProvidersConfiguration.class, CityMapperRepositoryConfiguration.class)
435 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml").run(context -> {
436 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
437 .getConfiguration();
438 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
439 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
440 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
441 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
442 assertThat(configuration.getDatabaseId()).isEqualTo("h2");
443 });
444 }
445
446 @Test
447 void testMixedWithConfigurationFileAndTypeHandlersPackage() {
448 this.contextRunner
449 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
450 CityMapperRepositoryConfiguration.class)
451 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml",
452 "mybatis.type-handlers-package:org.mybatis.spring.boot.autoconfigure.handler.")
453 .run(context -> {
454 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
455 .getConfiguration();
456 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
457 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
458 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
459 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
460 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
461 .isInstanceOf(DummyTypeHandler.class);
462 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicInteger.class))
463 .isInstanceOf(AtomicNumberTypeHandler.class);
464 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicLong.class))
465 .isInstanceOf(AtomicNumberTypeHandler.class);
466 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicInteger.class))
467 .hasToString("type=" + AtomicInteger.class);
468 });
469 }
470
471 @Test
472 void testMixedWithConfigurationFileAndTypeAliasesPackageAndMapperLocations() {
473 this.contextRunner
474 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
475 CityMapperRepositoryConfiguration.class)
476 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml",
477 "mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
478 "mybatis.mapper-locations:classpath:org/mybatis/spring/boot/autoconfigure/repository/CityMapper.xml")
479 .run(context -> {
480 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
481 .getConfiguration();
482 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
483 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
484 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
485 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
486 assertThat(configuration.getMappedStatementNames()).contains("selectCityById");
487 assertThat(configuration.getMappedStatementNames())
488 .contains("org.mybatis.spring.boot.autoconfigure.repository.CityMapperImpl.selectCityById");
489 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("city");
490 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("name");
491 });
492 }
493
494 @Test
495 void testMixedWithFullConfigurations() {
496 this.contextRunner
497 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
498 MybatisInterceptorConfiguration.class, DatabaseProvidersConfiguration.class,
499 CityMapperRepositoryConfiguration.class)
500 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml",
501 "mybatis.type-handlers-package:org.mybatis.spring.**.handler",
502 "mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
503 "mybatis.mapper-locations:classpath:org/mybatis/spring/boot/autoconfigure/repository/CityMapper.xml",
504 "mybatis.executor-type=REUSE")
505 .run(context -> {
506 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
507 .getConfiguration();
508 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
509 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
510 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
511 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
512 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
513 .isInstanceOf(DummyTypeHandler.class);
514 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicInteger.class))
515 .isInstanceOf(AtomicNumberTypeHandler.class);
516 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicLong.class))
517 .isInstanceOf(AtomicNumberTypeHandler.class);
518 assertThat(configuration.getMappedStatementNames()).hasSize(4);
519 assertThat(configuration.getMappedStatementNames()).contains("selectCityById");
520 assertThat(configuration.getMappedStatementNames())
521 .contains("org.mybatis.spring.boot.autoconfigure.repository.CityMapperImpl.selectCityById");
522 assertThat(configuration.getMappedStatementNames()).contains("findById");
523 assertThat(configuration.getMappedStatementNames())
524 .contains("org.mybatis.spring.boot.autoconfigure.mapper.CityMapper.findById");
525 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.REUSE);
526 assertThat(configuration.getInterceptors()).hasSize(2);
527 assertThat(configuration.getInterceptors().get(0)).isInstanceOf(MyInterceptor2.class);
528 assertThat(configuration.getInterceptors().get(1)).isInstanceOf(MyInterceptor.class);
529 assertThat(configuration.getDatabaseId()).isEqualTo("h2");
530 });
531 }
532
533 @Test
534 void testWithMyBatisConfiguration() {
535 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
536 .withPropertyValues("mybatis.configuration.map-underscore-to-camel-case:true").run(context -> assertThat(
537 context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase()).isTrue());
538 }
539
540 @Test
541 void testWithMyBatisConfigurationCustomizer() {
542 this.contextRunner
543 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MyBatisConfigurationCustomizerConfiguration.class)
544 .run(context -> {
545 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
546 assertThat(sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
547 .isInstanceOf(DummyTypeHandler.class);
548 assertThat(sqlSessionFactory.getConfiguration().getCache("test")).isNotNull();
549 });
550 }
551
552 @Test
553 void testWithSqlSessionFactoryBeanCustomizer() {
554 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
555 SqlSessionFactoryBeanCustomizerConfiguration.class).run(context -> {
556 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
557 assertThat(sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
558 .isInstanceOf(DummyTypeHandler.class);
559 assertThat(sqlSessionFactory.getConfiguration().getCache("test")).isNotNull();
560 });
561 }
562
563 @Test
564 void testConfigFileAndConfigurationWithTogether() {
565 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
566 .withPropertyValues("mybatis.config-location:mybatis-config.xml",
567 "mybatis.configuration.default-statement-timeout:30")
568 .run(context -> {
569 assertThat(context).hasFailed();
570 assertThat(context).getFailure().isInstanceOf(BeanCreationException.class)
571 .hasMessageContaining("Property 'configuration' and 'configLocation' can not specified with together");
572 });
573 }
574
575 @Test
576 void testWithoutConfigurationVariablesAndProperties() {
577 this.contextRunner
578 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
579 .run(context -> {
580 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
581 assertThat(variables).isEmpty();
582 });
583 }
584
585 @Test
586 void testWithConfigurationVariablesOnly() {
587 this.contextRunner
588 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
589 .withPropertyValues("mybatis.configuration.variables.key1:value1").run(context -> {
590 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
591 assertThat(variables).hasSize(1);
592 assertThat(variables.getProperty("key1")).isEqualTo("value1");
593 });
594 }
595
596 @Test
597 void testWithConfigurationPropertiesOnly() {
598 this.contextRunner
599 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
600 .withPropertyValues("mybatis.configuration-properties.key2:value2").run(context -> {
601 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
602 assertThat(variables).hasSize(1);
603 assertThat(variables.getProperty("key2")).isEqualTo("value2");
604 });
605 }
606
607 @Test
608 void testWithConfigurationVariablesAndPropertiesOtherKey() {
609 this.contextRunner
610 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
611 .withPropertyValues("mybatis.configuration.variables.key1:value1",
612 "mybatis.configuration-properties.key2:value2")
613 .run(context -> {
614 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
615 assertThat(variables).hasSize(2);
616 assertThat(variables.getProperty("key1")).isEqualTo("value1");
617 assertThat(variables.getProperty("key2")).isEqualTo("value2");
618 });
619 }
620
621 @Test
622 void testWithConfigurationVariablesAndPropertiesSameKey() {
623 this.contextRunner
624 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
625 .withPropertyValues("mybatis.configuration.variables.key:value1", "mybatis.configuration-properties.key:value2")
626 .run(context -> {
627 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
628 assertThat(variables).hasSize(1);
629 assertThat(variables.getProperty("key")).isEqualTo("value2");
630 });
631 }
632
633 @Test
634 void testCustomSqlSessionFactory() {
635 this.contextRunner
636 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
637 CustomSqlSessionFactoryConfiguration.class, CityMapperRepositoryConfiguration.class)
638 .run(context -> {
639 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
640 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getVariables().getProperty("key"))
641 .isEqualTo("value");
642 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
643 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
644 .getPropertyValues().getPropertyValue("sqlSessionFactory").getValue()).getBeanName())
645 .isEqualTo("customSqlSessionFactory");
646 });
647 }
648
649 @Test
650 void testMySqlSessionFactory() {
651 this.contextRunner
652 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MySqlSessionFactoryConfiguration.class)
653 .run(context -> {
654 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
655 assertThat(context.getBean(SqlSessionFactory.class)).isInstanceOf(MySqlSessionFactory.class);
656 });
657 }
658
659 @Test
660 void testCustomSqlSessionTemplate() {
661 this.contextRunner
662 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
663 CustomSqlSessionTemplateConfiguration.class, CityMapperRepositoryConfiguration.class)
664 .run(context -> {
665 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
666 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
667 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
668 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
669 .getPropertyValues().getPropertyValue("sqlSessionTemplate").getValue()).getBeanName())
670 .isEqualTo("customSqlSessionTemplate");
671 });
672 }
673
674 @Test
675 void testMySqlSessionTemplate() {
676 this.contextRunner
677 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MySqlSessionTemplateConfiguration.class)
678 .run(context -> {
679 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
680 assertThat(context.getBean(SqlSessionTemplate.class)).isInstanceOf(MySqlSessionTemplate.class);
681 });
682 }
683
684 @Test
685 void testCustomSqlSessionTemplateAndSqlSessionFactory() {
686 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
687 MybatisBootMapperScanAutoConfiguration.class, CustomSqlSessionFactoryConfiguration.class,
688 CustomSqlSessionTemplateConfiguration.class, CityMapperRepositoryConfiguration.class).run(context -> {
689 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
690 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
691 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
692 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
693 .getPropertyValues().getPropertyValue("sqlSessionTemplate").getValue()).getBeanName())
694 .isEqualTo("customSqlSessionTemplate");
695 });
696 }
697
698 @Test
699 void testTypeAliasesSuperTypeIsSpecify() {
700 this.contextRunner
701 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class)
702 .withPropertyValues("mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
703 "mybatis.type-aliases-super-type:org.mybatis.spring.boot.autoconfigure.domain.Domain")
704 .run(context -> {
705 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
706 .getConfiguration();
707 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("city");
708 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).doesNotContainKey("name");
709 });
710 }
711
712 @Test
713 void testMapperFactoryBean() {
714 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
715 MapperFactoryBeanConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
716 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
717 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
718 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
719 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
720 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
721 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
722 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
723 .isFalse();
724 });
725 }
726
727 @Test
728 void testMapperScannerConfigurer() {
729 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
730 MapperScannerConfigurerConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
731 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
732 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
733 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
734 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
735 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
736 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
737 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
738 .isFalse();
739 });
740 }
741
742 @Test
743 void testDefaultScriptingLanguageIsSpecify() {
744 this.contextRunner
745 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
746 PropertyPlaceholderAutoConfiguration.class)
747 .withPropertyValues(
748 "mybatis.default-scripting-language-driver:org.mybatis.scripting.thymeleaf.ThymeleafLanguageDriver")
749 .run(context -> {
750 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
751 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
752 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(ThymeleafLanguageDriver.class);
753 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(ThymeleafLanguageDriver.class);
754 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
755 });
756 }
757
758 @Test
759 void testExcludeMybatisLanguageDriverAutoConfiguration() {
760 this.contextRunner
761 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
762 PropertyPlaceholderAutoConfiguration.class)
763 .withPropertyValues(
764 "spring.autoconfigure.exclude:org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration")
765 .run(context -> {
766 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
767 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
768 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
769 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
770 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
771 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
772 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
773 .isFalse();
774 assertThat(context.getBeanNamesForType(LanguageDriver.class)).hasSize(0);
775 });
776 }
777
778 @Test
779 void testMybatisLanguageDriverAutoConfigurationWithSingleCandidate() {
780 this.contextRunner
781 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
782 SingleLanguageDriverConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
783 .withPropertyValues(
784 "spring.autoconfigure.exclude:org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration")
785 .run(context -> {
786 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
787 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
788 assertThat(context.getBeanNamesForType(LanguageDriver.class)).hasSize(1);
789 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(ThymeleafLanguageDriver.class);
790 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(ThymeleafLanguageDriver.class);
791 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
792 });
793 }
794
795 @Test
796 void testMybatisLanguageDriverAutoConfigurationWithSingleCandidateWhenDefaultLanguageDriverIsSpecify() {
797 this.contextRunner
798 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
799 SingleLanguageDriverConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
800 .withPropertyValues(
801 "mybatis.default-scripting-language-driver:org.apache.ibatis.scripting.xmltags.XMLLanguageDriver",
802 "spring.autoconfigure.exclude:org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration")
803 .run(context -> {
804 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
805 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
806 assertThat(context.getBeanNamesForType(LanguageDriver.class)).hasSize(1);
807 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(XMLLanguageDriver.class);
808 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(XMLLanguageDriver.class);
809 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
810 });
811 }
812
813 @Test
814 void whenFlywayIsAutoConfiguredThenMybatisSqlSessionTemplateDependsOnFlywayBeans() {
815 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
816 .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class, MybatisAutoConfiguration.class));
817 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {
818 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
819 assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("flywayInitializer", "flyway");
820 });
821 }
822
823 @Test
824 void whenCustomMigrationInitializerIsDefinedThenMybatisSqlSessionTemplateDependsOnIt() {
825 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
826 .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class, MybatisAutoConfiguration.class));
827 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlywayMigrationInitializer.class)
828 .run((context) -> {
829 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
830 assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("flywayMigrationInitializer", "flyway");
831 });
832 }
833
834 @Test
835 void whenCustomFlywayIsDefinedThenMybatisSqlSessionTemplateDependsOnIt() {
836 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
837 .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class, MybatisAutoConfiguration.class));
838 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlyway.class).run((context) -> {
839 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
840 assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("customFlyway");
841 });
842 }
843
844 @Test
845 void whenLiquibaseIsAutoConfiguredThenMybatisSqlSessionTemplateDependsOnSpringLiquibaseBeans() {
846 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
847 .withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class, MybatisAutoConfiguration.class));
848 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {
849 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
850 assertThat(beanDefinition.getDependsOn()).containsExactly("liquibase");
851 });
852 }
853
854 @Test
855 void whenCustomSpringLiquibaseIsDefinedThenMybatisSqlSessionTemplateDependsOnSpringLiquibaseBeans() {
856 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
857 .withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class, MybatisAutoConfiguration.class));
858 contextRunner.withUserConfiguration(LiquibaseUserConfiguration.class, EmbeddedDataSourceConfiguration.class)
859 .run((context) -> {
860 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
861 assertThat(beanDefinition.getDependsOn()).containsExactly("springLiquibase");
862 });
863 }
864
865 @Test
866 void testTypeAliasesWithMultiByteCharacterInPackageName() {
867 this.contextRunner
868 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class)
869 .withPropertyValues("mybatis.config-location:mybatis-config2.xml").run(context -> {
870 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
871 .getConfiguration();
872 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("シティー");
873 });
874 }
875
876 @Configuration
877 static class MultipleDataSourceConfiguration {
878 @Bean
879 DataSource dataSourcePrimary() {
880 return Mockito.mock(DataSource.class);
881 }
882
883 @Bean
884 DataSource dataSourceReplica() {
885 return Mockito.mock(DataSource.class);
886 }
887 }
888
889 @Configuration
890 static class SingleCandidateDataSourceConfiguration {
891 @Bean
892 @Primary
893 DataSource dataSourcePrimary() {
894 return Mockito.mock(DataSource.class);
895 }
896
897 @Bean
898 DataSource dataSourceReplica() {
899 return Mockito.mock(DataSource.class);
900 }
901 }
902
903 @Configuration
904 @MapperScan(basePackages = "com.example.mapper", lazyInitialization = "${mybatis.lazy-initialization:false}")
905 static class MybatisScanMapperConfiguration {
906 }
907
908 @Configuration
909 static class MapperFactoryBeanConfiguration {
910 @Bean
911 MapperFactoryBean<DateTimeMapper> dateTimeMapper(SqlSessionFactory sqlSessionFactory) {
912 MapperFactoryBean<DateTimeMapper> factoryBean = new MapperFactoryBean<>(DateTimeMapper.class);
913 factoryBean.setSqlSessionFactory(sqlSessionFactory);
914 return factoryBean;
915 }
916 }
917
918 @Configuration
919 static class MapperScannerConfigurerConfiguration {
920 @Bean
921 static MapperScannerConfigurer mapperScannerConfigurer() {
922 MapperScannerConfigurer configurer = new MapperScannerConfigurer();
923 configurer.setBasePackage("com.example.mapper");
924 return configurer;
925 }
926 }
927
928 @Configuration
929 static class MybatisBootMapperScanAutoConfiguration implements BeanFactoryPostProcessor {
930 @Override
931 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
932 beanFactory.registerScope("thread", new SimpleThreadScope());
933 }
934 }
935
936 @Configuration
937 static class MybatisMapperConfiguration {
938
939 @Bean
940 public CityMapperImpl cityMapper() {
941 return new CityMapperImpl();
942 }
943
944 }
945
946 @Configuration
947 static class MybatisInterceptorConfiguration {
948
949 @Bean
950 @Order(2)
951 public MyInterceptor myInterceptor() {
952 return new MyInterceptor();
953 }
954
955 @Bean
956 @Order(1)
957 public MyInterceptor2 myInterceptor2() {
958 return new MyInterceptor2();
959 }
960
961 }
962
963 @Configuration
964 static class MybatisInterceptorConfiguration2 {
965
966 @Bean
967 @Order(1)
968 public MyInterceptor myInterceptor() {
969 return new MyInterceptor();
970 }
971
972 @Bean
973 @Order(2)
974 public MyInterceptor2 myInterceptor2() {
975 return new MyInterceptor2();
976 }
977
978 }
979
980 @Configuration
981 static class MybatisTypeHandlerConfiguration {
982
983 @Bean
984 public MyTypeHandler myTypeHandler() {
985 return new MyTypeHandler();
986 }
987
988 }
989
990 @Configuration
991 static class MyBatisConfigurationCustomizerConfiguration {
992 @Bean
993 ConfigurationCustomizer typeHandlerConfigurationCustomizer() {
994 return configuration -> configuration.getTypeHandlerRegistry().register(new DummyTypeHandler());
995 }
996
997 @Bean
998 ConfigurationCustomizer cacheConfigurationCustomizer() {
999 return configuration -> configuration.addCache(new PerpetualCache("test"));
1000 }
1001 }
1002
1003 @Configuration
1004 static class SqlSessionFactoryBeanCustomizerConfiguration {
1005 @Bean
1006 SqlSessionFactoryBeanCustomizer typeHandlerSqlSessionFactoryBeanCustomizer() {
1007 return factoryBean -> factoryBean.setTypeHandlers(new DummyTypeHandler());
1008 }
1009
1010 @Bean
1011 SqlSessionFactoryBeanCustomizer cacheSqlSessionFactoryBeanCustomizer() {
1012 return factoryBean -> factoryBean.setCache(new PerpetualCache("test"));
1013 }
1014 }
1015
1016 @Configuration
1017 static class SingleLanguageDriverConfiguration {
1018 @Bean
1019 ThymeleafLanguageDriver myThymeleafLanguageDriver() {
1020 return new ThymeleafLanguageDriver();
1021 }
1022 }
1023
1024 @Intercepts(@Signature(type = Map.class, method = "get", args = { Object.class }))
1025 static class MyInterceptor implements Interceptor {
1026
1027 @Override
1028 public Object intercept(Invocation invocation) {
1029 return "Test";
1030 }
1031
1032 @Override
1033 public Object plugin(Object target) {
1034 return Plugin.wrap(target, this);
1035 }
1036
1037 @Override
1038 public void setProperties(Properties properties) {
1039
1040 }
1041 }
1042
1043 @Intercepts(@Signature(type = Map.class, method = "get", args = { Object.class }))
1044 static class MyInterceptor2 implements Interceptor {
1045
1046 @Override
1047 public Object intercept(Invocation invocation) {
1048 return "Test2";
1049 }
1050
1051 @Override
1052 public Object plugin(Object target) {
1053 return Plugin.wrap(target, this);
1054 }
1055
1056 @Override
1057 public void setProperties(Properties properties) {
1058
1059 }
1060 }
1061
1062 @Configuration
1063 static class DatabaseProvidersConfiguration {
1064
1065 @Bean
1066 public PropertiesFactoryBean vendorProperties() {
1067 Properties properties = new Properties();
1068 properties.put("SQL Server", "sqlserver");
1069 properties.put("DB2", "db2");
1070 properties.put("H2", "h2");
1071
1072 PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
1073 propertiesFactoryBean.setProperties(properties);
1074 return propertiesFactoryBean;
1075 }
1076
1077 @Bean
1078 public VendorDatabaseIdProvider vendorDatabaseIdProvider(
1079 @Qualifier("vendorProperties") Properties vendorProperties) {
1080 VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
1081 databaseIdProvider.setProperties(vendorProperties);
1082 return databaseIdProvider;
1083 }
1084
1085 }
1086
1087 @Configuration
1088 static class CustomSqlSessionFactoryConfiguration {
1089 @Bean
1090 public SqlSessionFactory customSqlSessionFactory(DataSource dataSource) throws Exception {
1091 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
1092 sqlSessionFactoryBean.setDataSource(dataSource);
1093 Properties props = new Properties();
1094 props.setProperty("key", "value");
1095 sqlSessionFactoryBean.setConfigurationProperties(props);
1096 return sqlSessionFactoryBean.getObject();
1097 }
1098 }
1099
1100 @Configuration
1101 static class MySqlSessionFactoryConfiguration {
1102 @Bean
1103 public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
1104 MySqlSessionFactory sqlSessionFactory = new MySqlSessionFactory(new org.apache.ibatis.session.Configuration());
1105 sqlSessionFactory.getConfiguration()
1106 .setEnvironment(new Environment("", new SpringManagedTransactionFactory(), dataSource));
1107 return sqlSessionFactory;
1108 }
1109 }
1110
1111 @Configuration
1112 static class CustomSqlSessionTemplateConfiguration {
1113 @Bean
1114 public SqlSessionTemplate customSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
1115 return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
1116 }
1117 }
1118
1119 @Configuration
1120 static class MySqlSessionTemplateConfiguration {
1121 @Bean
1122 public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
1123 return new MySqlSessionTemplate(sqlSessionFactory);
1124 }
1125 }
1126
1127 static class MySqlSessionFactory extends DefaultSqlSessionFactory {
1128 MySqlSessionFactory(org.apache.ibatis.session.Configuration configuration) {
1129 super(configuration);
1130 }
1131 }
1132
1133 static class MySqlSessionTemplate extends SqlSessionTemplate {
1134 MySqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
1135 super(sqlSessionFactory);
1136 }
1137 }
1138
1139 static class MyTypeHandler extends BaseTypeHandler<UUID> {
1140
1141 @Override
1142 public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) {
1143
1144 }
1145
1146 @Override
1147 public UUID getNullableResult(ResultSet rs, String columnName) {
1148 return null;
1149 }
1150
1151 @Override
1152 public UUID getNullableResult(ResultSet rs, int columnIndex) {
1153 return null;
1154 }
1155
1156 @Override
1157 public UUID getNullableResult(CallableStatement cs, int columnIndex) {
1158 return null;
1159 }
1160
1161 }
1162
1163 @Configuration
1164 @TestAutoConfigurationPackage(CityMapper.class)
1165 static class CityMapperRepositoryConfiguration {
1166
1167 }
1168
1169 @Configuration(proxyBeanMethods = false)
1170 static class CustomFlywayMigrationInitializer {
1171
1172 @Bean
1173 FlywayMigrationInitializer flywayMigrationInitializer(Flyway flyway) {
1174 FlywayMigrationInitializer initializer = new FlywayMigrationInitializer(flyway);
1175 initializer.setOrder(Ordered.HIGHEST_PRECEDENCE);
1176 return initializer;
1177 }
1178
1179 }
1180
1181 @Configuration(proxyBeanMethods = false)
1182 static class CustomFlyway {
1183
1184 @Bean
1185 Flyway customFlyway() {
1186 return Flyway.configure().load();
1187 }
1188
1189 }
1190
1191 @Configuration(proxyBeanMethods = false)
1192 static class LiquibaseUserConfiguration {
1193
1194 @Bean
1195 SpringLiquibase springLiquibase(DataSource dataSource) {
1196 SpringLiquibase liquibase = new SpringLiquibase();
1197 liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.yaml");
1198 liquibase.setShouldRun(true);
1199 liquibase.setDataSource(dataSource);
1200 return liquibase;
1201 }
1202
1203 }
1204
1205 }