View Javadoc
1   /*
2    * Copyright 2010-2025 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.mapper;
17  
18  import static org.springframework.util.Assert.notNull;
19  
20  import org.apache.ibatis.executor.ErrorContext;
21  import org.mybatis.spring.SqlSessionTemplate;
22  import org.mybatis.spring.support.SqlSessionDaoSupport;
23  import org.springframework.beans.factory.FactoryBean;
24  
25  /**
26   * BeanFactory that enables injection of MyBatis mapper interfaces. It can be set up with a SqlSessionFactory or a
27   * pre-configured SqlSessionTemplate.
28   * <p>
29   * Sample configuration:
30   *
31   * <pre class="code">
32   * {@code
33   *   <bean id="baseMapper" class="org.mybatis.spring.mapper.MapperFactoryBean" abstract="true" lazy-init="true">
34   *     <property name="sqlSessionFactory" ref="sqlSessionFactory" />
35   *   </bean>
36   *
37   *   <bean id="oneMapper" parent="baseMapper">
38   *     <property name="mapperInterface" value="my.package.MyMapperInterface" />
39   *   </bean>
40   *
41   *   <bean id="anotherMapper" parent="baseMapper">
42   *     <property name="mapperInterface" value="my.package.MyAnotherMapperInterface" />
43   *   </bean>
44   * }
45   * </pre>
46   * <p>
47   * Note that this factory can only inject <em>interfaces</em>, not concrete classes.
48   *
49   * @author Eduardo Macarron
50   *
51   * @param <T>
52   *          the generic type
53   *
54   * @see SqlSessionTemplate
55   */
56  public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
57  
58    private Class<T> mapperInterface;
59  
60    private boolean addToConfig = true;
61  
62    /**
63     * Instantiates a new mapper factory bean.
64     */
65    public MapperFactoryBean() {
66      // intentionally empty
67    }
68  
69    /**
70     * Instantiates a new mapper factory bean.
71     *
72     * @param mapperInterface
73     *          the mapper interface
74     */
75    public MapperFactoryBean(Class<T> mapperInterface) {
76      this.mapperInterface = mapperInterface;
77    }
78  
79    @Override
80    protected void checkDaoConfig() {
81      super.checkDaoConfig();
82  
83      notNull(this.mapperInterface, "Property 'mapperInterface' is required");
84  
85      var configuration = getSqlSession().getConfiguration();
86      if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
87        try {
88          configuration.addMapper(this.mapperInterface);
89        } catch (Exception e) {
90          logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
91          throw new IllegalArgumentException(e);
92        } finally {
93          ErrorContext.instance().reset();
94        }
95      }
96    }
97  
98    @Override
99    public T getObject() throws Exception {
100     return getSqlSession().getMapper(this.mapperInterface);
101   }
102 
103   @Override
104   public Class<T> getObjectType() {
105     return this.mapperInterface;
106   }
107 
108   @Override
109   public boolean isSingleton() {
110     return true;
111   }
112 
113   // ------------- mutators --------------
114 
115   /**
116    * Sets the mapper interface of the MyBatis mapper
117    *
118    * @param mapperInterface
119    *          class of the interface
120    */
121   public void setMapperInterface(Class<T> mapperInterface) {
122     this.mapperInterface = mapperInterface;
123   }
124 
125   /**
126    * Return the mapper interface of the MyBatis mapper
127    *
128    * @return class of the interface
129    */
130   public Class<T> getMapperInterface() {
131     return mapperInterface;
132   }
133 
134   /**
135    * If addToConfig is false the mapper will not be added to MyBatis. This means it must have been included in
136    * mybatis-config.xml.
137    * <p>
138    * If it is true, the mapper will be added to MyBatis in the case it is not already registered.
139    * <p>
140    * By default addToConfig is true.
141    *
142    * @param addToConfig
143    *          a flag that whether add mapper to MyBatis or not
144    */
145   public void setAddToConfig(boolean addToConfig) {
146     this.addToConfig = addToConfig;
147   }
148 
149   /**
150    * Return the flag for addition into MyBatis config.
151    *
152    * @return true if the mapper will be added to MyBatis in the case it is not already registered.
153    */
154   public boolean isAddToConfig() {
155     return addToConfig;
156   }
157 }