DEV Community

Salad Lam
Salad Lam

Posted on

Spring Framework bean definition XML: custom tag

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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());
    }
...
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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);
            }
        }
    }
...
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)