All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mybatis.guice.MyBatisModule Maven / Gradle / Ivy

Go to download

The MyBatis Guice module is easy-to-use Google Guice bridge for MyBatis sql mapping framework.

There is a newer version: 4.0.0
Show newest version
/*
 *    Copyright 2009-2022 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       https://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.mybatis.guice;

import static com.google.inject.name.Names.named;
import static com.google.inject.util.Providers.guicify;
import static org.mybatis.guice.Preconditions.checkArgument;

import com.google.inject.Key;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;

import java.util.Collection;
import java.util.Set;

import javax.inject.Provider;
import javax.sql.DataSource;

import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.type.Alias;
import org.apache.ibatis.type.TypeHandler;
import org.mybatis.guice.binder.AliasBinder;
import org.mybatis.guice.binder.TypeHandlerBinder;
import org.mybatis.guice.configuration.ConfigurationProvider;
import org.mybatis.guice.configuration.ConfigurationSettingListener;
import org.mybatis.guice.configuration.settings.AggressiveLazyLoadingConfigurationSetting;
import org.mybatis.guice.configuration.settings.AliasConfigurationSetting;
import org.mybatis.guice.configuration.settings.AutoMappingBehaviorConfigurationSetting;
import org.mybatis.guice.configuration.settings.CacheEnabledConfigurationSetting;
import org.mybatis.guice.configuration.settings.ConfigurationSetting;
import org.mybatis.guice.configuration.settings.DefaultExecutorTypeConfigurationSetting;
import org.mybatis.guice.configuration.settings.DefaultScriptingLanguageTypeConfigurationSetting;
import org.mybatis.guice.configuration.settings.DefaultStatementTimeoutConfigurationSetting;
import org.mybatis.guice.configuration.settings.InterceptorConfigurationSettingProvider;
import org.mybatis.guice.configuration.settings.JavaTypeAndHandlerConfigurationSettingProvider;
import org.mybatis.guice.configuration.settings.LazyLoadingEnabledConfigurationSetting;
import org.mybatis.guice.configuration.settings.LocalCacheScopeConfigurationSetting;
import org.mybatis.guice.configuration.settings.MapUnderscoreToCamelCaseConfigurationSetting;
import org.mybatis.guice.configuration.settings.MapperConfigurationSetting;
import org.mybatis.guice.configuration.settings.MultipleResultSetsEnabledConfigurationSetting;
import org.mybatis.guice.configuration.settings.ObjectFactoryConfigurationSetting;
import org.mybatis.guice.configuration.settings.ObjectWrapperFactoryConfigurationSetting;
import org.mybatis.guice.configuration.settings.TypeHandlerConfigurationSettingProvider;
import org.mybatis.guice.configuration.settings.UseColumnLabelConfigurationSetting;
import org.mybatis.guice.configuration.settings.UseGeneratedKeysConfigurationSetting;
import org.mybatis.guice.environment.EnvironmentProvider;
import org.mybatis.guice.provision.ConfigurationProviderProvisionListener;
import org.mybatis.guice.provision.KeyMatcher;
import org.mybatis.guice.session.SqlSessionFactoryProvider;
import org.mybatis.guice.type.TypeHandlerProvider;

/**
 * Easy to use helper Module that alleviates users to write the boilerplate google-guice bindings to create the
 * SqlSessionFactory.
 */
public abstract class MyBatisModule extends AbstractMyBatisModule {

  /**
   * The ObjectFactory class reference.
   */
  private Class objectFactoryType = DefaultObjectFactory.class;

  /**
   * The ObjectWrapperFactory class reference.
   */
  private Class objectWrapperFactoryType = DefaultObjectWrapperFactory.class;
  private Class defaultScriptingLanguageType = XMLLanguageDriver.class;

  /**
   * The SqlSessionFactory Provider class reference.
   */
  private Class> sqlSessionFactoryProviderType = SqlSessionFactoryProvider.class;

  private Class> configurationProviderType = ConfigurationProvider.class;

  @Override
  final void internalConfigure() {
    try {
      initialize();

    } finally {

    }

    // fixed bindings
    bind(Environment.class).toProvider(EnvironmentProvider.class).in(Scopes.SINGLETON);

    // replaceable bindings.
    bind(Configuration.class).toProvider(configurationProviderType).in(Scopes.SINGLETON);
    bind(SqlSessionFactory.class).toProvider(sqlSessionFactoryProviderType);

    // parametric bindings
    bind(ObjectFactory.class).to(objectFactoryType).in(Scopes.SINGLETON);
    bind(ObjectWrapperFactory.class).to(objectWrapperFactoryType).in(Scopes.SINGLETON);

    bindConfigurationSettingProvider(new ObjectFactoryConfigurationSetting(objectFactoryType));
    bindConfigurationSettingProvider(new ObjectWrapperFactoryConfigurationSetting(objectWrapperFactoryType));
    bindConfigurationSetting(new DefaultScriptingLanguageTypeConfigurationSetting(defaultScriptingLanguageType));
  }

  /**
   * Set the MyBatis configuration environment id.
   *
   * @param environmentId
   *          the MyBatis configuration environment id
   */
  protected final void environmentId(String environmentId) {
    checkArgument(environmentId != null, "Parameter 'environmentId' must be not null");
    bindConstant().annotatedWith(named("mybatis.environment.id")).to(environmentId);
  }

  /**
   * Lazy loading enabled.
   *
   * @param lazyLoadingEnabled
   *          the lazy loading enabled
   */
  protected final void lazyLoadingEnabled(boolean lazyLoadingEnabled) {
    bindConfigurationSetting(new LazyLoadingEnabledConfigurationSetting(lazyLoadingEnabled));
  }

  /**
   * Aggressive lazy loading.
   *
   * @param aggressiveLazyLoading
   *          the aggressive lazy loading
   */
  protected final void aggressiveLazyLoading(boolean aggressiveLazyLoading) {
    bindConfigurationSetting(new AggressiveLazyLoadingConfigurationSetting(aggressiveLazyLoading));
  }

  /**
   * Multiple result sets enabled.
   *
   * @param multipleResultSetsEnabled
   *          the multiple result sets enabled
   */
  protected final void multipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
    bindConfigurationSetting(new MultipleResultSetsEnabledConfigurationSetting(multipleResultSetsEnabled));
  }

  /**
   * Use generated keys.
   *
   * @param useGeneratedKeys
   *          the use generated keys
   */
  protected final void useGeneratedKeys(boolean useGeneratedKeys) {
    bindConfigurationSetting(new UseGeneratedKeysConfigurationSetting(useGeneratedKeys));
  }

  /**
   * Use column label.
   *
   * @param useColumnLabel
   *          the use column label
   */
  protected final void useColumnLabel(boolean useColumnLabel) {
    bindConfigurationSetting(new UseColumnLabelConfigurationSetting(useColumnLabel));
  }

  /**
   * Use cache enabled.
   *
   * @param useCacheEnabled
   *          the use cache enabled
   */
  protected final void useCacheEnabled(boolean useCacheEnabled) {
    bindConfigurationSetting(new CacheEnabledConfigurationSetting(useCacheEnabled));
  }

  /**
   * Use configuration provider.
   *
   * @param configurationProviderType
   *          provider for Configuration
   */
  protected final void useConfigurationProvider(
      Class> configurationProviderType) {
    this.configurationProviderType = configurationProviderType;
  }

  /**
   * Use sql session factory provider.
   *
   * @param sqlSessionFactoryProvider
   *          provider for SqlSessionFactory
   */
  protected final void useSqlSessionFactoryProvider(
      Class> sqlSessionFactoryProvider) {
    this.sqlSessionFactoryProviderType = sqlSessionFactoryProvider;
  }

  /**
   * Fail fast.
   *
   * @param failFast
   *          the fail fast
   */
  protected final void failFast(boolean failFast) {
    bindBoolean("mybatis.configuration.failFast", failFast);
  }

  /**
   * Maps underscores to camel case.
   *
   * @param mapUnderscoreToCamelCase
   *          Toggles this settings value.
   */
  protected final void mapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
    bindConfigurationSetting(new MapUnderscoreToCamelCaseConfigurationSetting(mapUnderscoreToCamelCase));
  }

  /**
   * set default statement timeout.
   *
   * @param defaultStatementTimeout
   *          default statement timeout in seconds.
   */
  protected final void defaultStatementTimeout(Integer defaultStatementTimeout) {
    bindConfigurationSetting(new DefaultStatementTimeoutConfigurationSetting(defaultStatementTimeout));
  }

  protected final void bindConfigurationSetting(final ConfigurationSetting configurationSetting) {
    bindListener(KeyMatcher.create(Key.get(ConfigurationSettingListener.class)),
        ConfigurationProviderProvisionListener.create(configurationSetting));
  }

  protected final 

> void bindConfigurationSettingProvider( P configurationSettingProvider) { bindListener(KeyMatcher.create(Key.get(ConfigurationSettingListener.class)), ConfigurationProviderProvisionListener.create(configurationSettingProvider, binder())); } private final void bindBoolean(String name, boolean value) { bindConstant().annotatedWith(named(name)).to(value); } /** * Executor type. * * @param executorType * the executor type */ protected final void executorType(ExecutorType executorType) { checkArgument(executorType != null, "Parameter 'executorType' must be not null"); bindConfigurationSetting(new DefaultExecutorTypeConfigurationSetting(executorType)); } /** * Configures the local cache scope setting. * * @param localeCacheScope * The cache scope to use. * @since 3.4 */ protected final void localCacheScope(LocalCacheScope localeCacheScope) { checkArgument(localeCacheScope != null, "Parameter 'localCacheScope' must be not null"); bindConfigurationSetting(new LocalCacheScopeConfigurationSetting(localeCacheScope)); } /** * Auto mapping behavior. * * @param autoMappingBehavior * the auto mapping behavior */ protected final void autoMappingBehavior(AutoMappingBehavior autoMappingBehavior) { checkArgument(autoMappingBehavior != null, "Parameter 'autoMappingBehavior' must be not null"); bindConfigurationSetting(new AutoMappingBehaviorConfigurationSetting(autoMappingBehavior)); } /** * Set the DataSource Provider type has to be bound. * * @param dataSourceProviderType * the DataSource Provider type */ protected final void bindDataSourceProviderType(Class> dataSourceProviderType) { checkArgument(dataSourceProviderType != null, "Parameter 'dataSourceProviderType' must be not null"); bind(DataSource.class).toProvider(dataSourceProviderType).in(Scopes.SINGLETON); } /** * Bind data source provider. * * @param dataSourceProvider * the data source provider */ protected final void bindDataSourceProvider(Provider dataSourceProvider) { checkArgument(dataSourceProvider != null, "Parameter 'dataSourceProvider' must be not null"); bindDataSourceProvider(guicify(dataSourceProvider)); } /** * Bind data source provider. * * @param dataSourceProvider * the data source provider */ protected final void bindDataSourceProvider(com.google.inject.Provider dataSourceProvider) { checkArgument(dataSourceProvider != null, "Parameter 'dataSourceProvider' must be not null"); bind(DataSource.class).toProvider(dataSourceProvider).in(Scopes.SINGLETON); } /** * Bind database id provider. * * @param databaseIdProvider * The DatabaseIdProvider class. */ protected final void bindDatabaseIdProvider(Class databaseIdProvider) { checkArgument(databaseIdProvider != null, "Parameter 'dataSourceProvider' must be not null"); bind(DatabaseIdProvider.class).to(databaseIdProvider).in(Scopes.SINGLETON); } /** * Bind database id provider. * * @param databaseIdProvider * The DatabaseIdProvider instance. */ protected final void bindDatabaseIdProvider(DatabaseIdProvider databaseIdProvider) { checkArgument(databaseIdProvider != null, "Parameter 'dataSourceProvider' must be not null"); bind(DatabaseIdProvider.class).toInstance(databaseIdProvider); } /** * Set the TransactionFactory type has to be bound. * * @param transactionFactoryType * the TransactionFactory type */ protected final void bindTransactionFactoryType(Class transactionFactoryType) { checkArgument(transactionFactoryType != null, "Parameter 'transactionFactoryType' must be not null"); bind(TransactionFactory.class).to(transactionFactoryType).in(Scopes.SINGLETON); } /** * Bind transaction factory. * * @param transactionFactoryProvider * the transaction factory provider */ protected final void bindTransactionFactory(Provider transactionFactoryProvider) { checkArgument(transactionFactoryProvider != null, "Parameter 'transactionFactoryProvider' must be not null"); bindTransactionFactory(guicify(transactionFactoryProvider)); } /** * Bind transaction factory. * * @param transactionFactoryProvider * the transaction factory provider */ protected final void bindTransactionFactory( com.google.inject.Provider transactionFactoryProvider) { checkArgument(transactionFactoryProvider != null, "Parameter 'transactionFactoryProvider' must be not null"); bind(TransactionFactory.class).toProvider(transactionFactoryProvider).in(Scopes.SINGLETON); } /** * Sets the ObjectFactory class. * * @param objectFactoryType * the ObjectFactory type */ protected final void bindObjectFactoryType(Class objectFactoryType) { checkArgument(objectFactoryType != null, "Parameter 'objectFactoryType' must be not null"); this.objectFactoryType = objectFactoryType; } /** * Sets the ObjectWrapperFactory class. * * @param objectWrapperFactoryType * the ObjectFactory type */ protected final void bindObjectWrapperFactoryType(Class objectWrapperFactoryType) { checkArgument(objectFactoryType != null, "Parameter 'objectWrapperFactoryType' must be not null"); this.objectWrapperFactoryType = objectWrapperFactoryType; } /** * Sets the default LanguageDriver class. *

* Due to current limitations in MyBatis, @Inject cannot be used in LanguageDriver class. *

* * @param defaultScriptingLanguageType * the default LanguageDriver type */ protected final void bindDefaultScriptingLanguageType(Class defaultScriptingLanguageType) { checkArgument(defaultScriptingLanguageType != null, "Parameter 'defaultScriptingLanguageType' must be not null"); this.defaultScriptingLanguageType = defaultScriptingLanguageType; } /** * Add a user defined binding. * * @param alias * the string type alias * @return the alias binder */ protected final AliasBinder addAlias(final String alias) { checkArgument(alias != null && alias.length() > 0, "Empty or null 'alias' is not valid"); return new AliasBinder() { @Override public void to(final Class clazz) { checkArgument(clazz != null, "Null type not valid for alias '%s'", alias); bindConfigurationSetting(new AliasConfigurationSetting(alias, clazz)); } }; } /** * Adding simple aliases means that every specified class will be bound using the simple class name, i.e. * {@code com.acme.Foo} becomes {@code Foo}. * * @param type * the specified types have to be bind */ protected final void addSimpleAlias(final Class type) { checkArgument(type != null, "Parameter 'type' must be not null"); String alias = type.getSimpleName(); // check if the class uses the Alias annotation. final Alias annotation = type.getAnnotation(Alias.class); if (annotation != null) { alias = annotation.value(); } addAlias(alias).to(type); } /** * Adding simple aliases means that every specified class will be bound using the simple class name, i.e. * {@code com.acme.Foo} becomes {@code Foo}. * * @param types * the specified types have to be bind */ protected final void addSimpleAliases(final Collection> types) { checkArgument(types != null, "Parameter 'types' must be not null"); for (Class type : types) { addSimpleAlias(type); } } /** * Adds all Classes in the given package as a simple alias. Adding simple aliases means that every specified class * will be bound using the simple class name, i.e. {@code com.acme.Foo} becomes {@code Foo}. * * @param packageName * the specified package to search for classes to alias. * @param test * a test to run against the objects found in the specified package */ protected final void addSimpleAliases(final String packageName, final ResolverUtil.Test test) { addSimpleAliases(getClasses(test, packageName)); } /** * Adds all Classes in the given package as a simple alias. Adding simple aliases means that every specified class * will be bound using the simple class name, i.e. {@code com.acme.Foo} becomes {@code Foo}. * * @param packageName * the specified package to search for classes to alias */ protected final void addSimpleAliases(final String packageName) { addSimpleAliases(getClasses(packageName)); } /** * Add a user defined Type Handler letting google-guice creating it. * * @param * the generic type * @param type * the specified type has to be handled. * @return the type handler binder */ protected final TypeHandlerBinder handleType(final Class type) { checkArgument(type != null, "Parameter 'type' must be not null"); return new TypeHandlerBinder() { @Override public void with(final Class> handler) { checkArgument(handler != null, "TypeHandler must not be null for '%s'", type.getName()); bindTypeHandler(TypeLiteral.get(handler)); bindConfigurationSettingProvider(JavaTypeAndHandlerConfigurationSettingProvider.create(type, Key.get(handler))); } @Override public void with(final TypeLiteral> handler) { checkArgument(handler != null, "TypeHandler must not be null for '%s'", type.getName()); bindTypeHandler(handler); bindConfigurationSettingProvider(JavaTypeAndHandlerConfigurationSettingProvider.create(type, Key.get(handler))); } @Override public void withProvidedTypeHandler(final Class> handler) { checkArgument(handler != null, "TypeHandler must not be null for '%s'", type.getName()); bindProvidedTypeHandler(TypeLiteral.get(handler), type); bindConfigurationSettingProvider(JavaTypeAndHandlerConfigurationSettingProvider.create(type, Key.get(handler))); } @Override public void withProvidedTypeHandler(final TypeLiteral> handler) { checkArgument(handler != null, "TypeHandler must not be null for '%s'", type.getName()); bindProvidedTypeHandler(handler, type); bindConfigurationSettingProvider(JavaTypeAndHandlerConfigurationSettingProvider.create(type, Key.get(handler))); } final > void bindTypeHandler(TypeLiteral typeHandlerType) { bind(typeHandlerType).in(Scopes.SINGLETON); } final > void bindProvidedTypeHandler(TypeLiteral typeHandlerType, Class type) { bind(typeHandlerType).toProvider(guicify(new TypeHandlerProvider(typeHandlerType, type))) .in(Scopes.SINGLETON); } }; } /** * Adds the user defined MyBatis type handler, letting google-guice creating it. * * @param handlerClass * the handler type. */ protected final void addTypeHandlerClass(final Class> handlerClass) { checkArgument(handlerClass != null, "Parameter 'handlerClass' must not be null"); bind(TypeLiteral.get(handlerClass)).in(Scopes.SINGLETON); bindConfigurationSettingProvider(new TypeHandlerConfigurationSettingProvider(Key.get(handlerClass))); } /** * Adds the user defined MyBatis type handlers, letting google-guice creating it. * * @param handlersClasses * the handler type. */ protected final void addTypeHandlersClasses(Collection>> handlersClasses) { checkArgument(handlersClasses != null, "Parameter 'handlersClasses' must not be null"); for (Class> handlerClass : handlersClasses) { addTypeHandlerClass(handlerClass); } } /** * Adds the user defined MyBatis type handlers in the given package, letting google-guice creating it. * * @param packageName * the package where looking for type handlers. */ protected final void addTypeHandlerClasses(String packageName) { checkArgument(packageName != null, "Parameter 'packageName' must not be null"); addTypeHandlersClasses( new ResolverUtil>().find(new ResolverUtil.IsA(TypeHandler.class), packageName).getClasses()); } /** * Adds the user defined myBatis interceptor plugins type, letting google-guice creating it. * * @param interceptorClass * The user defined MyBatis interceptor plugin type */ protected final void addInterceptorClass(final Class interceptorClass) { checkArgument(interceptorClass != null, "Parameter 'interceptorClass' must not be null"); bindConfigurationSettingProvider(new InterceptorConfigurationSettingProvider(interceptorClass)); } /** * Adds the user defined MyBatis interceptors plugins types, letting google-guice creating them. * * @param interceptorsClasses * the user defined MyBatis Interceptors plugins types */ protected final void addInterceptorsClasses(Collection> interceptorsClasses) { checkArgument(interceptorsClasses != null, "Parameter 'interceptorsClasses' must not be null"); for (Class interceptorClass : interceptorsClasses) { addInterceptorClass(interceptorClass); } } /** * Adds the user defined MyBatis interceptors plugins types in the given package, letting google-guice creating them. * * @param packageName * the package where looking for Interceptors plugins types. */ protected final void addInterceptorsClasses(String packageName) { checkArgument(packageName != null, "Parameter 'packageName' must not be null"); addInterceptorsClasses( new ResolverUtil().find(new ResolverUtil.IsA(Interceptor.class), packageName).getClasses()); } /** * Adds the user defined mapper classes. * * @param mapperClass * the user defined mapper classes. */ protected final void addMapperClass(Class mapperClass) { checkArgument(mapperClass != null, "Parameter 'mapperClass' must not be null"); bindListener(KeyMatcher.create(Key.get(ConfigurationSettingListener.class)), ConfigurationProviderProvisionListener.create(new MapperConfigurationSetting(mapperClass))); bindMapper(mapperClass); } /** * Adds the user defined mapper classes. * * @param mapperClasses * the user defined mapper classes */ protected final void addMapperClasses(Collection> mapperClasses) { checkArgument(mapperClasses != null, "Parameter 'mapperClasses' must not be null"); for (Class mapperClass : mapperClasses) { addMapperClass(mapperClass); } } /** * Adds the user defined mapper classes. * * @param packageName * the specified package to search for mappers to add. */ protected final void addMapperClasses(final String packageName) { addMapperClasses(getClasses(packageName)); } /** * Adds the user defined mapper classes. * * @param packageName * the specified package to search for mappers to add. * @param test * a test to run against the objects found in the specified package. */ protected final void addMapperClasses(final String packageName, final ResolverUtil.Test test) { addMapperClasses(getClasses(test, packageName)); } /** * Return a set of all classes contained in the given package. * * @param packageName * the package has to be analyzed. * @return a set of all classes contained in the given package. */ private static Set> getClasses(String packageName) { return getClasses(new ResolverUtil.IsA(Object.class), packageName); } /** * Return a set of all classes contained in the given package that match with the given test requirement. * * @param test * the class filter on the given package. * @param packageName * the package has to be analyzed. * @return a set of all classes contained in the given package. */ private static Set> getClasses(ResolverUtil.Test test, String packageName) { checkArgument(test != null, "Parameter 'test' must not be null"); checkArgument(packageName != null, "Parameter 'packageName' must not be null"); return new ResolverUtil().find(test, packageName).getClasses(); } }