Skip to content

Commit 55a5ac8

Browse files
authored
Merge pull request #836 from apdya/scanfilter
Support excluding filter on mapper scan feature
2 parents b1ab8e1 + b7f3f35 commit 55a5ac8

34 files changed

+1642
-4
lines changed

pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,12 @@
323323
<version>6.0.0</version>
324324
<scope>test</scope>
325325
</dependency>
326+
<dependency>
327+
<groupId>org.aspectj</groupId>
328+
<artifactId>aspectjweaver</artifactId>
329+
<version>1.9.19</version>
330+
<optional>true</optional>
331+
</dependency>
326332

327333
<dependency>
328334
<groupId>net.bytebuddy</groupId>

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

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.mybatis.spring.mapper.MapperScannerConfigurer;
2828
import org.springframework.beans.factory.support.AbstractBeanDefinition;
2929
import org.springframework.beans.factory.support.BeanNameGenerator;
30+
import org.springframework.context.annotation.ComponentScan;
3031
import org.springframework.context.annotation.Import;
3132
import org.springframework.core.annotation.AliasFor;
3233

@@ -196,4 +197,13 @@
196197
*/
197198
boolean processPropertyPlaceHolders() default true;
198199

200+
/**
201+
* Specifies which types are not eligible for mapper scanning.
202+
*
203+
* @since 3.0.3
204+
*
205+
* @return array of customized mapper excludeFilter
206+
*/
207+
ComponentScan.Filter[] excludeFilters() default {};
208+
199209
}

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

+94-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import java.lang.annotation.Annotation;
1919
import java.util.ArrayList;
2020
import java.util.Arrays;
21+
import java.util.HashMap;
2122
import java.util.List;
23+
import java.util.Map;
2224
import java.util.stream.Collectors;
2325

2426
import org.mybatis.spring.mapper.ClassPathMapperScanner;
@@ -31,10 +33,15 @@
3133
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3234
import org.springframework.beans.factory.support.BeanNameGenerator;
3335
import org.springframework.context.ResourceLoaderAware;
36+
import org.springframework.context.annotation.FilterType;
3437
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
3538
import org.springframework.core.annotation.AnnotationAttributes;
3639
import org.springframework.core.io.ResourceLoader;
3740
import org.springframework.core.type.AnnotationMetadata;
41+
import org.springframework.core.type.filter.AnnotationTypeFilter;
42+
import org.springframework.core.type.filter.AssignableTypeFilter;
43+
import org.springframework.core.type.filter.TypeFilter;
44+
import org.springframework.util.Assert;
3845
import org.springframework.util.ClassUtils;
3946
import org.springframework.util.StringUtils;
4047

@@ -54,15 +61,14 @@
5461
*/
5562
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
5663

64+
private ResourceLoader resourceLoader;
65+
5766
/**
5867
* {@inheritDoc}
59-
*
60-
* @deprecated Since 2.0.2, this method not used never.
6168
*/
6269
@Override
63-
@Deprecated
6470
public void setResourceLoader(ResourceLoader resourceLoader) {
65-
// NOP
71+
this.resourceLoader = resourceLoader;
6672
}
6773

6874
/**
@@ -126,6 +132,22 @@ void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes a
126132
basePackages.add(getDefaultBasePackage(annoMeta));
127133
}
128134

135+
AnnotationAttributes[] excludeFilterArray = annoAttrs.getAnnotationArray("excludeFilters");
136+
if (excludeFilterArray.length > 0) {
137+
List<TypeFilter> typeFilters = new ArrayList<>();
138+
List<Map<String, String>> rawTypeFilters = new ArrayList<>();
139+
for (AnnotationAttributes excludeFilters : excludeFilterArray) {
140+
if (excludeFilters.getStringArray("pattern").length > 0) {
141+
// in oder to apply placeholder resolver
142+
rawTypeFilters.addAll(parseFiltersHasPatterns(excludeFilters));
143+
} else {
144+
typeFilters.addAll(typeFiltersFor(excludeFilters));
145+
}
146+
}
147+
builder.addPropertyValue("excludeFilters", typeFilters);
148+
builder.addPropertyValue("rawExcludeFilters", rawTypeFilters);
149+
}
150+
129151
String lazyInitialization = annoAttrs.getString("lazyInitialization");
130152
if (StringUtils.hasText(lazyInitialization)) {
131153
builder.addPropertyValue("lazyInitialization", lazyInitialization);
@@ -145,6 +167,74 @@ void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes a
145167

146168
}
147169

170+
/**
171+
* Parse excludeFilters which FilterType is REGEX or ASPECTJ
172+
*
173+
* @param filterAttributes
174+
* AnnotationAttributes of excludeFilters
175+
*
176+
* @since 3.0.3
177+
*/
178+
private List<Map<String, String>> parseFiltersHasPatterns(AnnotationAttributes filterAttributes) {
179+
180+
List<Map<String, String>> rawTypeFilters = new ArrayList<>();
181+
FilterType filterType = filterAttributes.getEnum("type");
182+
String[] expressionArray = filterAttributes.getStringArray("pattern");
183+
for (String expression : expressionArray) {
184+
switch (filterType) {
185+
case REGEX:
186+
case ASPECTJ:
187+
Map<String, String> typeFilter = new HashMap<>(16);
188+
typeFilter.put("type", filterType.name().toLowerCase());
189+
typeFilter.put("expression", expression);
190+
rawTypeFilters.add(typeFilter);
191+
break;
192+
default:
193+
throw new IllegalArgumentException("Cannot specify the 'pattern' attribute if use the " + filterType
194+
+ " FilterType in exclude filter of @MapperScan");
195+
}
196+
}
197+
return rawTypeFilters;
198+
}
199+
200+
/**
201+
* Parse excludeFilters which FilterType is ANNOTATION ASSIGNABLE or CUSTOM
202+
*
203+
* @param filterAttributes
204+
* AnnotationAttributes of excludeFilters
205+
*
206+
* @since 3.0.3
207+
*/
208+
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
209+
210+
List<TypeFilter> typeFilters = new ArrayList<>();
211+
FilterType filterType = filterAttributes.getEnum("type");
212+
213+
for (Class<?> filterClass : filterAttributes.getClassArray("value")) {
214+
switch (filterType) {
215+
case ANNOTATION:
216+
Assert.isAssignable(Annotation.class, filterClass,
217+
"Specified an unsupported type in 'ANNOTATION' exclude filter of @MapperScan");
218+
@SuppressWarnings("unchecked")
219+
Class<Annotation> annoClass = (Class<Annotation>) filterClass;
220+
typeFilters.add(new AnnotationTypeFilter(annoClass));
221+
break;
222+
case ASSIGNABLE_TYPE:
223+
typeFilters.add(new AssignableTypeFilter(filterClass));
224+
break;
225+
case CUSTOM:
226+
Assert.isAssignable(TypeFilter.class, filterClass,
227+
"An error occured when processing a @ComponentScan " + "CUSTOM type filter: ");
228+
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
229+
break;
230+
default:
231+
throw new IllegalArgumentException("Cannot specify the 'value' or 'classes' attribute if use the "
232+
+ filterType + " FilterType in exclude filter of @MapperScan");
233+
}
234+
}
235+
return typeFilters;
236+
}
237+
148238
private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
149239
return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
150240
}

src/main/java/org/mybatis/spring/config/MapperScannerBeanDefinitionParser.java

+32
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
package org.mybatis.spring.config;
1717

1818
import java.lang.annotation.Annotation;
19+
import java.util.ArrayList;
20+
import java.util.HashMap;
21+
import java.util.List;
22+
import java.util.Map;
1923

2024
import org.mybatis.spring.mapper.ClassPathMapperScanner;
2125
import org.mybatis.spring.mapper.MapperFactoryBean;
@@ -31,6 +35,8 @@
3135
import org.springframework.util.ClassUtils;
3236
import org.springframework.util.StringUtils;
3337
import org.w3c.dom.Element;
38+
import org.w3c.dom.Node;
39+
import org.w3c.dom.NodeList;
3440

3541
/**
3642
* A {#code BeanDefinitionParser} that handles the element scan of the MyBatis. namespace
@@ -57,6 +63,7 @@ public class MapperScannerBeanDefinitionParser extends AbstractBeanDefinitionPar
5763
private static final String ATTRIBUTE_LAZY_INITIALIZATION = "lazy-initialization";
5864
private static final String ATTRIBUTE_DEFAULT_SCOPE = "default-scope";
5965
private static final String ATTRIBUTE_PROCESS_PROPERTY_PLACEHOLDERS = "process-property-placeholders";
66+
private static final String ATTRIBUTE_EXCLUDE_FILTER = "exclude-filter";
6067

6168
/**
6269
* {@inheritDoc}
@@ -98,6 +105,13 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
98105
.loadClass(mapperFactoryBeanClassName);
99106
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
100107
}
108+
109+
// parse raw exclude-filter in <mybatis:scan>
110+
List<Map<String, String>> rawExcludeFilters = parseScanTypeFilters(element, parserContext);
111+
if (!rawExcludeFilters.isEmpty()) {
112+
builder.addPropertyValue("rawExcludeFilters", rawExcludeFilters);
113+
}
114+
101115
} catch (Exception ex) {
102116
XmlReaderContext readerContext = parserContext.getReaderContext();
103117
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
@@ -115,6 +129,24 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
115129
return builder.getBeanDefinition();
116130
}
117131

132+
private List<Map<String, String>> parseScanTypeFilters(Element element, ParserContext parserContext) {
133+
List<Map<String, String>> typeFilters = new ArrayList<>();
134+
NodeList nodeList = element.getChildNodes();
135+
for (int i = 0; i < nodeList.getLength(); i++) {
136+
Node node = nodeList.item(i);
137+
if (Node.ELEMENT_NODE == node.getNodeType()) {
138+
String localName = parserContext.getDelegate().getLocalName(node);
139+
if (ATTRIBUTE_EXCLUDE_FILTER.equals(localName)) {
140+
Map<String, String> filter = new HashMap<>(16);
141+
filter.put("type", ((Element) node).getAttribute("type"));
142+
filter.put("expression", ((Element) node).getAttribute("expression"));
143+
typeFilters.add(filter);
144+
}
145+
}
146+
}
147+
return typeFilters;
148+
}
149+
118150
/**
119151
* {@inheritDoc}
120152
*

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

+14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.lang.annotation.Annotation;
1919
import java.util.Arrays;
20+
import java.util.List;
2021
import java.util.Optional;
2122
import java.util.Set;
2223

@@ -41,6 +42,7 @@
4142
import org.springframework.core.env.Environment;
4243
import org.springframework.core.type.filter.AnnotationTypeFilter;
4344
import org.springframework.core.type.filter.AssignableTypeFilter;
45+
import org.springframework.core.type.filter.TypeFilter;
4446
import org.springframework.util.StringUtils;
4547

4648
/**
@@ -86,6 +88,7 @@ public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
8688
private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
8789

8890
private String defaultScope;
91+
private List<TypeFilter> excludeFilters;
8992

9093
public ClassPathMapperScanner(BeanDefinitionRegistry registry, Environment environment) {
9194
super(registry, false, environment);
@@ -145,6 +148,10 @@ public void setMarkerInterface(Class<?> markerInterface) {
145148
this.markerInterface = markerInterface;
146149
}
147150

151+
public void setExcludeFilters(List<TypeFilter> excludeFilters) {
152+
this.excludeFilters = excludeFilters;
153+
}
154+
148155
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
149156
this.sqlSessionFactory = sqlSessionFactory;
150157
}
@@ -230,6 +237,13 @@ protected boolean matchClassName(String className) {
230237
String className = metadataReader.getClassMetadata().getClassName();
231238
return className.endsWith("package-info");
232239
});
240+
241+
// exclude types declared by MapperScan.excludeFilters
242+
if (excludeFilters != null && excludeFilters.size() > 0) {
243+
for (TypeFilter excludeFilter : excludeFilters) {
244+
addExcludeFilter(excludeFilter);
245+
}
246+
}
233247
}
234248

235249
/**

0 commit comments

Comments
 (0)