001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.beans.factory.support;
018:
019: import org.springframework.beans.MutablePropertyValues;
020: import org.springframework.beans.factory.BeanDefinitionStoreException;
021: import org.springframework.beans.factory.BeanFactoryUtils;
022: import org.springframework.beans.factory.config.BeanDefinitionHolder;
023: import org.springframework.beans.factory.config.ConstructorArgumentValues;
024: import org.springframework.util.ClassUtils;
025: import org.springframework.util.ObjectUtils;
026: import org.springframework.util.StringUtils;
027:
028: /**
029: * Utility methods that are useful for bean definition reader implementations.
030: * Mainly intended for internal use.
031: *
032: * @author Juergen Hoeller
033: * @author Rob Harrop
034: * @since 1.1
035: * @see PropertiesBeanDefinitionReader
036: * @see org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
037: */
038: public class BeanDefinitionReaderUtils {
039:
040: /**
041: * Separator for generated bean names. If a class name or parent name is not
042: * unique, "#1", "#2" etc will be appended, until the name becomes unique.
043: */
044: public static final String GENERATED_BEAN_NAME_SEPARATOR = BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR;
045:
046: /**
047: * Create a new RootBeanDefinition or ChildBeanDefinition for the given
048: * class name, parent, constructor arguments, and property values.
049: * @param className the name of the bean class, if any
050: * @param parent the name of the parent bean, if any
051: * @param cargs the constructor arguments, if any
052: * @param pvs the property values, if any
053: * @param classLoader the ClassLoader to use for loading bean classes
054: * (can be <code>null</code> to just register bean classes by name)
055: * @return the bean definition
056: * @throws ClassNotFoundException if the bean class could not be loaded
057: * @deprecated in favor of <code>createBeanDefinition(String, String, ClassLoader)</code>
058: * @see #createBeanDefinition(String, String, ClassLoader)
059: */
060: public static AbstractBeanDefinition createBeanDefinition(
061: String className, String parent,
062: ConstructorArgumentValues cargs, MutablePropertyValues pvs,
063: ClassLoader classLoader) throws ClassNotFoundException {
064:
065: AbstractBeanDefinition bd = createBeanDefinition(parent,
066: className, classLoader);
067: bd.setConstructorArgumentValues(cargs);
068: bd.setPropertyValues(pvs);
069: return bd;
070: }
071:
072: /**
073: * Create a new RootBeanDefinition or ChildBeanDefinition for the given
074: * class name, parent, constructor arguments, and property values.
075: * @param parent the name of the parent bean, if any
076: * @param className the name of the bean class, if any
077: * @param classLoader the ClassLoader to use for loading bean classes
078: * (can be <code>null</code> to just register bean classes by name)
079: * @return the bean definition
080: * @throws ClassNotFoundException if the bean class could not be loaded
081: */
082: public static AbstractBeanDefinition createBeanDefinition(
083: String parent, String className, ClassLoader classLoader)
084: throws ClassNotFoundException {
085:
086: AbstractBeanDefinition bd = null;
087: if (parent != null) {
088: bd = new ChildBeanDefinition(parent);
089: } else {
090: bd = new RootBeanDefinition();
091: }
092: if (className != null) {
093: if (classLoader != null) {
094: bd.setBeanClass(ClassUtils.forName(className,
095: classLoader));
096: } else {
097: bd.setBeanClassName(className);
098: }
099: }
100: return bd;
101: }
102:
103: /**
104: * Generate a bean name for the given bean definition, unique within the
105: * given bean factory.
106: * @param beanDefinition the bean definition to generate a bean name for
107: * @param beanFactory the bean factory that the definition is going to be
108: * registered with (to check for existing bean names)
109: * @param isInnerBean whether the given bean definition will be registered
110: * as inner bean or as top-level bean (allowing for special name generation
111: * for inner beans versus top-level beans)
112: * @return the generated bean name
113: * @throws BeanDefinitionStoreException if no unique name can be generated
114: * for the given bean definition
115: */
116: public static String generateBeanName(
117: AbstractBeanDefinition beanDefinition,
118: BeanDefinitionRegistry beanFactory, boolean isInnerBean)
119: throws BeanDefinitionStoreException {
120:
121: String generatedId = beanDefinition.getBeanClassName();
122: if (generatedId == null) {
123: if (beanDefinition instanceof ChildBeanDefinition) {
124: generatedId = ((ChildBeanDefinition) beanDefinition)
125: .getParentName()
126: + "$child";
127: } else if (beanDefinition.getFactoryBeanName() != null) {
128: generatedId = beanDefinition.getFactoryBeanName()
129: + "$created";
130: }
131: }
132: if (!StringUtils.hasText(generatedId)) {
133: throw new BeanDefinitionStoreException(
134: "Unnamed bean definition specifies neither "
135: + "'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
136: }
137:
138: String id = generatedId;
139: if (isInnerBean) {
140: // Inner bean: generate identity hashcode suffix.
141: id = generatedId + GENERATED_BEAN_NAME_SEPARATOR
142: + ObjectUtils.getIdentityHexString(beanDefinition);
143: } else {
144: // Top-level bean: use plain class name. If not already unique,
145: // add counter - increasing the counter until the name is unique.
146: int counter = 0;
147: while (beanFactory.containsBeanDefinition(id)) {
148: counter++;
149: id = generatedId + GENERATED_BEAN_NAME_SEPARATOR
150: + counter;
151: }
152: }
153: return id;
154: }
155:
156: /**
157: * Generate a bean name for the given top-level bean definition,
158: * unique within the given bean factory.
159: * @param beanDefinition the bean definition to generate a bean name for
160: * @param beanFactory the bean factory that the definition is going to be
161: * registered with (to check for existing bean names)
162: * @return the generated bean name
163: * @throws BeanDefinitionStoreException if no unique name can be generated
164: * for the given bean definition
165: */
166: public static String generateBeanName(
167: AbstractBeanDefinition beanDefinition,
168: BeanDefinitionRegistry beanFactory)
169: throws BeanDefinitionStoreException {
170:
171: return generateBeanName(beanDefinition, beanFactory, false);
172: }
173:
174: /**
175: * Register the given bean definition with the given bean factory.
176: * @param bdHolder the bean definition including name and aliases
177: * @param beanFactory the bean factory to register with
178: * @throws BeanDefinitionStoreException if registration failed
179: */
180: public static void registerBeanDefinition(
181: BeanDefinitionHolder bdHolder,
182: BeanDefinitionRegistry beanFactory)
183: throws BeanDefinitionStoreException {
184:
185: // Register bean definition under primary name.
186: String beanName = bdHolder.getBeanName();
187: beanFactory.registerBeanDefinition(beanName, bdHolder
188: .getBeanDefinition());
189:
190: // Register aliases for bean name, if any.
191: String[] aliases = bdHolder.getAliases();
192: if (aliases != null) {
193: for (int i = 0; i < aliases.length; i++) {
194: beanFactory.registerAlias(beanName, aliases[i]);
195: }
196: }
197: }
198:
199: /**
200: * Register the given bean definition with a generated name,
201: * unique within the given bean factory.
202: * @param beanDefinition the bean definition to generate a bean name for
203: * @param beanFactory the bean factory to register with
204: * @return the generated bean name
205: * @throws BeanDefinitionStoreException if no unique name can be generated
206: * for the given bean definition or the definition cannot be registered
207: */
208: public static String registerWithGeneratedName(
209: AbstractBeanDefinition beanDefinition,
210: BeanDefinitionRegistry beanFactory)
211: throws BeanDefinitionStoreException {
212:
213: String generatedName = generateBeanName(beanDefinition,
214: beanFactory, false);
215: beanFactory.registerBeanDefinition(generatedName,
216: beanDefinition);
217: return generatedName;
218: }
219:
220: }
|