Skip to content

Commit

Permalink
Merge pull request #836 from apdya/scanfilter
Browse files Browse the repository at this point in the history
Support excluding filter on mapper scan feature
  • Loading branch information
hazendaz committed May 10, 2024
2 parents b1ab8e1 + b7f3f35 commit 55a5ac8
Show file tree
Hide file tree
Showing 34 changed files with 1,642 additions and 4 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,12 @@
<version>6.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>net.bytebuddy</groupId>
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/mybatis/spring/annotation/MapperScan.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;

Expand Down Expand Up @@ -196,4 +197,13 @@
*/
boolean processPropertyPlaceHolders() default true;

/**
* Specifies which types are not eligible for mapper scanning.
*
* @since 3.0.3
*
* @return array of customized mapper excludeFilter
*/
ComponentScan.Filter[] excludeFilters() default {};

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.mybatis.spring.mapper.ClassPathMapperScanner;
Expand All @@ -31,10 +33,15 @@
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

Expand All @@ -54,15 +61,14 @@
*/
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

private ResourceLoader resourceLoader;

/**
* {@inheritDoc}
*
* @deprecated Since 2.0.2, this method not used never.
*/
@Override
@Deprecated
public void setResourceLoader(ResourceLoader resourceLoader) {
// NOP
this.resourceLoader = resourceLoader;
}

/**
Expand Down Expand Up @@ -126,6 +132,22 @@ void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes a
basePackages.add(getDefaultBasePackage(annoMeta));
}

AnnotationAttributes[] excludeFilterArray = annoAttrs.getAnnotationArray("excludeFilters");
if (excludeFilterArray.length > 0) {
List<TypeFilter> typeFilters = new ArrayList<>();
List<Map<String, String>> rawTypeFilters = new ArrayList<>();
for (AnnotationAttributes excludeFilters : excludeFilterArray) {
if (excludeFilters.getStringArray("pattern").length > 0) {
// in oder to apply placeholder resolver
rawTypeFilters.addAll(parseFiltersHasPatterns(excludeFilters));
} else {
typeFilters.addAll(typeFiltersFor(excludeFilters));
}
}
builder.addPropertyValue("excludeFilters", typeFilters);
builder.addPropertyValue("rawExcludeFilters", rawTypeFilters);
}

String lazyInitialization = annoAttrs.getString("lazyInitialization");
if (StringUtils.hasText(lazyInitialization)) {
builder.addPropertyValue("lazyInitialization", lazyInitialization);
Expand All @@ -145,6 +167,74 @@ void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes a

}

/**
* Parse excludeFilters which FilterType is REGEX or ASPECTJ
*
* @param filterAttributes
* AnnotationAttributes of excludeFilters
*
* @since 3.0.3
*/
private List<Map<String, String>> parseFiltersHasPatterns(AnnotationAttributes filterAttributes) {

List<Map<String, String>> rawTypeFilters = new ArrayList<>();
FilterType filterType = filterAttributes.getEnum("type");
String[] expressionArray = filterAttributes.getStringArray("pattern");
for (String expression : expressionArray) {
switch (filterType) {
case REGEX:
case ASPECTJ:
Map<String, String> typeFilter = new HashMap<>(16);
typeFilter.put("type", filterType.name().toLowerCase());
typeFilter.put("expression", expression);
rawTypeFilters.add(typeFilter);
break;
default:
throw new IllegalArgumentException("Cannot specify the 'pattern' attribute if use the " + filterType
+ " FilterType in exclude filter of @MapperScan");
}
}
return rawTypeFilters;
}

/**
* Parse excludeFilters which FilterType is ANNOTATION ASSIGNABLE or CUSTOM
*
* @param filterAttributes
* AnnotationAttributes of excludeFilters
*
* @since 3.0.3
*/
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {

List<TypeFilter> typeFilters = new ArrayList<>();
FilterType filterType = filterAttributes.getEnum("type");

for (Class<?> filterClass : filterAttributes.getClassArray("value")) {
switch (filterType) {
case ANNOTATION:
Assert.isAssignable(Annotation.class, filterClass,
"Specified an unsupported type in 'ANNOTATION' exclude filter of @MapperScan");
@SuppressWarnings("unchecked")
Class<Annotation> annoClass = (Class<Annotation>) filterClass;
typeFilters.add(new AnnotationTypeFilter(annoClass));
break;
case ASSIGNABLE_TYPE:
typeFilters.add(new AssignableTypeFilter(filterClass));
break;
case CUSTOM:
Assert.isAssignable(TypeFilter.class, filterClass,
"An error occured when processing a @ComponentScan " + "CUSTOM type filter: ");
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
break;
default:
throw new IllegalArgumentException("Cannot specify the 'value' or 'classes' attribute if use the "
+ filterType + " FilterType in exclude filter of @MapperScan");
}
}
return typeFilters;
}

private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
package org.mybatis.spring.config;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.mybatis.spring.mapper.MapperFactoryBean;
Expand All @@ -31,6 +35,8 @@
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

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

/**
* {@inheritDoc}
Expand Down Expand Up @@ -98,6 +105,13 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
.loadClass(mapperFactoryBeanClassName);
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}

// parse raw exclude-filter in <mybatis:scan>
List<Map<String, String>> rawExcludeFilters = parseScanTypeFilters(element, parserContext);
if (!rawExcludeFilters.isEmpty()) {
builder.addPropertyValue("rawExcludeFilters", rawExcludeFilters);
}

} catch (Exception ex) {
XmlReaderContext readerContext = parserContext.getReaderContext();
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
Expand All @@ -115,6 +129,24 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
return builder.getBeanDefinition();
}

private List<Map<String, String>> parseScanTypeFilters(Element element, ParserContext parserContext) {
List<Map<String, String>> typeFilters = new ArrayList<>();
NodeList nodeList = element.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (Node.ELEMENT_NODE == node.getNodeType()) {
String localName = parserContext.getDelegate().getLocalName(node);
if (ATTRIBUTE_EXCLUDE_FILTER.equals(localName)) {
Map<String, String> filter = new HashMap<>(16);
filter.put("type", ((Element) node).getAttribute("type"));
filter.put("expression", ((Element) node).getAttribute("expression"));
typeFilters.add(filter);
}
}
}
return typeFilters;
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;

Expand All @@ -41,6 +42,7 @@
import org.springframework.core.env.Environment;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.StringUtils;

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

private String defaultScope;
private List<TypeFilter> excludeFilters;

public ClassPathMapperScanner(BeanDefinitionRegistry registry, Environment environment) {
super(registry, false, environment);
Expand Down Expand Up @@ -145,6 +148,10 @@ public void setMarkerInterface(Class<?> markerInterface) {
this.markerInterface = markerInterface;
}

public void setExcludeFilters(List<TypeFilter> excludeFilters) {
this.excludeFilters = excludeFilters;
}

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
Expand Down Expand Up @@ -230,6 +237,13 @@ protected boolean matchClassName(String className) {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});

// exclude types declared by MapperScan.excludeFilters
if (excludeFilters != null && excludeFilters.size() > 0) {
for (TypeFilter excludeFilter : excludeFilters) {
addExcludeFilter(excludeFilter);
}
}
}

/**
Expand Down
Loading

0 comments on commit 55a5ac8

Please sign in to comment.