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 }