1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.spring.config;
17
18 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;
23
24 import org.mybatis.spring.mapper.ClassPathMapperScanner;
25 import org.mybatis.spring.mapper.MapperFactoryBean;
26 import org.mybatis.spring.mapper.MapperScannerConfigurer;
27 import org.springframework.beans.BeanUtils;
28 import org.springframework.beans.factory.config.BeanDefinition;
29 import org.springframework.beans.factory.support.AbstractBeanDefinition;
30 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
31 import org.springframework.beans.factory.support.BeanNameGenerator;
32 import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
33 import org.springframework.beans.factory.xml.ParserContext;
34 import org.springframework.util.ClassUtils;
35 import org.springframework.util.StringUtils;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.Node;
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class MapperScannerBeanDefinitionParser extends AbstractBeanDefinitionParser {
52
53 private static final String ATTRIBUTE_BASE_PACKAGE = "base-package";
54 private static final String ATTRIBUTE_ANNOTATION = "annotation";
55 private static final String ATTRIBUTE_MARKER_INTERFACE = "marker-interface";
56 private static final String ATTRIBUTE_NAME_GENERATOR = "name-generator";
57 private static final String ATTRIBUTE_TEMPLATE_REF = "template-ref";
58 private static final String ATTRIBUTE_FACTORY_REF = "factory-ref";
59 private static final String ATTRIBUTE_MAPPER_FACTORY_BEAN_CLASS = "mapper-factory-bean-class";
60 private static final String ATTRIBUTE_LAZY_INITIALIZATION = "lazy-initialization";
61 private static final String ATTRIBUTE_DEFAULT_SCOPE = "default-scope";
62 private static final String ATTRIBUTE_PROCESS_PROPERTY_PLACEHOLDERS = "process-property-placeholders";
63 private static final String ATTRIBUTE_EXCLUDE_FILTER = "exclude-filter";
64
65 @Override
66 protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
67 var builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
68
69 var classLoader = ClassUtils.getDefaultClassLoader();
70
71 var processPropertyPlaceHolders = element.getAttribute(ATTRIBUTE_PROCESS_PROPERTY_PLACEHOLDERS);
72 builder.addPropertyValue("processPropertyPlaceHolders",
73 !StringUtils.hasText(processPropertyPlaceHolders) || Boolean.parseBoolean(processPropertyPlaceHolders));
74 try {
75 var annotationClassName = element.getAttribute(ATTRIBUTE_ANNOTATION);
76 if (StringUtils.hasText(annotationClassName)) {
77 @SuppressWarnings("unchecked")
78 Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) classLoader
79 .loadClass(annotationClassName);
80 builder.addPropertyValue("annotationClass", annotationClass);
81 }
82 var markerInterfaceClassName = element.getAttribute(ATTRIBUTE_MARKER_INTERFACE);
83 if (StringUtils.hasText(markerInterfaceClassName)) {
84 Class<?> markerInterface = classLoader.loadClass(markerInterfaceClassName);
85 builder.addPropertyValue("markerInterface", markerInterface);
86 }
87 var nameGeneratorClassName = element.getAttribute(ATTRIBUTE_NAME_GENERATOR);
88 if (StringUtils.hasText(nameGeneratorClassName)) {
89 Class<?> nameGeneratorClass = classLoader.loadClass(nameGeneratorClassName);
90 var nameGenerator = BeanUtils.instantiateClass(nameGeneratorClass, BeanNameGenerator.class);
91 builder.addPropertyValue("nameGenerator", nameGenerator);
92 }
93 var mapperFactoryBeanClassName = element.getAttribute(ATTRIBUTE_MAPPER_FACTORY_BEAN_CLASS);
94 if (StringUtils.hasText(mapperFactoryBeanClassName)) {
95 @SuppressWarnings("unchecked")
96 Class<? extends MapperFactoryBean> mapperFactoryBeanClass = (Class<? extends MapperFactoryBean>) classLoader
97 .loadClass(mapperFactoryBeanClassName);
98 builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
99 }
100
101
102 var rawExcludeFilters = parseScanTypeFilters(element, parserContext);
103 if (!rawExcludeFilters.isEmpty()) {
104 builder.addPropertyValue("rawExcludeFilters", rawExcludeFilters);
105 }
106
107 } catch (Exception ex) {
108 var readerContext = parserContext.getReaderContext();
109 readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
110 }
111
112 builder.addPropertyValue("sqlSessionTemplateBeanName", element.getAttribute(ATTRIBUTE_TEMPLATE_REF));
113 builder.addPropertyValue("sqlSessionFactoryBeanName", element.getAttribute(ATTRIBUTE_FACTORY_REF));
114 builder.addPropertyValue("lazyInitialization", element.getAttribute(ATTRIBUTE_LAZY_INITIALIZATION));
115 builder.addPropertyValue("defaultScope", element.getAttribute(ATTRIBUTE_DEFAULT_SCOPE));
116 builder.addPropertyValue("basePackage", element.getAttribute(ATTRIBUTE_BASE_PACKAGE));
117
118
119 builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
120
121 return builder.getBeanDefinition();
122 }
123
124 private List<Map<String, String>> parseScanTypeFilters(Element element, ParserContext parserContext) {
125 List<Map<String, String>> typeFilters = new ArrayList<>();
126 var nodeList = element.getChildNodes();
127 for (var i = 0; i < nodeList.getLength(); i++) {
128 var node = nodeList.item(i);
129 if (Node.ELEMENT_NODE == node.getNodeType()) {
130 var localName = parserContext.getDelegate().getLocalName(node);
131 if (ATTRIBUTE_EXCLUDE_FILTER.equals(localName)) {
132 Map<String, String> filter = new HashMap<>(16);
133 filter.put("type", ((Element) node).getAttribute("type"));
134 filter.put("expression", ((Element) node).getAttribute("expression"));
135 typeFilters.add(filter);
136 }
137 }
138 }
139 return typeFilters;
140 }
141
142 @Override
143 protected boolean shouldGenerateIdAsFallback() {
144 return true;
145 }
146
147 }