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.flyway.autoconfigure.FlywayAutoConfiguration;
80 import org.springframework.boot.flyway.autoconfigure.FlywayMigrationInitializer;
81 import org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;
82 import org.springframework.boot.liquibase.autoconfigure.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).hasMessageContaining(
311 "Cannot find config location: class path resource [foo.xml] (please add config file or check your Mybatis configuration)"));
312 }
313
314 @Test
315 void testWithTypeHandlersPackage() {
316 this.contextRunner
317 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
318 .withPropertyValues("mybatis.type-handlers-package:org.mybatis.spring.boot.autoconfigure.handler")
319 .run(context -> {
320 TypeHandlerRegistry typeHandlerRegistry = context.getBean(SqlSessionFactory.class).getConfiguration()
321 .getTypeHandlerRegistry();
322 assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
323 assertThat(typeHandlerRegistry.hasTypeHandler(AtomicInteger.class)).isTrue();
324 assertThat(typeHandlerRegistry.hasTypeHandler(AtomicLong.class)).isTrue();
325 });
326 }
327
328 @Test
329 void testWithMapperLocation() {
330 this.contextRunner
331 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
332 .withPropertyValues("mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
333 "mybatis.mapper-locations:classpath:org/mybatis/spring/boot/autoconfigure/repository/CityMapper.xml")
334 .run(
335 context -> assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getMappedStatementNames())
336 .hasSize(2));
337 }
338
339 @Test
340 void testWithExecutorType() {
341 this.contextRunner
342 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisMapperConfiguration.class,
343 PropertyPlaceholderAutoConfiguration.class)
344 .withPropertyValues("mybatis.config-location:mybatis-config.xml", "mybatis.executor-type:REUSE")
345 .run(context -> assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType())
346 .isEqualTo(ExecutorType.REUSE));
347 }
348
349 @Test
350 void testDefaultBootConfiguration() {
351 this.contextRunner
352 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
353 PropertyPlaceholderAutoConfiguration.class, CityMapperRepositoryConfiguration.class)
354 .run(context -> {
355 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
356 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
357 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
358 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
359 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
360 });
361 }
362
363 @Test
364 void testWithInterceptorsOrder1() {
365 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
366 MybatisInterceptorConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
367 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
368 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
369 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors()).hasSize(2);
370 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(0))
371 .isInstanceOf(MyInterceptor2.class);
372 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(1))
373 .isInstanceOf(MyInterceptor.class);
374 });
375 }
376
377 @Test
378 void testWithInterceptorsOrder2() {
379 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
380 MybatisInterceptorConfiguration2.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
381 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
382 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
383 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors()).hasSize(2);
384 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(0))
385 .isInstanceOf(MyInterceptor.class);
386 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getInterceptors().get(1))
387 .isInstanceOf(MyInterceptor2.class);
388 });
389 }
390
391 @Test
392 void testWithTypeHandlers() {
393 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
394 MybatisTypeHandlerConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
395 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
396 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
397 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getTypeHandlerRegistry()
398 .getTypeHandler(UUID.class)).isInstanceOf(MyTypeHandler.class);
399 });
400 }
401
402 @Test
403 void testWithDatabaseIdProvider() {
404 this.contextRunner
405 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, DatabaseProvidersConfiguration.class,
406 PropertyPlaceholderAutoConfiguration.class)
407 .run(context -> assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getDatabaseId())
408 .isEqualTo("h2"));
409 }
410
411 @Test
412 void testMixedWithConfigurationFileAndInterceptor() {
413 this.contextRunner
414 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisInterceptorConfiguration.class,
415 CityMapperRepositoryConfiguration.class)
416 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml").run(context -> {
417 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
418 .getConfiguration();
419 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
420 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
421 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
422 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
423 assertThat(configuration.getInterceptors()).hasSize(2);
424 assertThat(configuration.getInterceptors().get(0)).isInstanceOf(MyInterceptor2.class);
425 assertThat(configuration.getInterceptors().get(1)).isInstanceOf(MyInterceptor.class);
426 });
427 }
428
429 @Test
430 void testMixedWithConfigurationFileAndDatabaseIdProvider() {
431 this.contextRunner
432 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
433 DatabaseProvidersConfiguration.class, CityMapperRepositoryConfiguration.class)
434 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml").run(context -> {
435 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
436 .getConfiguration();
437 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
438 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
439 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
440 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
441 assertThat(configuration.getDatabaseId()).isEqualTo("h2");
442 });
443 }
444
445 @Test
446 void testMixedWithConfigurationFileAndTypeHandlersPackage() {
447 this.contextRunner
448 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
449 CityMapperRepositoryConfiguration.class)
450 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml",
451 "mybatis.type-handlers-package:org.mybatis.spring.boot.autoconfigure.handler.")
452 .run(context -> {
453 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
454 .getConfiguration();
455 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
456 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
457 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
458 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
459 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
460 .isInstanceOf(DummyTypeHandler.class);
461 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicInteger.class))
462 .isInstanceOf(AtomicNumberTypeHandler.class);
463 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicLong.class))
464 .isInstanceOf(AtomicNumberTypeHandler.class);
465 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicInteger.class))
466 .hasToString("type=" + AtomicInteger.class);
467 });
468 }
469
470 @Test
471 void testMixedWithConfigurationFileAndTypeAliasesPackageAndMapperLocations() {
472 this.contextRunner
473 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
474 CityMapperRepositoryConfiguration.class)
475 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml",
476 "mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
477 "mybatis.mapper-locations:classpath:org/mybatis/spring/boot/autoconfigure/repository/CityMapper.xml")
478 .run(context -> {
479 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
480 .getConfiguration();
481 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
482 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
483 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
484 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
485 assertThat(configuration.getMappedStatementNames()).contains("selectCityById");
486 assertThat(configuration.getMappedStatementNames())
487 .contains("org.mybatis.spring.boot.autoconfigure.repository.CityMapperImpl.selectCityById");
488 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("city");
489 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("name");
490 });
491 }
492
493 @Test
494 void testMixedWithFullConfigurations() {
495 this.contextRunner
496 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
497 MybatisInterceptorConfiguration.class, DatabaseProvidersConfiguration.class,
498 CityMapperRepositoryConfiguration.class)
499 .withPropertyValues("mybatis.config-location:mybatis-config-settings-only.xml",
500 "mybatis.type-handlers-package:org.mybatis.spring.**.handler",
501 "mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
502 "mybatis.mapper-locations:classpath:org/mybatis/spring/boot/autoconfigure/repository/CityMapper.xml",
503 "mybatis.executor-type=REUSE")
504 .run(context -> {
505 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
506 .getConfiguration();
507 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
508 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
509 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
510 assertThat(configuration.getDefaultFetchSize()).isEqualTo(1000);
511 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
512 .isInstanceOf(DummyTypeHandler.class);
513 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicInteger.class))
514 .isInstanceOf(AtomicNumberTypeHandler.class);
515 assertThat(configuration.getTypeHandlerRegistry().getTypeHandler(AtomicLong.class))
516 .isInstanceOf(AtomicNumberTypeHandler.class);
517 assertThat(configuration.getMappedStatementNames()).hasSize(4);
518 assertThat(configuration.getMappedStatementNames()).contains("selectCityById");
519 assertThat(configuration.getMappedStatementNames())
520 .contains("org.mybatis.spring.boot.autoconfigure.repository.CityMapperImpl.selectCityById");
521 assertThat(configuration.getMappedStatementNames()).contains("findById");
522 assertThat(configuration.getMappedStatementNames())
523 .contains("org.mybatis.spring.boot.autoconfigure.mapper.CityMapper.findById");
524 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.REUSE);
525 assertThat(configuration.getInterceptors()).hasSize(2);
526 assertThat(configuration.getInterceptors().get(0)).isInstanceOf(MyInterceptor2.class);
527 assertThat(configuration.getInterceptors().get(1)).isInstanceOf(MyInterceptor.class);
528 assertThat(configuration.getDatabaseId()).isEqualTo("h2");
529 });
530 }
531
532 @Test
533 void testWithMyBatisConfiguration() {
534 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
535 .withPropertyValues("mybatis.configuration.map-underscore-to-camel-case:true").run(context -> assertThat(
536 context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase()).isTrue());
537 }
538
539 @Test
540 void testWithMyBatisConfigurationCustomizer() {
541 this.contextRunner
542 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MyBatisConfigurationCustomizerConfiguration.class)
543 .run(context -> {
544 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
545 assertThat(sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
546 .isInstanceOf(DummyTypeHandler.class);
547 assertThat(sqlSessionFactory.getConfiguration().getCache("test")).isNotNull();
548 });
549 }
550
551 @Test
552 void testWithSqlSessionFactoryBeanCustomizer() {
553 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
554 SqlSessionFactoryBeanCustomizerConfiguration.class).run(context -> {
555 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
556 assertThat(sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().getTypeHandler(BigInteger.class))
557 .isInstanceOf(DummyTypeHandler.class);
558 assertThat(sqlSessionFactory.getConfiguration().getCache("test")).isNotNull();
559 });
560 }
561
562 @Test
563 void testConfigFileAndConfigurationWithTogether() {
564 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
565 .withPropertyValues("mybatis.config-location:mybatis-config.xml",
566 "mybatis.configuration.default-statement-timeout:30")
567 .run(context -> {
568 assertThat(context).hasFailed();
569 assertThat(context).getFailure().isInstanceOf(BeanCreationException.class)
570 .hasMessageContaining("Property 'configuration' and 'configLocation' can not specified with together");
571 });
572 }
573
574 @Test
575 void testWithoutConfigurationVariablesAndProperties() {
576 this.contextRunner
577 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
578 .run(context -> {
579 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
580 assertThat(variables).isEmpty();
581 });
582 }
583
584 @Test
585 void testWithConfigurationVariablesOnly() {
586 this.contextRunner
587 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
588 .withPropertyValues("mybatis.configuration.variables.key1:value1").run(context -> {
589 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
590 assertThat(variables).hasSize(1);
591 assertThat(variables.getProperty("key1")).isEqualTo("value1");
592 });
593 }
594
595 @Test
596 void testWithConfigurationPropertiesOnly() {
597 this.contextRunner
598 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
599 .withPropertyValues("mybatis.configuration-properties.key2:value2").run(context -> {
600 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
601 assertThat(variables).hasSize(1);
602 assertThat(variables.getProperty("key2")).isEqualTo("value2");
603 });
604 }
605
606 @Test
607 void testWithConfigurationVariablesAndPropertiesOtherKey() {
608 this.contextRunner
609 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
610 .withPropertyValues("mybatis.configuration.variables.key1:value1",
611 "mybatis.configuration-properties.key2:value2")
612 .run(context -> {
613 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
614 assertThat(variables).hasSize(2);
615 assertThat(variables.getProperty("key1")).isEqualTo("value1");
616 assertThat(variables.getProperty("key2")).isEqualTo("value2");
617 });
618 }
619
620 @Test
621 void testWithConfigurationVariablesAndPropertiesSameKey() {
622 this.contextRunner
623 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
624 .withPropertyValues("mybatis.configuration.variables.key:value1", "mybatis.configuration-properties.key:value2")
625 .run(context -> {
626 Properties variables = context.getBean(SqlSessionFactory.class).getConfiguration().getVariables();
627 assertThat(variables).hasSize(1);
628 assertThat(variables.getProperty("key")).isEqualTo("value2");
629 });
630 }
631
632 @Test
633 void testCustomSqlSessionFactory() {
634 this.contextRunner
635 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
636 CustomSqlSessionFactoryConfiguration.class, CityMapperRepositoryConfiguration.class)
637 .run(context -> {
638 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
639 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().getVariables().getProperty("key"))
640 .isEqualTo("value");
641 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
642 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
643 .getPropertyValues().getPropertyValue("sqlSessionFactory").getValue()).getBeanName())
644 .isEqualTo("customSqlSessionFactory");
645 });
646 }
647
648 @Test
649 void testMySqlSessionFactory() {
650 this.contextRunner
651 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MySqlSessionFactoryConfiguration.class)
652 .run(context -> {
653 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
654 assertThat(context.getBean(SqlSessionFactory.class)).isInstanceOf(MySqlSessionFactory.class);
655 });
656 }
657
658 @Test
659 void testCustomSqlSessionTemplate() {
660 this.contextRunner
661 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
662 CustomSqlSessionTemplateConfiguration.class, CityMapperRepositoryConfiguration.class)
663 .run(context -> {
664 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
665 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
666 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
667 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
668 .getPropertyValues().getPropertyValue("sqlSessionTemplate").getValue()).getBeanName())
669 .isEqualTo("customSqlSessionTemplate");
670 });
671 }
672
673 @Test
674 void testMySqlSessionTemplate() {
675 this.contextRunner
676 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MySqlSessionTemplateConfiguration.class)
677 .run(context -> {
678 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
679 assertThat(context.getBean(SqlSessionTemplate.class)).isInstanceOf(MySqlSessionTemplate.class);
680 });
681 }
682
683 @Test
684 void testCustomSqlSessionTemplateAndSqlSessionFactory() {
685 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
686 MybatisBootMapperScanAutoConfiguration.class, CustomSqlSessionFactoryConfiguration.class,
687 CustomSqlSessionTemplateConfiguration.class, CityMapperRepositoryConfiguration.class).run(context -> {
688 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
689 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
690 assertThat(context.getBeanNamesForType(CityMapper.class)).hasSize(1);
691 assertThat(((RuntimeBeanReference) context.getBeanFactory().getBeanDefinition("cityMapper")
692 .getPropertyValues().getPropertyValue("sqlSessionTemplate").getValue()).getBeanName())
693 .isEqualTo("customSqlSessionTemplate");
694 });
695 }
696
697 @Test
698 void testTypeAliasesSuperTypeIsSpecify() {
699 this.contextRunner
700 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class)
701 .withPropertyValues("mybatis.type-aliases-package:org.mybatis.spring.boot.autoconfigure.domain",
702 "mybatis.type-aliases-super-type:org.mybatis.spring.boot.autoconfigure.domain.Domain")
703 .run(context -> {
704 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
705 .getConfiguration();
706 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("city");
707 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).doesNotContainKey("name");
708 });
709 }
710
711 @Test
712 void testMapperFactoryBean() {
713 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
714 MapperFactoryBeanConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
715 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
716 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
717 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
718 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
719 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
720 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
721 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
722 .isFalse();
723 });
724 }
725
726 @Test
727 void testMapperScannerConfigurer() {
728 this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,
729 MapperScannerConfigurerConfiguration.class, PropertyPlaceholderAutoConfiguration.class).run(context -> {
730 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
731 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
732 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
733 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
734 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
735 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
736 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
737 .isFalse();
738 });
739 }
740
741 @Test
742 void testDefaultScriptingLanguageIsSpecify() {
743 this.contextRunner
744 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
745 PropertyPlaceholderAutoConfiguration.class)
746 .withPropertyValues(
747 "mybatis.default-scripting-language-driver:org.mybatis.scripting.thymeleaf.ThymeleafLanguageDriver")
748 .run(context -> {
749 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
750 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
751 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(ThymeleafLanguageDriver.class);
752 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(ThymeleafLanguageDriver.class);
753 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
754 });
755 }
756
757 @Test
758 void testExcludeMybatisLanguageDriverAutoConfiguration() {
759 this.contextRunner
760 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
761 PropertyPlaceholderAutoConfiguration.class)
762 .withPropertyValues(
763 "spring.autoconfigure.exclude:org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration")
764 .run(context -> {
765 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
766 assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
767 assertThat(context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
768 assertThat(context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
769 assertThat(context.getBeanNamesForType(DateTimeMapper.class)).hasSize(1);
770 assertThat(context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
771 assertThat(context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase())
772 .isFalse();
773 assertThat(context.getBeanNamesForType(LanguageDriver.class)).hasSize(0);
774 });
775 }
776
777 @Test
778 void testMybatisLanguageDriverAutoConfigurationWithSingleCandidate() {
779 this.contextRunner
780 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
781 SingleLanguageDriverConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
782 .withPropertyValues(
783 "spring.autoconfigure.exclude:org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration")
784 .run(context -> {
785 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
786 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
787 assertThat(context.getBeanNamesForType(LanguageDriver.class)).hasSize(1);
788 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(ThymeleafLanguageDriver.class);
789 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(ThymeleafLanguageDriver.class);
790 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
791 });
792 }
793
794 @Test
795 void testMybatisLanguageDriverAutoConfigurationWithSingleCandidateWhenDefaultLanguageDriverIsSpecify() {
796 this.contextRunner
797 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisScanMapperConfiguration.class,
798 SingleLanguageDriverConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
799 .withPropertyValues(
800 "mybatis.default-scripting-language-driver:org.apache.ibatis.scripting.xmltags.XMLLanguageDriver",
801 "spring.autoconfigure.exclude:org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration")
802 .run(context -> {
803 SqlSessionFactory sqlSessionFactory = context.getBean(SqlSessionFactory.class);
804 LanguageDriverRegistry languageDriverRegistry = sqlSessionFactory.getConfiguration().getLanguageRegistry();
805 assertThat(context.getBeanNamesForType(LanguageDriver.class)).hasSize(1);
806 assertThat(languageDriverRegistry.getDefaultDriverClass()).isEqualTo(XMLLanguageDriver.class);
807 assertThat(languageDriverRegistry.getDefaultDriver()).isInstanceOf(XMLLanguageDriver.class);
808 assertThat(languageDriverRegistry.getDriver(ThymeleafLanguageDriver.class)).isNotNull();
809 });
810 }
811
812 @Test
813 void whenFlywayIsAutoConfiguredThenMybatisSqlSessionTemplateDependsOnFlywayBeans() {
814 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
815 .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class, MybatisAutoConfiguration.class));
816 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {
817 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
818 assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("flywayInitializer", "flyway");
819 });
820 }
821
822 @Test
823 void whenCustomMigrationInitializerIsDefinedThenMybatisSqlSessionTemplateDependsOnIt() {
824 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
825 .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class, MybatisAutoConfiguration.class));
826 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlywayMigrationInitializer.class)
827 .run((context) -> {
828 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
829 assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("flywayMigrationInitializer", "flyway");
830 });
831 }
832
833 @Test
834 void whenCustomFlywayIsDefinedThenMybatisSqlSessionTemplateDependsOnIt() {
835 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
836 .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class, MybatisAutoConfiguration.class));
837 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlyway.class).run((context) -> {
838 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
839 assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("customFlyway");
840 });
841 }
842
843 @Test
844 void whenLiquibaseIsAutoConfiguredThenMybatisSqlSessionTemplateDependsOnSpringLiquibaseBeans() {
845 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
846 .withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class, MybatisAutoConfiguration.class));
847 contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {
848 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
849 assertThat(beanDefinition.getDependsOn()).containsExactly("liquibase");
850 });
851 }
852
853 @Test
854 void whenCustomSpringLiquibaseIsDefinedThenMybatisSqlSessionTemplateDependsOnSpringLiquibaseBeans() {
855 ApplicationContextRunner contextRunner = new ApplicationContextRunner()
856 .withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class, MybatisAutoConfiguration.class));
857 contextRunner.withUserConfiguration(LiquibaseUserConfiguration.class, EmbeddedDataSourceConfiguration.class)
858 .run((context) -> {
859 BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("sqlSessionTemplate");
860 assertThat(beanDefinition.getDependsOn()).containsExactly("springLiquibase");
861 });
862 }
863
864 @Test
865 void testTypeAliasesWithMultiByteCharacterInPackageName() {
866 this.contextRunner
867 .withUserConfiguration(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class)
868 .withPropertyValues("mybatis.config-location:mybatis-config2.xml").run(context -> {
869 org.apache.ibatis.session.Configuration configuration = context.getBean(SqlSessionFactory.class)
870 .getConfiguration();
871 assertThat(configuration.getTypeAliasRegistry().getTypeAliases()).containsKey("シティー");
872 });
873 }
874
875 @Configuration
876 static class MultipleDataSourceConfiguration {
877 @Bean
878 DataSource dataSourcePrimary() {
879 return Mockito.mock(DataSource.class);
880 }
881
882 @Bean
883 DataSource dataSourceReplica() {
884 return Mockito.mock(DataSource.class);
885 }
886 }
887
888 @Configuration
889 static class SingleCandidateDataSourceConfiguration {
890 @Bean
891 @Primary
892 DataSource dataSourcePrimary() {
893 return Mockito.mock(DataSource.class);
894 }
895
896 @Bean
897 DataSource dataSourceReplica() {
898 return Mockito.mock(DataSource.class);
899 }
900 }
901
902 @Configuration
903 @MapperScan(basePackages = "com.example.mapper", lazyInitialization = "${mybatis.lazy-initialization:false}")
904 static class MybatisScanMapperConfiguration {
905 }
906
907 @Configuration
908 static class MapperFactoryBeanConfiguration {
909 @Bean
910 MapperFactoryBean<DateTimeMapper> dateTimeMapper(SqlSessionFactory sqlSessionFactory) {
911 MapperFactoryBean<DateTimeMapper> factoryBean = new MapperFactoryBean<>(DateTimeMapper.class);
912 factoryBean.setSqlSessionFactory(sqlSessionFactory);
913 return factoryBean;
914 }
915 }
916
917 @Configuration
918 static class MapperScannerConfigurerConfiguration {
919 @Bean
920 static MapperScannerConfigurer mapperScannerConfigurer() {
921 MapperScannerConfigurer configurer = new MapperScannerConfigurer();
922 configurer.setBasePackage("com.example.mapper");
923 return configurer;
924 }
925 }
926
927 @Configuration
928 static class MybatisBootMapperScanAutoConfiguration implements BeanFactoryPostProcessor {
929 @Override
930 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
931 beanFactory.registerScope("thread", new SimpleThreadScope());
932 }
933 }
934
935 @Configuration
936 static class MybatisMapperConfiguration {
937
938 @Bean
939 public CityMapperImpl cityMapper() {
940 return new CityMapperImpl();
941 }
942
943 }
944
945 @Configuration
946 static class MybatisInterceptorConfiguration {
947
948 @Bean
949 @Order(2)
950 public MyInterceptor myInterceptor() {
951 return new MyInterceptor();
952 }
953
954 @Bean
955 @Order(1)
956 public MyInterceptor2 myInterceptor2() {
957 return new MyInterceptor2();
958 }
959
960 }
961
962 @Configuration
963 static class MybatisInterceptorConfiguration2 {
964
965 @Bean
966 @Order(1)
967 public MyInterceptor myInterceptor() {
968 return new MyInterceptor();
969 }
970
971 @Bean
972 @Order(2)
973 public MyInterceptor2 myInterceptor2() {
974 return new MyInterceptor2();
975 }
976
977 }
978
979 @Configuration
980 static class MybatisTypeHandlerConfiguration {
981
982 @Bean
983 public MyTypeHandler myTypeHandler() {
984 return new MyTypeHandler();
985 }
986
987 }
988
989 @Configuration
990 static class MyBatisConfigurationCustomizerConfiguration {
991 @Bean
992 ConfigurationCustomizer typeHandlerConfigurationCustomizer() {
993 return configuration -> configuration.getTypeHandlerRegistry().register(new DummyTypeHandler());
994 }
995
996 @Bean
997 ConfigurationCustomizer cacheConfigurationCustomizer() {
998 return configuration -> configuration.addCache(new PerpetualCache("test"));
999 }
1000 }
1001
1002 @Configuration
1003 static class SqlSessionFactoryBeanCustomizerConfiguration {
1004 @Bean
1005 SqlSessionFactoryBeanCustomizer typeHandlerSqlSessionFactoryBeanCustomizer() {
1006 return factoryBean -> factoryBean.setTypeHandlers(new DummyTypeHandler());
1007 }
1008
1009 @Bean
1010 SqlSessionFactoryBeanCustomizer cacheSqlSessionFactoryBeanCustomizer() {
1011 return factoryBean -> factoryBean.setCache(new PerpetualCache("test"));
1012 }
1013 }
1014
1015 @Configuration
1016 static class SingleLanguageDriverConfiguration {
1017 @Bean
1018 ThymeleafLanguageDriver myThymeleafLanguageDriver() {
1019 return new ThymeleafLanguageDriver();
1020 }
1021 }
1022
1023 @Intercepts(@Signature(type = Map.class, method = "get", args = { Object.class }))
1024 static class MyInterceptor implements Interceptor {
1025
1026 @Override
1027 public Object intercept(Invocation invocation) {
1028 return "Test";
1029 }
1030
1031 @Override
1032 public Object plugin(Object target) {
1033 return Plugin.wrap(target, this);
1034 }
1035
1036 @Override
1037 public void setProperties(Properties properties) {
1038
1039 }
1040 }
1041
1042 @Intercepts(@Signature(type = Map.class, method = "get", args = { Object.class }))
1043 static class MyInterceptor2 implements Interceptor {
1044
1045 @Override
1046 public Object intercept(Invocation invocation) {
1047 return "Test2";
1048 }
1049
1050 @Override
1051 public Object plugin(Object target) {
1052 return Plugin.wrap(target, this);
1053 }
1054
1055 @Override
1056 public void setProperties(Properties properties) {
1057
1058 }
1059 }
1060
1061 @Configuration
1062 static class DatabaseProvidersConfiguration {
1063
1064 @Bean
1065 public PropertiesFactoryBean vendorProperties() {
1066 Properties properties = new Properties();
1067 properties.put("SQL Server", "sqlserver");
1068 properties.put("DB2", "db2");
1069 properties.put("H2", "h2");
1070
1071 PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
1072 propertiesFactoryBean.setProperties(properties);
1073 return propertiesFactoryBean;
1074 }
1075
1076 @Bean
1077 public VendorDatabaseIdProvider vendorDatabaseIdProvider(
1078 @Qualifier("vendorProperties") Properties vendorProperties) {
1079 VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
1080 databaseIdProvider.setProperties(vendorProperties);
1081 return databaseIdProvider;
1082 }
1083
1084 }
1085
1086 @Configuration
1087 static class CustomSqlSessionFactoryConfiguration {
1088 @Bean
1089 public SqlSessionFactory customSqlSessionFactory(DataSource dataSource) throws Exception {
1090 SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
1091 sqlSessionFactoryBean.setDataSource(dataSource);
1092 Properties props = new Properties();
1093 props.setProperty("key", "value");
1094 sqlSessionFactoryBean.setConfigurationProperties(props);
1095 return sqlSessionFactoryBean.getObject();
1096 }
1097 }
1098
1099 @Configuration
1100 static class MySqlSessionFactoryConfiguration {
1101 @Bean
1102 public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
1103 MySqlSessionFactory sqlSessionFactory = new MySqlSessionFactory(new org.apache.ibatis.session.Configuration());
1104 sqlSessionFactory.getConfiguration()
1105 .setEnvironment(new Environment("", new SpringManagedTransactionFactory(), dataSource));
1106 return sqlSessionFactory;
1107 }
1108 }
1109
1110 @Configuration
1111 static class CustomSqlSessionTemplateConfiguration {
1112 @Bean
1113 public SqlSessionTemplate customSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
1114 return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
1115 }
1116 }
1117
1118 @Configuration
1119 static class MySqlSessionTemplateConfiguration {
1120 @Bean
1121 public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
1122 return new MySqlSessionTemplate(sqlSessionFactory);
1123 }
1124 }
1125
1126 static class MySqlSessionFactory extends DefaultSqlSessionFactory {
1127 MySqlSessionFactory(org.apache.ibatis.session.Configuration configuration) {
1128 super(configuration);
1129 }
1130 }
1131
1132 static class MySqlSessionTemplate extends SqlSessionTemplate {
1133 MySqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
1134 super(sqlSessionFactory);
1135 }
1136 }
1137
1138 static class MyTypeHandler extends BaseTypeHandler<UUID> {
1139
1140 @Override
1141 public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType) {
1142
1143 }
1144
1145 @Override
1146 public UUID getNullableResult(ResultSet rs, String columnName) {
1147 return null;
1148 }
1149
1150 @Override
1151 public UUID getNullableResult(ResultSet rs, int columnIndex) {
1152 return null;
1153 }
1154
1155 @Override
1156 public UUID getNullableResult(CallableStatement cs, int columnIndex) {
1157 return null;
1158 }
1159
1160 }
1161
1162 @Configuration
1163 @TestAutoConfigurationPackage(CityMapper.class)
1164 static class CityMapperRepositoryConfiguration {
1165
1166 }
1167
1168 @Configuration(proxyBeanMethods = false)
1169 static class CustomFlywayMigrationInitializer {
1170
1171 @Bean
1172 FlywayMigrationInitializer flywayMigrationInitializer(Flyway flyway) {
1173 FlywayMigrationInitializer initializer = new FlywayMigrationInitializer(flyway);
1174 initializer.setOrder(Ordered.HIGHEST_PRECEDENCE);
1175 return initializer;
1176 }
1177
1178 }
1179
1180 @Configuration(proxyBeanMethods = false)
1181 static class CustomFlyway {
1182
1183 @Bean
1184 Flyway customFlyway() {
1185 return Flyway.configure().load();
1186 }
1187
1188 }
1189
1190 @Configuration(proxyBeanMethods = false)
1191 static class LiquibaseUserConfiguration {
1192
1193 @Bean
1194 SpringLiquibase springLiquibase(DataSource dataSource) {
1195 SpringLiquibase liquibase = new SpringLiquibase();
1196 liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.yaml");
1197 liquibase.setShouldRun(true);
1198 liquibase.setDataSource(dataSource);
1199 return liquibase;
1200 }
1201
1202 }
1203
1204 }