Package org.springframework.beans.factory.support

Source Code of org.springframework.beans.factory.support.BeanDefinitionValueResolver

/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.beans.factory.support;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;

/**
* Helper class for use in bean factory implementations,
* resolving values contained in bean definition objects
* into the actual values applied to the target bean instance.
*
* <p>Operates on an {@link AbstractBeanFactory} and a plain
* {@link org.springframework.beans.factory.config.BeanDefinition} object.
* Used by {@link AbstractAutowireCapableBeanFactory}.
*
* @author Juergen Hoeller
* @since 1.2
* @see AbstractAutowireCapableBeanFactory
*/
class BeanDefinitionValueResolver {

  private final AbstractBeanFactory beanFactory;

  private final String beanName;

  private final BeanDefinition beanDefinition;

  private final TypeConverter typeConverter;


  /**
   * Create a BeanDefinitionValueResolver for the given BeanFactory and BeanDefinition.
   * @param beanFactory the BeanFactory to resolve against
   * @param beanName the name of the bean that we work on
   * @param beanDefinition the BeanDefinition of the bean that we work on
   * @param typeConverter the TypeConverter to use for resolving TypedStringValues
   */
  public BeanDefinitionValueResolver(
      AbstractBeanFactory beanFactory, String beanName, BeanDefinition beanDefinition, TypeConverter typeConverter) {

    this.beanFactory = beanFactory;
    this.beanName = beanName;
    this.beanDefinition = beanDefinition;
    this.typeConverter = typeConverter;
  }

  /**
   * Given a PropertyValue, return a value, resolving any references to other
   * beans in the factory if necessary. The value could be:
   * <li>A BeanDefinition, which leads to the creation of a corresponding
   * new bean instance. Singleton flags and names of such "inner beans"
   * are always ignored: Inner beans are anonymous prototypes.
   * <li>A RuntimeBeanReference, which must be resolved.
   * <li>A ManagedList. This is a special collection that may contain
   * RuntimeBeanReferences or Collections that will need to be resolved.
   * <li>A ManagedSet. May also contain RuntimeBeanReferences or
   * Collections that will need to be resolved.
   * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
   * or Collection that will need to be resolved.
   * <li>An ordinary object or <code>null</code>, in which case it's left alone.
   * @param argName the name of the argument that the value is defined for
   * @param value the value object to resolve
   * @return the resolved object
   */
  public Object resolveValueIfNecessary(Object argName, Object value) {
    // We must check each value to see whether it requires a runtime reference
    // to another bean to be resolved.
    if (value instanceof RuntimeBeanReference) {
      RuntimeBeanReference ref = (RuntimeBeanReference) value;
      return resolveReference(argName, ref);
    }
    else if (value instanceof RuntimeBeanNameReference) {
      String ref = ((RuntimeBeanNameReference) value).getBeanName();
      if (!this.beanFactory.containsBean(ref)) {
        throw new BeanDefinitionStoreException(
            "Invalid bean name '" + ref + "' in bean reference for " + argName);
      }
      return ref;
    }
    else if (value instanceof BeanDefinitionHolder) {
      // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
      BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
      return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
    }
    else if (value instanceof BeanDefinition) {
      // Resolve plain BeanDefinition, without contained name: use dummy name.
      BeanDefinition bd = (BeanDefinition) value;
      return resolveInnerBean(argName, "(inner bean)", bd);
    }
    else if (value instanceof ManagedList) {
      // May need to resolve contained runtime references.
      return resolveManagedList(argName, (List) value);
    }
    else if (value instanceof ManagedSet) {
      // May need to resolve contained runtime references.
      return resolveManagedSet(argName, (Set) value);
    }
    else if (value instanceof ManagedMap) {
      // May need to resolve contained runtime references.
      return resolveManagedMap(argName, (Map) value);
    }
    else if (value instanceof ManagedProperties) {
      Properties original = (Properties) value;
      Properties copy = new Properties();
      for (Iterator it = original.entrySet().iterator(); it.hasNext();) {
        Map.Entry propEntry = (Map.Entry) it.next();
        Object propKey = propEntry.getKey();
        Object propValue = propEntry.getValue();
        if (propKey instanceof TypedStringValue) {
          propKey = ((TypedStringValue) propKey).getValue();
        }
        if (propValue instanceof TypedStringValue) {
          propValue = ((TypedStringValue) propValue).getValue();
        }
        copy.put(propKey, propValue);
      }
      return copy;
    }
    else if (value instanceof TypedStringValue) {
      // Convert value to target type here.
      TypedStringValue typedStringValue = (TypedStringValue) value;
      try {
        Class resolvedTargetType = resolveTargetType(typedStringValue);
        if (resolvedTargetType != null) {
          return this.typeConverter.convertIfNecessary(typedStringValue.getValue(), resolvedTargetType);
        }
        else {
          // No target type specified - no conversion necessary...
          return typedStringValue.getValue();
        }
      }
      catch (Throwable ex) {
        // Improve the message by showing the context.
        throw new BeanCreationException(
            this.beanDefinition.getResourceDescription(), this.beanName,
            "Error converting typed String value for " + argName, ex);
      }
    }
    else {
      // No need to resolve value...
      return value;
    }
  }

  /**
   * Resolve the target type in the given TypedStringValue.
   * @param value the TypedStringValue to resolve
   * @return the resolved target type (or <code>null</code> if none specified)
   * @throws ClassNotFoundException if the specified type cannot be resolved
   * @see TypedStringValue#resolveTargetType
   */
  protected Class resolveTargetType(TypedStringValue value) throws ClassNotFoundException {
    if (value.hasTargetType()) {
      return value.getTargetType();
    }
    return value.resolveTargetType(this.beanFactory.getBeanClassLoader());
  }

  /**
   * Resolve an inner bean definition.
   * @param argName the name of the argument that the inner bean is defined for
   * @param innerBeanName the name of the inner bean
   * @param innerBd the bean definition for the inner bean
   * @return the resolved inner bean instance
   */
  private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefinition innerBd) {
    RootBeanDefinition mbd = null;
    try {
      mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
      // Check given bean name whether it is unique. If not already unique,
      // add counter - increasing the counter until the name is unique.
      String actualInnerBeanName = innerBeanName;
      if (mbd.isSingleton()) {
        actualInnerBeanName = adaptInnerBeanName(innerBeanName);
      }
      // Guarantee initialization of beans that the inner bean depends on.
      String[] dependsOn = mbd.getDependsOn();
      if (dependsOn != null) {
        for (int i = 0; i < dependsOn.length; i++) {
          String dependsOnBean = dependsOn[i];
          this.beanFactory.getBean(dependsOnBean);
          this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
        }
      }
      Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
      this.beanFactory.registerDependentBean(actualInnerBeanName, this.beanName);
      if (innerBean instanceof FactoryBean) {
        return this.beanFactory.getObjectFromFactoryBean((FactoryBean) innerBean, actualInnerBeanName, mbd);
      }
      else {
        return innerBean;
      }
    }
    catch (BeansException ex) {
      throw new BeanCreationException(
          this.beanDefinition.getResourceDescription(), this.beanName,
          "Cannot create inner bean '" + innerBeanName + "' " +
          (mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
          "while setting " + argName, ex);
    }
  }

  /**
   * Checks the given bean name whether it is unique. If not already unique,
   * a counter is added, increasing the counter until the name is unique.
   * @param innerBeanName the original name for the inner bean
   * @return the adapted name for the inner bean
   */
  private String adaptInnerBeanName(String innerBeanName) {
    String actualInnerBeanName = innerBeanName;
    int counter = 0;
    while (this.beanFactory.isBeanNameInUse(actualInnerBeanName)) {
      counter++;
      actualInnerBeanName = innerBeanName + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + counter;
    }
    return actualInnerBeanName;
  }

  /**
   * Resolve a reference to another bean in the factory.
   */
  private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    try {
      if (ref.isToParent()) {
        if (this.beanFactory.getParentBeanFactory() == null) {
          throw new BeanCreationException(
              this.beanDefinition.getResourceDescription(), this.beanName,
              "Can't resolve reference to bean '" + ref.getBeanName() +
              "' in parent factory: no parent factory available");
        }
        return this.beanFactory.getParentBeanFactory().getBean(ref.getBeanName());
      }
      else {
        Object bean = this.beanFactory.getBean(ref.getBeanName());
        this.beanFactory.registerDependentBean(ref.getBeanName(), this.beanName);
        return bean;
      }
    }
    catch (BeansException ex) {
      throw new BeanCreationException(
          this.beanDefinition.getResourceDescription(), this.beanName,
          "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
    }
  }

  /**
   * For each element in the ManagedList, resolve reference if necessary.
   */
  private List resolveManagedList(Object argName, List ml) {
    List resolved = new ArrayList(ml.size());
    for (int i = 0; i < ml.size(); i++) {
      resolved.add(
          resolveValueIfNecessary(
              argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
              ml.get(i)));
    }
    return resolved;
  }

  /**
   * For each element in the ManagedList, resolve reference if necessary.
   */
  private Set resolveManagedSet(Object argName, Set ms) {
    Set resolved = new LinkedHashSet(ms.size());
    int i = 0;
    for (Iterator it = ms.iterator(); it.hasNext();) {
      resolved.add(
          resolveValueIfNecessary(
              argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX,
              it.next()));
      i++;
    }
    return resolved;
  }

  /**
   * For each element in the ManagedMap, resolve reference if necessary.
   */
  private Map resolveManagedMap(Object argName, Map mm) {
    Map resolved = new LinkedHashMap(mm.size());
    Iterator it = mm.entrySet().iterator();
    while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
      Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
      Object resolvedValue = resolveValueIfNecessary(
          argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + entry.getKey() + BeanWrapper.PROPERTY_KEY_SUFFIX,
          entry.getValue());
      resolved.put(resolvedKey, resolvedValue);
    }
    return resolved;
  }

}
TOP

Related Classes of org.springframework.beans.factory.support.BeanDefinitionValueResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.