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