View Javadoc
1   /*
2    *    Copyright 2009-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.guice;
17  
18  import static com.google.inject.matcher.Matchers.annotatedWith;
19  import static com.google.inject.matcher.Matchers.any;
20  import static com.google.inject.matcher.Matchers.not;
21  import static com.google.inject.name.Names.named;
22  import static com.google.inject.util.Providers.guicify;
23  import static org.mybatis.guice.Preconditions.checkArgument;
24  
25  import com.google.inject.AbstractModule;
26  import com.google.inject.Binder;
27  import com.google.inject.Scopes;
28  import com.google.inject.matcher.AbstractMatcher;
29  
30  import java.lang.reflect.Method;
31  import java.util.Set;
32  
33  import org.apache.ibatis.io.ResolverUtil;
34  import org.apache.ibatis.session.SqlSession;
35  import org.apache.ibatis.session.SqlSessionManager;
36  import org.mybatis.guice.mappers.MapperProvider;
37  import org.mybatis.guice.session.SqlSessionManagerProvider;
38  import org.mybatis.guice.transactional.Transactional;
39  import org.mybatis.guice.transactional.TransactionalMethodInterceptor;
40  
41  abstract class AbstractMyBatisModule extends AbstractModule {
42  
43    protected static final AbstractMatcher<Method> DECLARED_BY_OBJECT = new AbstractMatcher<Method>() {
44      @Override
45      public boolean matches(Method method) {
46        return method.getDeclaringClass() == Object.class;
47      }
48    };
49  
50    protected static final AbstractMatcher<Method> SYNTHETIC = new AbstractMatcher<Method>() {
51      @Override
52      public boolean matches(Method method) {
53        return method.isSynthetic();
54      }
55    };
56  
57    private ClassLoader resourcesClassLoader = getDefaultClassLoader();
58  
59    private ClassLoader driverClassLoader = getDefaultClassLoader();
60  
61    /**
62     * Return a set of all classes contained in the given package.
63     *
64     * @param packageName
65     *          the package has to be analyzed.
66     *
67     * @return a set of all classes contained in the given package.
68     */
69    protected static Set<Class<?>> getClasses(String packageName) {
70      return AbstractMyBatisModule.getClasses(new ResolverUtil.IsA(Object.class), packageName);
71    }
72  
73    /**
74     * Return a set of all classes contained in the given package that match with the given test requirement.
75     *
76     * @param test
77     *          the class filter on the given package.
78     * @param packageName
79     *          the package has to be analyzed.
80     *
81     * @return a set of all classes contained in the given package.
82     */
83    protected static Set<Class<?>> getClasses(ResolverUtil.Test test, String packageName) {
84      checkArgument(test != null, "Parameter 'test' must not be null");
85      checkArgument(packageName != null, "Parameter 'packageName' must not be null");
86      return new ResolverUtil<Object>().find(test, packageName).getClasses();
87    }
88  
89    @Override
90    protected final void configure() {
91      try {
92        // sql session manager
93        bind(SqlSessionManager.class).toProvider(SqlSessionManagerProvider.class).in(Scopes.SINGLETON);
94        bind(SqlSession.class).to(SqlSessionManager.class).in(Scopes.SINGLETON);
95  
96        internalConfigure();
97  
98        bindTransactionInterceptors();
99  
100       bind(ClassLoader.class).annotatedWith(named("JDBC.driverClassLoader")).toInstance(driverClassLoader);
101     } finally {
102       resourcesClassLoader = getDefaultClassLoader();
103       driverClassLoader = getDefaultClassLoader();
104     }
105   }
106 
107   /**
108    * bind transactional interceptors.
109    */
110   protected void bindTransactionInterceptors() {
111     // transactional interceptor
112     TransactionalMethodInterceptor interceptor = new TransactionalMethodInterceptor();
113     requestInjection(interceptor);
114     bindInterceptor(any(), not(SYNTHETIC).and(not(DECLARED_BY_OBJECT)).and(annotatedWith(Transactional.class)),
115         interceptor);
116     // Intercept classes annotated with Transactional, but avoid "double"
117     // interception when a mathod is also annotated inside an annotated
118     // class.
119     bindInterceptor(annotatedWith(Transactional.class),
120         not(SYNTHETIC).and(not(DECLARED_BY_OBJECT)).and(not(annotatedWith(Transactional.class))), interceptor);
121   }
122 
123   /**
124    * Bind mapper.
125    *
126    * @param <T>
127    *          the generic type
128    * @param mapperType
129    *          the mapper type
130    */
131   final <T> void bindMapper(Class<T> mapperType) {
132     bind(mapperType).toProvider(guicify(new MapperProvider<T>(mapperType))).in(Scopes.SINGLETON);
133   }
134 
135   /**
136    * Use resource class loader.
137    *
138    * @param resourceClassLoader
139    *          the resource class loader
140    *
141    * @since 3.3
142    */
143   public void useResourceClassLoader(ClassLoader resourceClassLoader) {
144     this.resourcesClassLoader = resourceClassLoader;
145   }
146 
147   /**
148    * Gets the resource class loader.
149    *
150    * @return the resource class loader
151    *
152    * @since 3.3
153    */
154   protected final ClassLoader getResourceClassLoader() {
155     return resourcesClassLoader;
156   }
157 
158   /**
159    * Use jdbc driver class loader.
160    *
161    * @param driverClassLoader
162    *          the driver class loader
163    *
164    * @since 3.3
165    */
166   public void useJdbcDriverClassLoader(ClassLoader driverClassLoader) {
167     this.driverClassLoader = driverClassLoader;
168   }
169 
170   /**
171    * Gets the default class loader.
172    *
173    * @return the default class loader
174    *
175    * @since 3.3
176    */
177   private ClassLoader getDefaultClassLoader() {
178     return getClass().getClassLoader();
179   }
180 
181   /**
182    * Configures a {@link Binder} via the exposed methods.
183    */
184   abstract void internalConfigure();
185 
186   /**
187    * Initialize.
188    */
189   protected abstract void initialize();
190 
191 }