• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / spring / #1227

14 Sep 2023 05:15PM CUT coverage: 89.622%. Remained the same
#1227

Pull #854

github

web-flow
Update dependency net.bytebuddy:byte-buddy-agent to v1.14.8
Pull Request #854: Update dependency net.bytebuddy:byte-buddy-agent to v1.14.8

829 of 925 relevant lines covered (89.62%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.39
/src/main/java/org/mybatis/spring/SqlSessionFactoryBean.java
1
/*
2
 * Copyright 2010-2023 the original author or authors.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *    https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package org.mybatis.spring;
17

18
import static org.springframework.util.Assert.notNull;
19
import static org.springframework.util.Assert.state;
20
import static org.springframework.util.ObjectUtils.isEmpty;
21
import static org.springframework.util.StringUtils.hasLength;
22
import static org.springframework.util.StringUtils.tokenizeToStringArray;
23

24
import java.io.IOException;
25
import java.lang.reflect.Modifier;
26
import java.sql.SQLException;
27
import java.util.ArrayList;
28
import java.util.Arrays;
29
import java.util.HashSet;
30
import java.util.List;
31
import java.util.Optional;
32
import java.util.Properties;
33
import java.util.Set;
34
import java.util.function.IntFunction;
35
import java.util.stream.Stream;
36

37
import javax.sql.DataSource;
38

39
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
40
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
41
import org.apache.ibatis.cache.Cache;
42
import org.apache.ibatis.executor.ErrorContext;
43
import org.apache.ibatis.io.Resources;
44
import org.apache.ibatis.io.VFS;
45
import org.apache.ibatis.mapping.DatabaseIdProvider;
46
import org.apache.ibatis.mapping.Environment;
47
import org.apache.ibatis.plugin.Interceptor;
48
import org.apache.ibatis.reflection.factory.ObjectFactory;
49
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
50
import org.apache.ibatis.scripting.LanguageDriver;
51
import org.apache.ibatis.session.Configuration;
52
import org.apache.ibatis.session.SqlSessionFactory;
53
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
54
import org.apache.ibatis.transaction.TransactionFactory;
55
import org.apache.ibatis.type.TypeHandler;
56
import org.mybatis.logging.Logger;
57
import org.mybatis.logging.LoggerFactory;
58
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
59
import org.springframework.beans.factory.FactoryBean;
60
import org.springframework.beans.factory.InitializingBean;
61
import org.springframework.context.ApplicationListener;
62
import org.springframework.context.ConfigurableApplicationContext;
63
import org.springframework.context.event.ContextRefreshedEvent;
64
import org.springframework.core.io.Resource;
65
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
66
import org.springframework.core.io.support.ResourcePatternResolver;
67
import org.springframework.core.type.ClassMetadata;
68
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
69
import org.springframework.core.type.classreading.MetadataReaderFactory;
70
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
71
import org.springframework.util.ClassUtils;
72

73
/**
74
 * {@code FactoryBean} that creates a MyBatis {@code SqlSessionFactory}. This is the usual way to set up a shared
75
 * MyBatis {@code SqlSessionFactory} in a Spring application context; the SqlSessionFactory can then be passed to
76
 * MyBatis-based DAOs via dependency injection.
77
 * <p>
78
 * Either {@code DataSourceTransactionManager} or {@code JtaTransactionManager} can be used for transaction demarcation
79
 * in combination with a {@code SqlSessionFactory}. JTA should be used for transactions which span multiple databases or
80
 * when container managed transactions (CMT) are being used.
81
 *
82
 * @author Putthiphong Boonphong
83
 * @author Hunter Presnall
84
 * @author Eduardo Macarron
85
 * @author Eddú Meléndez
86
 * @author Kazuki Shimizu
87
 * @author Jens Schauder
88
 *
89
 * @see #setConfigLocation
90
 * @see #setDataSource
91
 */
92
public class SqlSessionFactoryBean
1✔
93
    implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ContextRefreshedEvent> {
94

95
  private static final Logger LOGGER = LoggerFactory.getLogger(SqlSessionFactoryBean.class);
1✔
96

97
  private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();
1✔
98
  private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();
1✔
99

100
  private Resource configLocation;
101

102
  private Configuration configuration;
103

104
  private Resource[] mapperLocations;
105

106
  private DataSource dataSource;
107

108
  private TransactionFactory transactionFactory;
109

110
  private Properties configurationProperties;
111

112
  private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
1✔
113

114
  private SqlSessionFactory sqlSessionFactory;
115

116
  // EnvironmentAware requires spring 3.1
117
  private String environment = SqlSessionFactoryBean.class.getSimpleName();
1✔
118

119
  private boolean failFast;
120

121
  private Interceptor[] plugins;
122

123
  private TypeHandler<?>[] typeHandlers;
124

125
  private String typeHandlersPackage;
126

127
  @SuppressWarnings("rawtypes")
128
  private Class<? extends TypeHandler> defaultEnumTypeHandler;
129

130
  private Class<?>[] typeAliases;
131

132
  private String typeAliasesPackage;
133

134
  private Class<?> typeAliasesSuperType;
135

136
  private LanguageDriver[] scriptingLanguageDrivers;
137

138
  private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;
139

140
  // issue #19. No default provider.
141
  private DatabaseIdProvider databaseIdProvider;
142

143
  private Class<? extends VFS> vfs;
144

145
  private Cache cache;
146

147
  private ObjectFactory objectFactory;
148

149
  private ObjectWrapperFactory objectWrapperFactory;
150

151
  /**
152
   * Sets the ObjectFactory.
153
   *
154
   * @since 1.1.2
155
   *
156
   * @param objectFactory
157
   *          a custom ObjectFactory
158
   */
159
  public void setObjectFactory(ObjectFactory objectFactory) {
160
    this.objectFactory = objectFactory;
1✔
161
  }
1✔
162

163
  /**
164
   * Sets the ObjectWrapperFactory.
165
   *
166
   * @since 1.1.2
167
   *
168
   * @param objectWrapperFactory
169
   *          a specified ObjectWrapperFactory
170
   */
171
  public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
172
    this.objectWrapperFactory = objectWrapperFactory;
1✔
173
  }
1✔
174

175
  /**
176
   * Gets the DatabaseIdProvider
177
   *
178
   * @since 1.1.0
179
   *
180
   * @return a specified DatabaseIdProvider
181
   */
182
  public DatabaseIdProvider getDatabaseIdProvider() {
183
    return databaseIdProvider;
×
184
  }
185

186
  /**
187
   * Sets the DatabaseIdProvider. As of version 1.2.2 this variable is not initialized by default.
188
   *
189
   * @since 1.1.0
190
   *
191
   * @param databaseIdProvider
192
   *          a DatabaseIdProvider
193
   */
194
  public void setDatabaseIdProvider(DatabaseIdProvider databaseIdProvider) {
195
    this.databaseIdProvider = databaseIdProvider;
1✔
196
  }
1✔
197

198
  /**
199
   * Gets the VFS.
200
   *
201
   * @return a specified VFS
202
   */
203
  public Class<? extends VFS> getVfs() {
204
    return this.vfs;
×
205
  }
206

207
  /**
208
   * Sets the VFS.
209
   *
210
   * @param vfs
211
   *          a VFS
212
   */
213
  public void setVfs(Class<? extends VFS> vfs) {
214
    this.vfs = vfs;
×
215
  }
×
216

217
  /**
218
   * Gets the Cache.
219
   *
220
   * @return a specified Cache
221
   */
222
  public Cache getCache() {
223
    return this.cache;
1✔
224
  }
225

226
  /**
227
   * Sets the Cache.
228
   *
229
   * @param cache
230
   *          a Cache
231
   */
232
  public void setCache(Cache cache) {
233
    this.cache = cache;
1✔
234
  }
1✔
235

236
  /**
237
   * Mybatis plugin list.
238
   *
239
   * @since 1.0.1
240
   *
241
   * @param plugins
242
   *          list of plugins
243
   */
244
  public void setPlugins(Interceptor... plugins) {
245
    this.plugins = plugins;
1✔
246
  }
1✔
247

248
  /**
249
   * Packages to search for type aliases.
250
   * <p>
251
   * Since 2.0.1, allow to specify a wildcard such as {@code com.example.*.model}.
252
   *
253
   * @since 1.0.1
254
   *
255
   * @param typeAliasesPackage
256
   *          package to scan for domain objects
257
   */
258
  public void setTypeAliasesPackage(String typeAliasesPackage) {
259
    this.typeAliasesPackage = typeAliasesPackage;
1✔
260
  }
1✔
261

262
  /**
263
   * Super class which domain objects have to extend to have a type alias created. No effect if there is no package to
264
   * scan configured.
265
   *
266
   * @since 1.1.2
267
   *
268
   * @param typeAliasesSuperType
269
   *          super class for domain objects
270
   */
271
  public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
272
    this.typeAliasesSuperType = typeAliasesSuperType;
1✔
273
  }
1✔
274

275
  /**
276
   * Packages to search for type handlers.
277
   * <p>
278
   * Since 2.0.1, allow to specify a wildcard such as {@code com.example.*.typehandler}.
279
   *
280
   * @since 1.0.1
281
   *
282
   * @param typeHandlersPackage
283
   *          package to scan for type handlers
284
   */
285
  public void setTypeHandlersPackage(String typeHandlersPackage) {
286
    this.typeHandlersPackage = typeHandlersPackage;
1✔
287
  }
1✔
288

289
  /**
290
   * Set type handlers. They must be annotated with {@code MappedTypes} and optionally with {@code MappedJdbcTypes}
291
   *
292
   * @since 1.0.1
293
   *
294
   * @param typeHandlers
295
   *          Type handler list
296
   */
297
  public void setTypeHandlers(TypeHandler<?>... typeHandlers) {
298
    this.typeHandlers = typeHandlers;
1✔
299
  }
1✔
300

301
  /**
302
   * Set the default type handler class for enum.
303
   *
304
   * @since 2.0.5
305
   *
306
   * @param defaultEnumTypeHandler
307
   *          The default type handler class for enum
308
   */
309
  public void setDefaultEnumTypeHandler(
310
      @SuppressWarnings("rawtypes") Class<? extends TypeHandler> defaultEnumTypeHandler) {
311
    this.defaultEnumTypeHandler = defaultEnumTypeHandler;
1✔
312
  }
1✔
313

314
  /**
315
   * List of type aliases to register. They can be annotated with {@code Alias}
316
   *
317
   * @since 1.0.1
318
   *
319
   * @param typeAliases
320
   *          Type aliases list
321
   */
322
  public void setTypeAliases(Class<?>... typeAliases) {
323
    this.typeAliases = typeAliases;
1✔
324
  }
1✔
325

326
  /**
327
   * If true, a final check is done on Configuration to assure that all mapped statements are fully loaded and there is
328
   * no one still pending to resolve includes. Defaults to false.
329
   *
330
   * @since 1.0.1
331
   *
332
   * @param failFast
333
   *          enable failFast
334
   */
335
  public void setFailFast(boolean failFast) {
336
    this.failFast = failFast;
×
337
  }
×
338

339
  /**
340
   * Set the location of the MyBatis {@code SqlSessionFactory} config file. A typical value is
341
   * "WEB-INF/mybatis-configuration.xml".
342
   *
343
   * @param configLocation
344
   *          a location the MyBatis config file
345
   */
346
  public void setConfigLocation(Resource configLocation) {
347
    this.configLocation = configLocation;
1✔
348
  }
1✔
349

350
  /**
351
   * Set a customized MyBatis configuration.
352
   *
353
   * @param configuration
354
   *          MyBatis configuration
355
   *
356
   * @since 1.3.0
357
   */
358
  public void setConfiguration(Configuration configuration) {
359
    this.configuration = configuration;
1✔
360
  }
1✔
361

362
  /**
363
   * Set locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory} configuration
364
   * at runtime.
365
   * <p>
366
   * This is an alternative to specifying "&lt;sqlmapper&gt;" entries in an MyBatis config file. This property being
367
   * based on Spring's resource abstraction also allows for specifying resource patterns here: e.g.
368
   * "classpath*:sqlmap/*-mapper.xml".
369
   *
370
   * @param mapperLocations
371
   *          location of MyBatis mapper files
372
   */
373
  public void setMapperLocations(Resource... mapperLocations) {
374
    this.mapperLocations = mapperLocations;
1✔
375
  }
1✔
376

377
  /**
378
   * Set optional properties to be passed into the SqlSession configuration, as alternative to a
379
   * {@code &lt;properties&gt;} tag in the configuration xml file. This will be used to resolve placeholders in the
380
   * config file.
381
   *
382
   * @param sqlSessionFactoryProperties
383
   *          optional properties for the SqlSessionFactory
384
   */
385
  public void setConfigurationProperties(Properties sqlSessionFactoryProperties) {
386
    this.configurationProperties = sqlSessionFactoryProperties;
1✔
387
  }
1✔
388

389
  /**
390
   * Set the JDBC {@code DataSource} that this instance should manage transactions for. The {@code DataSource} should
391
   * match the one used by the {@code SqlSessionFactory}: for example, you could specify the same JNDI DataSource for
392
   * both.
393
   * <p>
394
   * A transactional JDBC {@code Connection} for this {@code DataSource} will be provided to application code accessing
395
   * this {@code DataSource} directly via {@code DataSourceUtils} or {@code DataSourceTransactionManager}.
396
   * <p>
397
   * The {@code DataSource} specified here should be the target {@code DataSource} to manage transactions for, not a
398
   * {@code TransactionAwareDataSourceProxy}. Only data access code may work with
399
   * {@code TransactionAwareDataSourceProxy}, while the transaction manager needs to work on the underlying target
400
   * {@code DataSource}. If there's nevertheless a {@code TransactionAwareDataSourceProxy} passed in, it will be
401
   * unwrapped to extract its target {@code DataSource}.
402
   *
403
   * @param dataSource
404
   *          a JDBC {@code DataSource}
405
   */
406
  public void setDataSource(DataSource dataSource) {
407
    if (dataSource instanceof TransactionAwareDataSourceProxy) {
1✔
408
      // If we got a TransactionAwareDataSourceProxy, we need to perform
409
      // transactions for its underlying target DataSource, else data
410
      // access code won't see properly exposed transactions (i.e.
411
      // transactions for the target DataSource).
412
      this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
×
413
    } else {
414
      this.dataSource = dataSource;
1✔
415
    }
416
  }
1✔
417

418
  /**
419
   * Sets the {@code SqlSessionFactoryBuilder} to use when creating the {@code SqlSessionFactory}.
420
   * <p>
421
   * This is mainly meant for testing so that mock SqlSessionFactory classes can be injected. By default,
422
   * {@code SqlSessionFactoryBuilder} creates {@code DefaultSqlSessionFactory} instances.
423
   *
424
   * @param sqlSessionFactoryBuilder
425
   *          a SqlSessionFactoryBuilder
426
   */
427
  public void setSqlSessionFactoryBuilder(SqlSessionFactoryBuilder sqlSessionFactoryBuilder) {
428
    this.sqlSessionFactoryBuilder = sqlSessionFactoryBuilder;
1✔
429
  }
1✔
430

431
  /**
432
   * Set the MyBatis TransactionFactory to use. Default is {@code SpringManagedTransactionFactory}.
433
   * <p>
434
   * The default {@code SpringManagedTransactionFactory} should be appropriate for all cases: be it Spring transaction
435
   * management, EJB CMT or plain JTA. If there is no active transaction, SqlSession operations will execute SQL
436
   * statements non-transactionally.
437
   * <p>
438
   * <b>It is strongly recommended to use the default {@code TransactionFactory}.</b> If not used, any attempt at
439
   * getting an SqlSession through Spring's MyBatis framework will throw an exception if a transaction is active.
440
   *
441
   * @see SpringManagedTransactionFactory
442
   *
443
   * @param transactionFactory
444
   *          the MyBatis TransactionFactory
445
   */
446
  public void setTransactionFactory(TransactionFactory transactionFactory) {
447
    this.transactionFactory = transactionFactory;
1✔
448
  }
1✔
449

450
  /**
451
   * <b>NOTE:</b> This class <em>overrides</em> any {@code Environment} you have set in the MyBatis config file. This is
452
   * used only as a placeholder name. The default value is {@code SqlSessionFactoryBean.class.getSimpleName()}.
453
   *
454
   * @param environment
455
   *          the environment name
456
   */
457
  public void setEnvironment(String environment) {
458
    this.environment = environment;
1✔
459
  }
1✔
460

461
  /**
462
   * Set scripting language drivers.
463
   *
464
   * @param scriptingLanguageDrivers
465
   *          scripting language drivers
466
   *
467
   * @since 2.0.2
468
   */
469
  public void setScriptingLanguageDrivers(LanguageDriver... scriptingLanguageDrivers) {
470
    this.scriptingLanguageDrivers = scriptingLanguageDrivers;
1✔
471
  }
1✔
472

473
  /**
474
   * Set a default scripting language driver class.
475
   *
476
   * @param defaultScriptingLanguageDriver
477
   *          A default scripting language driver class
478
   *
479
   * @since 2.0.2
480
   */
481
  public void setDefaultScriptingLanguageDriver(Class<? extends LanguageDriver> defaultScriptingLanguageDriver) {
482
    this.defaultScriptingLanguageDriver = defaultScriptingLanguageDriver;
1✔
483
  }
1✔
484

485
  /**
486
   * Add locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory} configuration
487
   * at runtime.
488
   * <p>
489
   * This is an alternative to specifying "&lt;sqlmapper&gt;" entries in an MyBatis config file. This property being
490
   * based on Spring's resource abstraction also allows for specifying resource patterns here: e.g.
491
   * "classpath*:sqlmap/*-mapper.xml".
492
   *
493
   * @param mapperLocations
494
   *          location of MyBatis mapper files
495
   *
496
   * @see #setMapperLocations(Resource...)
497
   *
498
   * @since 3.0.2
499
   */
500
  public void addMapperLocations(Resource... mapperLocations) {
501
    setMapperLocations(appendArrays(this.mapperLocations, mapperLocations, Resource[]::new));
1✔
502
  }
1✔
503

504
  /**
505
   * Add type handlers.
506
   *
507
   * @param typeHandlers
508
   *          Type handler list
509
   *
510
   * @since 3.0.2
511
   */
512
  public void addTypeHandlers(TypeHandler<?>... typeHandlers) {
513
    setTypeHandlers(appendArrays(this.typeHandlers, typeHandlers, TypeHandler[]::new));
1✔
514
  }
1✔
515

516
  /**
517
   * Add scripting language drivers.
518
   *
519
   * @param scriptingLanguageDrivers
520
   *          scripting language drivers
521
   *
522
   * @since 3.0.2
523
   */
524
  public void addScriptingLanguageDrivers(LanguageDriver... scriptingLanguageDrivers) {
525
    setScriptingLanguageDrivers(
1✔
526
        appendArrays(this.scriptingLanguageDrivers, scriptingLanguageDrivers, LanguageDriver[]::new));
1✔
527
  }
1✔
528

529
  /**
530
   * Add Mybatis plugins.
531
   *
532
   * @param plugins
533
   *          list of plugins
534
   *
535
   * @since 3.0.2
536
   */
537
  public void addPlugins(Interceptor... plugins) {
538
    setPlugins(appendArrays(this.plugins, plugins, Interceptor[]::new));
1✔
539
  }
1✔
540

541
  /**
542
   * Add type aliases.
543
   *
544
   * @param typeAliases
545
   *          Type aliases list
546
   *
547
   * @since 3.0.2
548
   */
549
  public void addTypeAliases(Class<?>... typeAliases) {
550
    setTypeAliases(appendArrays(this.typeAliases, typeAliases, Class[]::new));
1✔
551
  }
1✔
552

553
  private <T> T[] appendArrays(T[] oldArrays, T[] newArrays, IntFunction<T[]> generator) {
554
    if (oldArrays == null) {
1✔
555
      return newArrays;
1✔
556
    } else {
557
      if (newArrays == null) {
1✔
558
        return oldArrays;
1✔
559
      } else {
560
        List<T> newList = new ArrayList<>(Arrays.asList(oldArrays));
1✔
561
        newList.addAll(Arrays.asList(newArrays));
1✔
562
        return newList.toArray(generator.apply(0));
1✔
563
      }
564
    }
565
  }
566

567
  /**
568
   * {@inheritDoc}
569
   */
570
  @Override
571
  public void afterPropertiesSet() throws Exception {
572
    notNull(dataSource, "Property 'dataSource' is required");
1✔
573
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
1✔
574
    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
1✔
575
        "Property 'configuration' and 'configLocation' can not specified with together");
576

577
    this.sqlSessionFactory = buildSqlSessionFactory();
1✔
578
  }
1✔
579

580
  /**
581
   * Build a {@code SqlSessionFactory} instance.
582
   * <p>
583
   * The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a
584
   * {@code SqlSessionFactory} instance based on a Reader. Since 1.3.0, it can be specified a {@link Configuration}
585
   * instance directly(without config file).
586
   *
587
   * @return SqlSessionFactory
588
   *
589
   * @throws Exception
590
   *           if configuration is failed
591
   */
592
  protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
593

594
    final Configuration targetConfiguration;
595

596
    XMLConfigBuilder xmlConfigBuilder = null;
1✔
597
    if (this.configuration != null) {
1✔
598
      targetConfiguration = this.configuration;
1✔
599
      if (targetConfiguration.getVariables() == null) {
1✔
600
        targetConfiguration.setVariables(this.configurationProperties);
1✔
601
      } else if (this.configurationProperties != null) {
1✔
602
        targetConfiguration.getVariables().putAll(this.configurationProperties);
1✔
603
      }
604
    } else if (this.configLocation != null) {
1✔
605
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
1✔
606
      targetConfiguration = xmlConfigBuilder.getConfiguration();
1✔
607
    } else {
608
      LOGGER.debug(
1✔
609
          () -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
×
610
      targetConfiguration = new Configuration();
1✔
611
      Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
1✔
612
    }
613

614
    Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
1✔
615
    Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
1✔
616
    Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
1✔
617

618
    if (hasLength(this.typeAliasesPackage)) {
1✔
619
      scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
1✔
620
          .filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
1✔
621
          .filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
1✔
622
    }
623

624
    if (!isEmpty(this.typeAliases)) {
1✔
625
      Stream.of(this.typeAliases).forEach(typeAlias -> {
1✔
626
        targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
1✔
627
        LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
1✔
628
      });
1✔
629
    }
630

631
    if (!isEmpty(this.plugins)) {
1✔
632
      Stream.of(this.plugins).forEach(plugin -> {
1✔
633
        targetConfiguration.addInterceptor(plugin);
1✔
634
        LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
1✔
635
      });
1✔
636
    }
637

638
    if (hasLength(this.typeHandlersPackage)) {
1✔
639
      scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
1✔
640
          .filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
1✔
641
          .forEach(targetConfiguration.getTypeHandlerRegistry()::register);
1✔
642
    }
643

644
    if (!isEmpty(this.typeHandlers)) {
1✔
645
      Stream.of(this.typeHandlers).forEach(typeHandler -> {
1✔
646
        targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
1✔
647
        LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
1✔
648
      });
1✔
649
    }
650

651
    targetConfiguration.setDefaultEnumTypeHandler(defaultEnumTypeHandler);
1✔
652

653
    if (!isEmpty(this.scriptingLanguageDrivers)) {
1✔
654
      Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {
1✔
655
        targetConfiguration.getLanguageRegistry().register(languageDriver);
1✔
656
        LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");
1✔
657
      });
1✔
658
    }
659
    Optional.ofNullable(this.defaultScriptingLanguageDriver)
1✔
660
        .ifPresent(targetConfiguration::setDefaultScriptingLanguage);
1✔
661

662
    if (this.databaseIdProvider != null) {// fix #64 set databaseId before parse mapper xmls
1✔
663
      try {
664
        targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
×
665
      } catch (SQLException e) {
×
666
        throw new IOException("Failed getting a databaseId", e);
×
667
      }
×
668
    }
669

670
    Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);
1✔
671

672
    if (xmlConfigBuilder != null) {
1✔
673
      try {
674
        xmlConfigBuilder.parse();
1✔
675
        LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");
1✔
676
      } catch (Exception ex) {
×
677
        throw new IOException("Failed to parse config resource: " + this.configLocation, ex);
×
678
      } finally {
679
        ErrorContext.instance().reset();
1✔
680
      }
681
    }
682

683
    targetConfiguration.setEnvironment(new Environment(this.environment,
1✔
684
        this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
1✔
685
        this.dataSource));
686

687
    if (this.mapperLocations != null) {
1✔
688
      if (this.mapperLocations.length == 0) {
1✔
689
        LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");
1✔
690
      } else {
691
        for (Resource mapperLocation : this.mapperLocations) {
1✔
692
          if (mapperLocation == null) {
1✔
693
            continue;
1✔
694
          }
695
          try {
696
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
1✔
697
                targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
1✔
698
            xmlMapperBuilder.parse();
1✔
699
          } catch (Exception e) {
×
700
            throw new IOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
×
701
          } finally {
702
            ErrorContext.instance().reset();
1✔
703
          }
704
          LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");
1✔
705
        }
706
      }
707
    } else {
708
      LOGGER.debug(() -> "Property 'mapperLocations' was not specified.");
1✔
709
    }
710

711
    return this.sqlSessionFactoryBuilder.build(targetConfiguration);
1✔
712
  }
713

714
  /**
715
   * {@inheritDoc}
716
   */
717
  @Override
718
  public SqlSessionFactory getObject() throws Exception {
719
    if (this.sqlSessionFactory == null) {
1✔
720
      afterPropertiesSet();
1✔
721
    }
722

723
    return this.sqlSessionFactory;
1✔
724
  }
725

726
  /**
727
   * {@inheritDoc}
728
   */
729
  @Override
730
  public Class<? extends SqlSessionFactory> getObjectType() {
731
    return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
1✔
732
  }
733

734
  /**
735
   * {@inheritDoc}
736
   */
737
  @Override
738
  public boolean isSingleton() {
739
    return true;
1✔
740
  }
741

742
  /**
743
   * {@inheritDoc}
744
   */
745
  @Override
746
  public void onApplicationEvent(ContextRefreshedEvent event) {
747
    if (failFast) {
1✔
748
      // fail-fast -> check all statements are completed
749
      this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
×
750
    }
751
  }
1✔
752

753
  private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType) throws IOException {
754
    Set<Class<?>> classes = new HashSet<>();
1✔
755
    String[] packagePatternArray = tokenizeToStringArray(packagePatterns,
1✔
756
        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
757
    for (String packagePattern : packagePatternArray) {
1✔
758
      Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
1✔
759
          + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class");
1✔
760
      for (Resource resource : resources) {
1✔
761
        try {
762
          ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
1✔
763
          Class<?> clazz = Resources.classForName(classMetadata.getClassName());
1✔
764
          if (assignableType == null || assignableType.isAssignableFrom(clazz)) {
1✔
765
            classes.add(clazz);
1✔
766
          }
767
        } catch (Throwable e) {
×
768
          LOGGER.warn(() -> "Cannot load the '" + resource + "'. Cause by " + e.toString());
×
769
        }
1✔
770
      }
771
    }
772
    return classes;
1✔
773
  }
774

775
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc