001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.xml;
018
019import org.w3c.dom.Element;
020
021import org.springframework.beans.factory.support.AbstractBeanDefinition;
022import org.springframework.beans.factory.support.BeanDefinitionBuilder;
023
024/**
025 * Base class for those {@link BeanDefinitionParser} implementations that
026 * need to parse and define just a <i>single</i> {@code BeanDefinition}.
027 *
028 * <p>Extend this parser class when you want to create a single bean definition
029 * from an arbitrarily complex XML element. You may wish to consider extending
030 * the {@link AbstractSimpleBeanDefinitionParser} when you want to create a
031 * single bean definition from a relatively simple custom XML element.
032 *
033 * <p>The resulting {@code BeanDefinition} will be automatically registered
034 * with the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}.
035 * Your job simply is to {@link #doParse parse} the custom XML {@link Element}
036 * into a single {@code BeanDefinition}.
037 *
038 * @author Rob Harrop
039 * @author Juergen Hoeller
040 * @author Rick Evans
041 * @since 2.0
042 * @see #getBeanClass
043 * @see #getBeanClassName
044 * @see #doParse
045 */
046public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
047
048        /**
049         * Creates a {@link BeanDefinitionBuilder} instance for the
050         * {@link #getBeanClass bean Class} and passes it to the
051         * {@link #doParse} strategy method.
052         * @param element the element that is to be parsed into a single BeanDefinition
053         * @param parserContext the object encapsulating the current state of the parsing process
054         * @return the BeanDefinition resulting from the parsing of the supplied {@link Element}
055         * @throws IllegalStateException if the bean {@link Class} returned from
056         * {@link #getBeanClass(org.w3c.dom.Element)} is {@code null}
057         * @see #doParse
058         */
059        @Override
060        protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
061                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
062                String parentName = getParentName(element);
063                if (parentName != null) {
064                        builder.getRawBeanDefinition().setParentName(parentName);
065                }
066                Class<?> beanClass = getBeanClass(element);
067                if (beanClass != null) {
068                        builder.getRawBeanDefinition().setBeanClass(beanClass);
069                }
070                else {
071                        String beanClassName = getBeanClassName(element);
072                        if (beanClassName != null) {
073                                builder.getRawBeanDefinition().setBeanClassName(beanClassName);
074                        }
075                }
076                builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
077                if (parserContext.isNested()) {
078                        // Inner bean definition must receive same scope as containing bean.
079                        builder.setScope(parserContext.getContainingBeanDefinition().getScope());
080                }
081                if (parserContext.isDefaultLazyInit()) {
082                        // Default-lazy-init applies to custom bean definitions as well.
083                        builder.setLazyInit(true);
084                }
085                doParse(element, parserContext, builder);
086                return builder.getBeanDefinition();
087        }
088
089        /**
090         * Determine the name for the parent of the currently parsed bean,
091         * in case of the current bean being defined as a child bean.
092         * <p>The default implementation returns {@code null},
093         * indicating a root bean definition.
094         * @param element the {@code Element} that is being parsed
095         * @return the name of the parent bean for the currently parsed bean,
096         * or {@code null} if none
097         */
098        protected String getParentName(Element element) {
099                return null;
100        }
101
102        /**
103         * Determine the bean class corresponding to the supplied {@link Element}.
104         * <p>Note that, for application classes, it is generally preferable to
105         * override {@link #getBeanClassName} instead, in order to avoid a direct
106         * dependence on the bean implementation class. The BeanDefinitionParser
107         * and its NamespaceHandler can be used within an IDE plugin then, even
108         * if the application classes are not available on the plugin's classpath.
109         * @param element the {@code Element} that is being parsed
110         * @return the {@link Class} of the bean that is being defined via parsing
111         * the supplied {@code Element}, or {@code null} if none
112         * @see #getBeanClassName
113         */
114        protected Class<?> getBeanClass(Element element) {
115                return null;
116        }
117
118        /**
119         * Determine the bean class name corresponding to the supplied {@link Element}.
120         * @param element the {@code Element} that is being parsed
121         * @return the class name of the bean that is being defined via parsing
122         * the supplied {@code Element}, or {@code null} if none
123         * @see #getBeanClass
124         */
125        protected String getBeanClassName(Element element) {
126                return null;
127        }
128
129        /**
130         * Parse the supplied {@link Element} and populate the supplied
131         * {@link BeanDefinitionBuilder} as required.
132         * <p>The default implementation delegates to the {@code doParse}
133         * version without ParserContext argument.
134         * @param element the XML element being parsed
135         * @param parserContext the object encapsulating the current state of the parsing process
136         * @param builder used to define the {@code BeanDefinition}
137         * @see #doParse(Element, BeanDefinitionBuilder)
138         */
139        protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
140                doParse(element, builder);
141        }
142
143        /**
144         * Parse the supplied {@link Element} and populate the supplied
145         * {@link BeanDefinitionBuilder} as required.
146         * <p>The default implementation does nothing.
147         * @param element the XML element being parsed
148         * @param builder used to define the {@code BeanDefinition}
149         */
150        protected void doParse(Element element, BeanDefinitionBuilder builder) {
151        }
152
153}