Notice
I wrote this article and was originally published on Qiita on 27 August 2019.
At first
In document of Spring Framework, there is an example of define bean by using XML element "<util:list>".
https://docs.spring.io/spring/docs/5.0.x/spring-framework-reference/core.html#xsd-schemas-util-list
<!-- creates a java.util.List instance with the supplied values -->
<util:list id="emails">
<value>pechorin@hero.org</value>
<value>raskolnikov@slums.org</value>
<value>stavrogin@gov.org</value>
<value>porfiry@gov.org</value>
</util:list>
The code above has same function of below code.
<!-- creates a java.util.List instance with values loaded from the supplied 'sourceList' -->
<bean id="emails" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>pechorin@hero.org</value>
<value>raskolnikov@slums.org</value>
<value>stavrogin@gov.org</value>
<value>porfiry@gov.org</value>
</list>
</property>
</bean>
I am interest in this magic, so I start to look into source code.
The turth of magic
First, I tried to find out classes which implement interface org.springframework.beans.factory.xmlBean.DefinitionParser in Eclipse. A lot of classes came out. And one of class org.springframework.beans.factory.xml.UtilNamespaceHandler (In Java archive spring-beans-3.2.3.RELEASE.jar) I felt suspect. So I read the code of this
...
public void init() {
registerBeanDefinitionParser("constant", new ConstantBeanDefinitionParser());
registerBeanDefinitionParser("property-path", new PropertyPathBeanDefinitionParser());
registerBeanDefinitionParser("list", new ListBeanDefinitionParser());
registerBeanDefinitionParser("set", new SetBeanDefinitionParser());
registerBeanDefinitionParser("map", new MapBeanDefinitionParser());
registerBeanDefinitionParser("properties", new PropertiesBeanDefinitionParser());
}
...
May be I found out the class which handle XML element "list". In the same Java archive, I tried to look into "/META-INF/spring.handlers"
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
Bingo! Elements in "util" namespace is really handle by class org.springframework.beans.factory.xml.UtilNamespaceHandler. Return to method init(). XML element "list" is handle by class ListBeanDefinitionParser(inner class of org.springframework.beans.factory.xml.UtilNamespaceHandler).
...
private static class ListBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class getBeanClass(Element element) {
return ListFactoryBean.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String listClass = element.getAttribute("list-class");
List parsedList = parserContext.getDelegate().parseListElement(element, builder.getRawBeanDefinition());
builder.addPropertyValue("sourceList", parsedList);
if (StringUtils.hasText(listClass)) {
builder.addPropertyValue("targetListClass", listClass);
}
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
if (StringUtils.hasLength(scope)) {
builder.setScope(scope);
}
}
}
...
Method getBeanClass() is for getting List bean factory class org.springframework.beans.factory.config.ListFactoryBean. And method doParse() is for reading XML element properties and child element.
Reference
https://docs.spring.io/spring/docs/5.0.x/spring-framework-reference/core.html#xml-custom