Skip to content

Commit 0a4eb81

Browse files
nguyenvanthanChristian Nguyen Van Than
authored and
Christian Nguyen Van Than
committed
add possibility to use custom factory bean on MapperScan annotation
1 parent 5a84cb8 commit 0a4eb81

File tree

6 files changed

+131
-15
lines changed

6 files changed

+131
-15
lines changed

src/main/java/org/mybatis/spring/annotation/MapperScan.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
*
6262
* @author Michael Lanyon
6363
* @author Eduardo Macarron
64-
*
64+
*
6565
* @since 1.2.0
6666
* @see MapperScannerRegistrar
6767
* @see MapperFactoryBean
@@ -101,7 +101,7 @@
101101
* within the Spring container.
102102
*/
103103
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
104-
104+
105105
/**
106106
* This property specifies the annotation that the scanner will search for.
107107
* <p>
@@ -136,4 +136,10 @@
136136
*/
137137
String sqlSessionFactoryRef() default "";
138138

139+
/**
140+
* Specifies a custom MapperFactoryBean to return a mybatis proxy as spring bean.
141+
*
142+
*/
143+
Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
144+
139145
}

src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
7979
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
8080
}
8181

82+
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
83+
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
84+
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
85+
}
86+
8287
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
8388
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
8489

src/main/java/org/mybatis/spring/mapper/ClassPathMapperScanner.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/**
2-
* Copyright 2010-2015 the original author or authors.
1+
/*
2+
* Copyright 2010-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -70,6 +70,8 @@ public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
7070

7171
private Class<?> markerInterface;
7272

73+
private MapperFactoryBean mapperFactoryBean = new MapperFactoryBean();
74+
7375
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
7476
super(registry, false);
7577
}
@@ -102,6 +104,11 @@ public void setSqlSessionFactoryBeanName(String sqlSessionFactoryBeanName) {
102104
this.sqlSessionFactoryBeanName = sqlSessionFactoryBeanName;
103105
}
104106

107+
public void setMapperFactoryBean(MapperFactoryBean mapperFactoryBean) {
108+
this.mapperFactoryBean = (mapperFactoryBean != null ? mapperFactoryBean : new MapperFactoryBean());
109+
}
110+
111+
105112
/**
106113
* Configures parent scanner to search for the right interfaces. It can search
107114
* for all interfaces or just for those that extends a markerInterface or/and
@@ -177,8 +184,8 @@ private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
177184

178185
// the mapper interface is the original class of the bean
179186
// but, the actual class of the bean is MapperFactoryBean
180-
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
181-
definition.setBeanClass(MapperFactoryBean.class);
187+
definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
188+
definition.setBeanClass(this.mapperFactoryBean.getClass());
182189

183190
definition.getPropertyValues().add("addToConfig", this.addToConfig);
184191

src/main/java/org/mybatis/spring/mapper/MapperFactoryBean.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/**
2-
* Copyright 2010-2015 the original author or authors.
1+
/*
2+
* Copyright 2010-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -66,7 +66,7 @@ public MapperFactoryBean(Class<T> mapperInterface) {
6666
public MapperFactoryBean() {
6767
}
6868

69-
/**
69+
/**
7070
* Sets the mapper interface of the MyBatis mapper
7171
*
7272
* @param mapperInterface class of the interface
@@ -115,25 +115,40 @@ protected void checkDaoConfig() {
115115
/**
116116
* {@inheritDoc}
117117
*/
118-
@Override
119118
public T getObject() throws Exception {
120119
return getSqlSession().getMapper(this.mapperInterface);
121120
}
122121

123122
/**
124123
* {@inheritDoc}
125124
*/
126-
@Override
127125
public Class<T> getObjectType() {
128126
return this.mapperInterface;
129127
}
130128

131129
/**
132130
* {@inheritDoc}
133131
*/
134-
@Override
135132
public boolean isSingleton() {
136133
return true;
137134
}
138135

136+
//------------- mutators --------------
137+
138+
/**
139+
* Return the mapper interface of the MyBatis mapper
140+
* @return class of the interface
141+
*/
142+
public Class<T> getMapperInterface() {
143+
return mapperInterface;
144+
}
145+
146+
/**
147+
* Return the flag for addition into MyBatis config.
148+
* @return true if the mapper will be added to MyBatis in the case it is not already
149+
* registered.
150+
*/
151+
public boolean isAddToConfig() {
152+
return addToConfig;
153+
}
139154
}

src/test/java/org/mybatis/spring/annotation/MapperScanTest.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
*/
1616
package org.mybatis.spring.annotation;
1717

18-
import static org.junit.Assert.assertSame;
19-
import static org.junit.Assert.fail;
20-
2118
import org.junit.After;
2219
import org.junit.Before;
2320
import org.junit.Test;
@@ -27,6 +24,7 @@
2724
import org.mybatis.spring.mapper.MapperInterface;
2825
import org.mybatis.spring.mapper.MapperSubinterface;
2926
import org.mybatis.spring.mapper.child.MapperChildInterface;
27+
import org.mybatis.spring.type.DummyMapperFactoryBean;
3028
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3129
import org.springframework.beans.factory.config.BeanDefinition;
3230
import org.springframework.beans.factory.config.ConstructorArgumentValues;
@@ -39,6 +37,8 @@
3937

4038
import com.mockrunner.mock.jdbc.MockDataSource;
4139

40+
import static org.junit.Assert.*;
41+
4242
/**
4343
* Test for the MapperScannerRegistrar.
4444
* <p>
@@ -162,6 +162,22 @@ public void testMarkerInterfaceAndAnnotationScan() {
162162
assertBeanNotLoaded("mapperInterface");
163163
}
164164

165+
@Test
166+
public void testCustomMapperFactoryBean() {
167+
applicationContext.register(AppConfigWithCustomMapperFactoryBean.class);
168+
169+
startContext();
170+
171+
// all interfaces with methods should be loaded
172+
applicationContext.getBean("mapperInterface");
173+
applicationContext.getBean("mapperSubinterface");
174+
applicationContext.getBean("mapperChildInterface");
175+
applicationContext.getBean("annotatedMapper");
176+
177+
assertTrue(DummyMapperFactoryBean.getMapperCount() > 0);
178+
179+
}
180+
165181
@Test
166182
public void testScanWithNameConflict() {
167183
GenericBeanDefinition definition = new GenericBeanDefinition();
@@ -265,6 +281,11 @@ public static class AppConfigWithSqlSessionFactory {
265281
public static class AppConfigWithNameGenerator {
266282
}
267283

284+
@Configuration
285+
@MapperScan(basePackages = "org.mybatis.spring.mapper", factoryBean = DummyMapperFactoryBean.class)
286+
public static class AppConfigWithCustomMapperFactoryBean {
287+
}
288+
268289
public static class BeanNameGenerator implements org.springframework.beans.factory.support.BeanNameGenerator {
269290

270291
public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry definitionRegistry) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.mybatis.spring.type;
2+
3+
import org.apache.ibatis.session.SqlSessionFactory;
4+
import org.apache.log4j.Logger;
5+
import org.mybatis.spring.mapper.MapperFactoryBean;
6+
7+
import java.lang.reflect.InvocationHandler;
8+
import java.lang.reflect.Method;
9+
import java.lang.reflect.Proxy;
10+
import java.util.concurrent.atomic.AtomicInteger;
11+
12+
public class DummyMapperFactoryBean<T> extends MapperFactoryBean<T> {
13+
14+
private static final Logger LOGGER = Logger.getLogger(DummyMapperFactoryBean.class);
15+
16+
private static final AtomicInteger mapperInstanceCount = new AtomicInteger(0);
17+
18+
@Override
19+
protected void checkDaoConfig() {
20+
super.checkDaoConfig();
21+
// make something more
22+
if (isAddToConfig()) {
23+
LOGGER.debug("register mapper for interface : " + getMapperInterface());
24+
25+
}
26+
}
27+
28+
@Override
29+
public T getObject() throws Exception {
30+
MapperFactoryBean<T> mapperFactoryBean = new MapperFactoryBean<T>();
31+
mapperFactoryBean.setMapperInterface(getMapperInterface());
32+
mapperFactoryBean.setAddToConfig(isAddToConfig());
33+
mapperFactoryBean.setSqlSessionFactory(getCustomSessionFactoryForClass(getMapperInterface()));
34+
T object = mapperFactoryBean.getObject();
35+
mapperInstanceCount.incrementAndGet();
36+
return object;
37+
}
38+
39+
40+
41+
private SqlSessionFactory getCustomSessionFactoryForClass(Class mapperClass) {
42+
// can for example read a custom annotation to set a custom sqlSessionFactory
43+
44+
// just a dummy implementation example
45+
return (SqlSessionFactory) Proxy.newProxyInstance(
46+
SqlSessionFactory.class.getClassLoader(),
47+
new Class[]{SqlSessionFactory.class},
48+
new InvocationHandler() {
49+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
50+
if ("getConfiguration".equals(method.getName())) {
51+
return getSqlSession().getConfiguration();
52+
}
53+
// dummy
54+
return null;
55+
}
56+
});
57+
}
58+
59+
public static final int getMapperCount(){
60+
return mapperInstanceCount.get();
61+
}
62+
}

0 commit comments

Comments
 (0)