Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » beans » factory » support » [javadoc | source]
    1   /*
    2    * Copyright 2002-2008 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.springframework.beans.factory.support;
   18   
   19   import java.util.ArrayList;
   20   import java.util.Iterator;
   21   import java.util.LinkedHashMap;
   22   import java.util.LinkedHashSet;
   23   import java.util.List;
   24   import java.util.Map;
   25   import java.util.Properties;
   26   import java.util.Set;
   27   
   28   import org.springframework.beans.BeanWrapper;
   29   import org.springframework.beans.BeansException;
   30   import org.springframework.beans.TypeConverter;
   31   import org.springframework.beans.factory.BeanCreationException;
   32   import org.springframework.beans.factory.BeanDefinitionStoreException;
   33   import org.springframework.beans.factory.BeanFactoryUtils;
   34   import org.springframework.beans.factory.FactoryBean;
   35   import org.springframework.beans.factory.config.BeanDefinition;
   36   import org.springframework.beans.factory.config.BeanDefinitionHolder;
   37   import org.springframework.beans.factory.config.RuntimeBeanNameReference;
   38   import org.springframework.beans.factory.config.RuntimeBeanReference;
   39   import org.springframework.beans.factory.config.TypedStringValue;
   40   
   41   /**
   42    * Helper class for use in bean factory implementations,
   43    * resolving values contained in bean definition objects
   44    * into the actual values applied to the target bean instance.
   45    *
   46    * <p>Operates on an {@link AbstractBeanFactory} and a plain
   47    * {@link org.springframework.beans.factory.config.BeanDefinition} object.
   48    * Used by {@link AbstractAutowireCapableBeanFactory}.
   49    *
   50    * @author Juergen Hoeller
   51    * @since 1.2
   52    * @see AbstractAutowireCapableBeanFactory
   53    */
   54   class BeanDefinitionValueResolver {
   55   
   56   	private final AbstractBeanFactory beanFactory;
   57   
   58   	private final String beanName;
   59   
   60   	private final BeanDefinition beanDefinition;
   61   
   62   	private final TypeConverter typeConverter;
   63   
   64   
   65   	/**
   66   	 * Create a BeanDefinitionValueResolver for the given BeanFactory and BeanDefinition.
   67   	 * @param beanFactory the BeanFactory to resolve against
   68   	 * @param beanName the name of the bean that we work on
   69   	 * @param beanDefinition the BeanDefinition of the bean that we work on
   70   	 * @param typeConverter the TypeConverter to use for resolving TypedStringValues
   71   	 */
   72   	public BeanDefinitionValueResolver(
   73   			AbstractBeanFactory beanFactory, String beanName, BeanDefinition beanDefinition, TypeConverter typeConverter) {
   74   
   75   		this.beanFactory = beanFactory;
   76   		this.beanName = beanName;
   77   		this.beanDefinition = beanDefinition;
   78   		this.typeConverter = typeConverter;
   79   	}
   80   
   81   	/**
   82   	 * Given a PropertyValue, return a value, resolving any references to other
   83   	 * beans in the factory if necessary. The value could be:
   84   	 * <li>A BeanDefinition, which leads to the creation of a corresponding
   85   	 * new bean instance. Singleton flags and names of such "inner beans"
   86   	 * are always ignored: Inner beans are anonymous prototypes.
   87   	 * <li>A RuntimeBeanReference, which must be resolved.
   88   	 * <li>A ManagedList. This is a special collection that may contain
   89   	 * RuntimeBeanReferences or Collections that will need to be resolved.
   90   	 * <li>A ManagedSet. May also contain RuntimeBeanReferences or
   91   	 * Collections that will need to be resolved.
   92   	 * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
   93   	 * or Collection that will need to be resolved.
   94   	 * <li>An ordinary object or <code>null</code>, in which case it's left alone.
   95   	 * @param argName the name of the argument that the value is defined for
   96   	 * @param value the value object to resolve
   97   	 * @return the resolved object
   98   	 */
   99   	public Object resolveValueIfNecessary(Object argName, Object value) {
  100   		// We must check each value to see whether it requires a runtime reference
  101   		// to another bean to be resolved.
  102   		if (value instanceof RuntimeBeanReference) {
  103   			RuntimeBeanReference ref = (RuntimeBeanReference) value;
  104   			return resolveReference(argName, ref);
  105   		}
  106   		else if (value instanceof RuntimeBeanNameReference) {
  107   			String ref = ((RuntimeBeanNameReference) value).getBeanName();
  108   			if (!this.beanFactory.containsBean(ref)) {
  109   				throw new BeanDefinitionStoreException(
  110   						"Invalid bean name '" + ref + "' in bean reference for " + argName);
  111   			}
  112   			return ref;
  113   		}
  114   		else if (value instanceof BeanDefinitionHolder) {
  115   			// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
  116   			BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
  117   			return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
  118   		}
  119   		else if (value instanceof BeanDefinition) {
  120   			// Resolve plain BeanDefinition, without contained name: use dummy name.
  121   			BeanDefinition bd = (BeanDefinition) value;
  122   			return resolveInnerBean(argName, "(inner bean)", bd);
  123   		}
  124   		else if (value instanceof ManagedList) {
  125   			// May need to resolve contained runtime references.
  126   			return resolveManagedList(argName, (List) value);
  127   		}
  128   		else if (value instanceof ManagedSet) {
  129   			// May need to resolve contained runtime references.
  130   			return resolveManagedSet(argName, (Set) value);
  131   		}
  132   		else if (value instanceof ManagedMap) {
  133   			// May need to resolve contained runtime references.
  134   			return resolveManagedMap(argName, (Map) value);
  135   		}
  136   		else if (value instanceof ManagedProperties) {
  137   			Properties original = (Properties) value;
  138   			Properties copy = new Properties();
  139   			for (Iterator it = original.entrySet().iterator(); it.hasNext();) {
  140   				Map.Entry propEntry = (Map.Entry) it.next();
  141   				Object propKey = propEntry.getKey();
  142   				Object propValue = propEntry.getValue();
  143   				if (propKey instanceof TypedStringValue) {
  144   					propKey = ((TypedStringValue) propKey).getValue();
  145   				}
  146   				if (propValue instanceof TypedStringValue) {
  147   					propValue = ((TypedStringValue) propValue).getValue();
  148   				}
  149   				copy.put(propKey, propValue);
  150   			}
  151   			return copy;
  152   		}
  153   		else if (value instanceof TypedStringValue) {
  154   			// Convert value to target type here.
  155   			TypedStringValue typedStringValue = (TypedStringValue) value;
  156   			try {
  157   				Class resolvedTargetType = resolveTargetType(typedStringValue);
  158   				if (resolvedTargetType != null) {
  159   					return this.typeConverter.convertIfNecessary(typedStringValue.getValue(), resolvedTargetType);
  160   				}
  161   				else {
  162   					// No target type specified - no conversion necessary...
  163   					return typedStringValue.getValue();
  164   				}
  165   			}
  166   			catch (Throwable ex) {
  167   				// Improve the message by showing the context.
  168   				throw new BeanCreationException(
  169   						this.beanDefinition.getResourceDescription(), this.beanName,
  170   						"Error converting typed String value for " + argName, ex);
  171   			}
  172   		}
  173   		else {
  174   			// No need to resolve value...
  175   			return value;
  176   		}
  177   	}
  178   
  179   	/**
  180   	 * Resolve the target type in the given TypedStringValue.
  181   	 * @param value the TypedStringValue to resolve
  182   	 * @return the resolved target type (or <code>null</code> if none specified)
  183   	 * @throws ClassNotFoundException if the specified type cannot be resolved
  184   	 * @see TypedStringValue#resolveTargetType
  185   	 */
  186   	protected Class resolveTargetType(TypedStringValue value) throws ClassNotFoundException {
  187   		if (value.hasTargetType()) {
  188   			return value.getTargetType();
  189   		}
  190   		return value.resolveTargetType(this.beanFactory.getBeanClassLoader());
  191   	}
  192   
  193   	/**
  194   	 * Resolve an inner bean definition.
  195   	 * @param argName the name of the argument that the inner bean is defined for
  196   	 * @param innerBeanName the name of the inner bean
  197   	 * @param innerBd the bean definition for the inner bean
  198   	 * @return the resolved inner bean instance
  199   	 */
  200   	private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefinition innerBd) {
  201   		RootBeanDefinition mbd = null;
  202   		try {
  203   			mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
  204   			// Check given bean name whether it is unique. If not already unique,
  205   			// add counter - increasing the counter until the name is unique.
  206   			String actualInnerBeanName = innerBeanName;
  207   			if (mbd.isSingleton()) {
  208   				actualInnerBeanName = adaptInnerBeanName(innerBeanName);
  209   			}
  210   			// Guarantee initialization of beans that the inner bean depends on.
  211   			String[] dependsOn = mbd.getDependsOn();
  212   			if (dependsOn != null) {
  213   				for (int i = 0; i < dependsOn.length; i++) {
  214   					String dependsOnBean = dependsOn[i];
  215   					this.beanFactory.getBean(dependsOnBean);
  216   					this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
  217   				}
  218   			}
  219   			Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
  220   			this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
  221   			if (innerBean instanceof FactoryBean) {
  222   				boolean synthetic = (mbd != null && mbd.isSynthetic());
  223   				return this.beanFactory.getObjectFromFactoryBean((FactoryBean) innerBean, actualInnerBeanName, !synthetic);
  224   			}
  225   			else {
  226   				return innerBean;
  227   			}
  228   		}
  229   		catch (BeansException ex) {
  230   			throw new BeanCreationException(
  231   					this.beanDefinition.getResourceDescription(), this.beanName,
  232   					"Cannot create inner bean '" + innerBeanName + "' " +
  233   					(mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
  234   					"while setting " + argName, ex);
  235   		}
  236   	}
  237   
  238   	/**
  239   	 * Checks the given bean name whether it is unique. If not already unique,
  240   	 * a counter is added, increasing the counter until the name is unique.
  241   	 * @param innerBeanName the original name for the inner bean
  242   	 * @return the adapted name for the inner bean
  243   	 */
  244   	private String adaptInnerBeanName(String innerBeanName) {
  245   		String actualInnerBeanName = innerBeanName;
  246   		int counter = 0;
  247   		while (this.beanFactory.isBeanNameInUse(actualInnerBeanName)) {
  248   			counter++;
  249   			actualInnerBeanName = innerBeanName + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + counter;
  250   		}
  251   		return actualInnerBeanName;
  252   	}
  253   
  254   	/**
  255   	 * Resolve a reference to another bean in the factory.
  256   	 */
  257   	private Object resolveReference(Object argName, RuntimeBeanReference ref) {
  258   		try {
  259   			if (ref.isToParent()) {
  260   				if (this.beanFactory.getParentBeanFactory() == null) {
  261   					throw new BeanCreationException(
  262   							this.beanDefinition.getResourceDescription(), this.beanName,
  263   							"Can't resolve reference to bean '" + ref.getBeanName() +
  264   							"' in parent factory: no parent factory available");
  265   				}
  266   				return this.beanFactory.getParentBeanFactory().getBean(ref.getBeanName());
  267   			}
  268   			else {
  269   				Object bean = this.beanFactory.getBean(ref.getBeanName());
  270   				this.beanFactory.registerDependentBean(ref.getBeanName(), this.beanName);
  271   				return bean;
  272   			}
  273   		}
  274   		catch (BeansException ex) {
  275   			throw new BeanCreationException(
  276   					this.beanDefinition.getResourceDescription(), this.beanName,
  277   					"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
  278   		}
  279   	}
  280   
  281   	/**
  282   	 * For each element in the ManagedList, resolve reference if necessary.
  283   	 */
  284   	private List resolveManagedList(Object argName, List ml) {
  285   		List resolved = new ArrayList(ml.size());
  286   		for (int i = 0; i < ml.size(); i++) {
  287   			resolved.add(
  288   			    resolveValueIfNecessary(
  289   							argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
  290   							ml.get(i)));
  291   		}
  292   		return resolved;
  293   	}
  294   
  295   	/**
  296   	 * For each element in the ManagedList, resolve reference if necessary.
  297   	 */
  298   	private Set resolveManagedSet(Object argName, Set ms) {
  299   		Set resolved = new LinkedHashSet(ms.size());
  300   		int i = 0;
  301   		for (Iterator it = ms.iterator(); it.hasNext();) {
  302   			resolved.add(
  303   			    resolveValueIfNecessary(
  304   							argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
  305   							it.next()));
  306   			i++;
  307   		}
  308   		return resolved;
  309   	}
  310   
  311   	/**
  312   	 * For each element in the ManagedMap, resolve reference if necessary.
  313   	 */
  314   	private Map resolveManagedMap(Object argName, Map mm) {
  315   		Map resolved = new LinkedHashMap(mm.size());
  316   		Iterator it = mm.entrySet().iterator();
  317   		while (it.hasNext()) {
  318   			Map.Entry entry = (Map.Entry) it.next();
  319   			Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
  320   			Object resolvedValue = resolveValueIfNecessary(
  321   					argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + entry.getKey() + BeanWrapper.PROPERTY_KEY_SUFFIX,
  322   					entry.getValue());
  323   			resolved.put(resolvedKey, resolvedValue);
  324   		}
  325   		return resolved;
  326   	}
  327   
  328   }

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » beans » factory » support » [javadoc | source]