Open Source Repository

Home /spring/spring-beans-3.0.5 | Repository Home



org/springframework/beans/factory/support/AbstractBeanDefinition.java
/*
 * Copyright 2002-2009 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.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.BeanMetadataAttributeAccessor;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * Base class for concrete, full-fledged
 {@link org.springframework.beans.factory.config.BeanDefinition} classes,
 * factoring out common properties of {@link RootBeanDefinition} and
 {@link ChildBeanDefinition}.
 *
 <p>The autowire constants match the ones defined in the
 {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
 * interface.
 *
 @author Rod Johnson
 @author Juergen Hoeller
 @author Rob Harrop
 @author Mark Fisher
 @see RootBeanDefinition
 @see ChildBeanDefinition
 */
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
    implements BeanDefinition, Cloneable {

  /**
   * Constant for the default scope name: "", equivalent to singleton status
   * but to be overridden from a parent bean definition (if applicable).
   */
  public static final String SCOPE_DEFAULT = "";


  /**
   * Constant that indicates no autowiring at all.
   @see #setAutowireMode
   */
  public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;

  /**
   * Constant that indicates autowiring bean properties by name.
   @see #setAutowireMode
   */
  public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;

  /**
   * Constant that indicates autowiring bean properties by type.
   @see #setAutowireMode
   */
  public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;

  /**
   * Constant that indicates autowiring a constructor.
   @see #setAutowireMode
   */
  public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;

  /**
   * Constant that indicates determining an appropriate autowire strategy
   * through introspection of the bean class.
   @see #setAutowireMode
   @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
   * use annotation-based autowiring for clearer demarcation of autowiring needs.
   */
  @Deprecated
  public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;


  /**
   * Constant that indicates no dependency check at all.
   @see #setDependencyCheck
   */
  public static final int DEPENDENCY_CHECK_NONE = 0;

  /**
   * Constant that indicates dependency checking for object references.
   @see #setDependencyCheck
   */
  public static final int DEPENDENCY_CHECK_OBJECTS = 1;

  /**
   * Constant that indicates dependency checking for "simple" properties.
   @see #setDependencyCheck
   @see org.springframework.beans.BeanUtils#isSimpleProperty
   */
  public static final int DEPENDENCY_CHECK_SIMPLE = 2;

  /**
   * Constant that indicates dependency checking for all properties
   * (object references as well as "simple" properties).
   @see #setDependencyCheck
   */
  public static final int DEPENDENCY_CHECK_ALL = 3;


  private volatile Object beanClass;

  private String scope = SCOPE_DEFAULT;

  private boolean singleton = true;

  private boolean prototype = false;

  private boolean abstractFlag = false;

  private boolean lazyInit = false;

  private int autowireMode = AUTOWIRE_NO;

  private int dependencyCheck = DEPENDENCY_CHECK_NONE;

  private String[] dependsOn;

  private boolean autowireCandidate = true;

  private boolean primary = false;

  private final Map<String, AutowireCandidateQualifier> qualifiers =
      new LinkedHashMap<String, AutowireCandidateQualifier>(0);

  private boolean nonPublicAccessAllowed = true;

  private boolean lenientConstructorResolution = true;

  private ConstructorArgumentValues constructorArgumentValues;

  private MutablePropertyValues propertyValues;

  private MethodOverrides methodOverrides = new MethodOverrides();

  private String factoryBeanName;

  private String factoryMethodName;

  private String initMethodName;

  private String destroyMethodName;

  private boolean enforceInitMethod = true;

  private boolean enforceDestroyMethod = true;

  private boolean synthetic = false;

  private int role = BeanDefinition.ROLE_APPLICATION;

  private String description;

  private Resource resource;


  /**
   * Create a new AbstractBeanDefinition with default settings.
   */
  protected AbstractBeanDefinition() {
    this(null, null);
  }

  /**
   * Create a new AbstractBeanDefinition with the given
   * constructor argument values and property values.
   */
  protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
    setConstructorArgumentValues(cargs);
    setPropertyValues(pvs);
  }

  /**
   * Create a new AbstractBeanDefinition as deep copy of the given
   * bean definition.
   @param original the original bean definition to copy from
   @deprecated since Spring 2.5, in favor of {@link #AbstractBeanDefinition(BeanDefinition)}
   */
  @Deprecated
  protected AbstractBeanDefinition(AbstractBeanDefinition original) {
    this((BeanDefinitionoriginal);
  }

  /**
   * Create a new AbstractBeanDefinition as deep copy of the given
   * bean definition.
   @param original the original bean definition to copy from
   */
  protected AbstractBeanDefinition(BeanDefinition original) {
    setParentName(original.getParentName());
    setBeanClassName(original.getBeanClassName());
    setFactoryBeanName(original.getFactoryBeanName());
    setFactoryMethodName(original.getFactoryMethodName());
    setScope(original.getScope());
    setAbstract(original.isAbstract());
    setLazyInit(original.isLazyInit());
    setRole(original.getRole());
    setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
    setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
    setSource(original.getSource());
    copyAttributesFrom(original);

    if (original instanceof AbstractBeanDefinition) {
      AbstractBeanDefinition originalAbd = (AbstractBeanDefinitionoriginal;
      if (originalAbd.hasBeanClass()) {
        setBeanClass(originalAbd.getBeanClass());
      }
      setAutowireMode(originalAbd.getAutowireMode());
      setDependencyCheck(originalAbd.getDependencyCheck());
      setDependsOn(originalAbd.getDependsOn());
      setAutowireCandidate(originalAbd.isAutowireCandidate());
      copyQualifiersFrom(originalAbd);
      setPrimary(originalAbd.isPrimary());
      setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
      setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
      setInitMethodName(originalAbd.getInitMethodName());
      setEnforceInitMethod(originalAbd.isEnforceInitMethod());
      setDestroyMethodName(originalAbd.getDestroyMethodName());
      setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
      setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
      setSynthetic(originalAbd.isSynthetic());
      setResource(originalAbd.getResource());
    }
    else {
      setResourceDescription(original.getResourceDescription());
    }
  }


  /**
   * Override settings in this bean definition (assumably a copied parent
   * from a parent-child inheritance relationship) from the given bean
   * definition (assumably the child).
   @deprecated since Spring 2.5, in favor of {@link #overrideFrom(BeanDefinition)}
   */
  @Deprecated
  public void overrideFrom(AbstractBeanDefinition other) {
    overrideFrom((BeanDefinitionother);
  }

  /**
   * Override settings in this bean definition (assumably a copied parent
   * from a parent-child inheritance relationship) from the given bean
   * definition (assumably the child).
   <ul>
   <li>Will override beanClass if specified in the given bean definition.
   <li>Will always take <code>abstract</code><code>scope</code>,
   <code>lazyInit</code><code>autowireMode</code><code>dependencyCheck</code>,
   * and <code>dependsOn</code> from the given bean definition.
   <li>Will add <code>constructorArgumentValues</code><code>propertyValues</code>,
   <code>methodOverrides</code> from the given bean definition to existing ones.
   <li>Will override <code>factoryBeanName</code><code>factoryMethodName</code>,
   <code>initMethodName</code>, and <code>destroyMethodName</code> if specified
   * in the given bean definition.
   </ul>
   */
  public void overrideFrom(BeanDefinition other) {
    if (StringUtils.hasLength(other.getBeanClassName())) {
      setBeanClassName(other.getBeanClassName());
    }
    if (StringUtils.hasLength(other.getFactoryBeanName())) {
      setFactoryBeanName(other.getFactoryBeanName());
    }
    if (StringUtils.hasLength(other.getFactoryMethodName())) {
      setFactoryMethodName(other.getFactoryMethodName());
    }
    if (StringUtils.hasLength(other.getScope())) {
      setScope(other.getScope());
    }
    setAbstract(other.isAbstract());
    setLazyInit(other.isLazyInit());
    setRole(other.getRole());
    getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
    getPropertyValues().addPropertyValues(other.getPropertyValues());
    setSource(other.getSource());
    copyAttributesFrom(other);

    if (other instanceof AbstractBeanDefinition) {
      AbstractBeanDefinition otherAbd = (AbstractBeanDefinitionother;
      if (otherAbd.hasBeanClass()) {
        setBeanClass(otherAbd.getBeanClass());
      }
      setAutowireCandidate(otherAbd.isAutowireCandidate());
      setAutowireMode(otherAbd.getAutowireMode());
      copyQualifiersFrom(otherAbd);
      setPrimary(otherAbd.isPrimary());
      setDependencyCheck(otherAbd.getDependencyCheck());
      setDependsOn(otherAbd.getDependsOn());
      setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
      setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
      if (StringUtils.hasLength(otherAbd.getInitMethodName())) {
        setInitMethodName(otherAbd.getInitMethodName());
        setEnforceInitMethod(otherAbd.isEnforceInitMethod());
      }
      if (StringUtils.hasLength(otherAbd.getDestroyMethodName())) {
        setDestroyMethodName(otherAbd.getDestroyMethodName());
        setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
      }
      getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
      setSynthetic(otherAbd.isSynthetic());
      setResource(otherAbd.getResource());
    }
    else {
      setResourceDescription(other.getResourceDescription());
    }
  }

  /**
   * Apply the provided default values to this bean.
   @param defaults the defaults to apply
   */
  public void applyDefaults(BeanDefinitionDefaults defaults) {
    setLazyInit(defaults.isLazyInit());
    setAutowireMode(defaults.getAutowireMode());
    setDependencyCheck(defaults.getDependencyCheck());
    setInitMethodName(defaults.getInitMethodName());
    setEnforceInitMethod(false);
    setDestroyMethodName(defaults.getDestroyMethodName());
    setEnforceDestroyMethod(false);
  }


  /**
   * Return whether this definition specifies a bean class.
   */
  public boolean hasBeanClass() {
    return (this.beanClass instanceof Class);
  }

  /**
   * Specify the class for this bean.
   */
  public void setBeanClass(Class<?> beanClass) {
    this.beanClass = beanClass;
  }

  /**
   * Return the class of the wrapped bean, if already resolved.
   @return the bean class, or <code>null</code> if none defined
   @throws IllegalStateException if the bean definition does not define a bean class,
   * or a specified bean class name has not been resolved into an actual Class
   */
  public Class<?> getBeanClass() throws IllegalStateException {
    Object beanClassObject = this.beanClass;
    if (beanClassObject == null) {
      throw new IllegalStateException("No bean class specified on bean definition");
    }
    if (!(beanClassObject instanceof Class)) {
      throw new IllegalStateException(
          "Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
    }
    return (ClassbeanClassObject;
  }

  public void setBeanClassName(String beanClassName) {
    this.beanClass = beanClassName;
  }

  public String getBeanClassName() {
    Object beanClassObject = this.beanClass;
    if (beanClassObject instanceof Class) {
      return ((ClassbeanClassObject).getName();
    }
    else {
      return (StringbeanClassObject;
    }
  }

  /**
   * Determine the class of the wrapped bean, resolving it from a
   * specified class name if necessary. Will also reload a specified
   * Class from its name when called with the bean class already resolved.
   @param classLoader the ClassLoader to use for resolving a (potential) class name
   @return the resolved bean class
   @throws ClassNotFoundException if the class name could be resolved
   */
  public Class resolveBeanClass(ClassLoader classLoaderthrows ClassNotFoundException {
    String className = getBeanClassName();
    if (className == null) {
      return null;
    }
    Class resolvedClass = ClassUtils.forName(className, classLoader);
    this.beanClass = resolvedClass;
    return resolvedClass;
  }


  /**
   * Set the name of the target scope for the bean.
   <p>Default is singleton status, although this is only applied once
   * a bean definition becomes active in the containing factory. A bean
   * definition may eventually inherit its scope from a parent bean definitionFor this
   * reason, the default scope name is empty (empty String), with
   * singleton status being assumed until a resolved scope will be set.
   @see #SCOPE_SINGLETON
   @see #SCOPE_PROTOTYPE
   */
  public void setScope(String scope) {
    this.scope = scope;
    this.singleton = SCOPE_SINGLETON.equals(scope|| SCOPE_DEFAULT.equals(scope);
    this.prototype = SCOPE_PROTOTYPE.equals(scope);
  }

  /**
   * Return the name of the target scope for the bean.
   */
  public String getScope() {
    return this.scope;
  }

  /**
   * Set if this a <b>Singleton</b>, with a single, shared instance returned
   * on all calls. In case of "false", the BeanFactory will apply the <b>Prototype</b>
   * design pattern, with each caller requesting an instance getting an independent
   * instance. How this is exactly defined will depend on the BeanFactory.
   <p>"Singletons" are the commoner type, so the default is "true".
   * Note that as of Spring 2.0, this flag is just an alternative way to
   * specify scope="singleton" or scope="prototype".
   @deprecated since Spring 2.5, in favor of {@link #setScope}
   @see #setScope
   @see #SCOPE_SINGLETON
   @see #SCOPE_PROTOTYPE
   */
  @Deprecated
  public void setSingleton(boolean singleton) {
    this.scope = (singleton ? SCOPE_SINGLETON : SCOPE_PROTOTYPE);
    this.singleton = singleton;
    this.prototype = !singleton;
  }

  /**
   * Return whether this a <b>Singleton</b>, with a single shared instance
   * returned from all calls.
   @see #SCOPE_SINGLETON
   */
  public boolean isSingleton() {
    return this.singleton;
  }

  /**
   * Return whether this a <b>Prototype</b>, with an independent instance
   * returned for each call.
   @see #SCOPE_PROTOTYPE
   */
  public boolean isPrototype() {
    return this.prototype;
  }

  /**
   * Set if this bean is "abstract", i.e. not meant to be instantiated itself but
   * rather just serving as parent for concrete child bean definitions.
   <p>Default is "false". Specify true to tell the bean factory to not try to
   * instantiate that particular bean in any case.
   */
  public void setAbstract(boolean abstractFlag) {
    this.abstractFlag = abstractFlag;
  }

  /**
   * Return whether this bean is "abstract", i.e. not meant to be instantiated
   * itself but rather just serving as parent for concrete child bean definitions.
   */
  public boolean isAbstract() {
    return this.abstractFlag;
  }

  /**
   * Set whether this bean should be lazily initialized.
   <p>If <code>false</code>, the bean will get instantiated on startup by bean
   * factories that perform eager initialization of singletons.
   */
  public void setLazyInit(boolean lazyInit) {
    this.lazyInit = lazyInit;
  }

  /**
   * Return whether this bean should be lazily initialized, i.e. not
   * eagerly instantiated on startup. Only applicable to a singleton bean.
   */
  public boolean isLazyInit() {
    return this.lazyInit;
  }


  /**
   * Set the autowire mode. This determines whether any automagical detection
   * and setting of bean references will happen. Default is AUTOWIRE_NO,
   * which means there's no autowire.
   @param autowireMode the autowire mode to set.
   * Must be one of the constants defined in this class.
   @see #AUTOWIRE_NO
   @see #AUTOWIRE_BY_NAME
   @see #AUTOWIRE_BY_TYPE
   @see #AUTOWIRE_CONSTRUCTOR
   @see #AUTOWIRE_AUTODETECT
   */
  public void setAutowireMode(int autowireMode) {
    this.autowireMode = autowireMode;
  }

  /**
   * Return the autowire mode as specified in the bean definition.
   */
  public int getAutowireMode() {
    return this.autowireMode;
  }

  /**
   * Return the resolved autowire code,
   * (resolving AUTOWIRE_AUTODETECT to AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE).
   @see #AUTOWIRE_AUTODETECT
   @see #AUTOWIRE_CONSTRUCTOR
   @see #AUTOWIRE_BY_TYPE
   */
  public int getResolvedAutowireMode() {
    if (this.autowireMode == AUTOWIRE_AUTODETECT) {
      // Work out whether to apply setter autowiring or constructor autowiring.
      // If it has a no-arg constructor it's deemed to be setter autowiring,
      // otherwise we'll try constructor autowiring.
      Constructor[] constructors = getBeanClass().getConstructors();
      for (Constructor constructor : constructors) {
        if (constructor.getParameterTypes().length == 0) {
          return AUTOWIRE_BY_TYPE;
        }
      }
      return AUTOWIRE_CONSTRUCTOR;
    }
    else {
      return this.autowireMode;
    }
  }

  /**
   * Set the dependency check code.
   @param dependencyCheck the code to set.
   * Must be one of the four constants defined in this class.
   @see #DEPENDENCY_CHECK_NONE
   @see #DEPENDENCY_CHECK_OBJECTS
   @see #DEPENDENCY_CHECK_SIMPLE
   @see #DEPENDENCY_CHECK_ALL
   */
  public void setDependencyCheck(int dependencyCheck) {
    this.dependencyCheck = dependencyCheck;
  }

  /**
   * Return the dependency check code.
   */
  public int getDependencyCheck() {
    return this.dependencyCheck;
  }

  /**
   * Set the names of the beans that this bean depends on being initialized.
   * The bean factory will guarantee that these beans get initialized first.
   <p>Note that dependencies are normally expressed through bean properties or
   * constructor arguments. This property should just be necessary for other kinds
   * of dependencies like statics (*ugh*) or database preparation on startup.
   */
  public void setDependsOn(String[] dependsOn) {
    this.dependsOn = dependsOn;
  }

  /**
   * Return the bean names that this bean depends on.
   */
  public String[] getDependsOn() {
    return this.dependsOn;
  }

  /**
   * Set whether this bean is a candidate for getting autowired into some other bean.
   */
  public void setAutowireCandidate(boolean autowireCandidate) {
    this.autowireCandidate = autowireCandidate;
  }

  /**
   * Return whether this bean is a candidate for getting autowired into some other bean.
   */
  public boolean isAutowireCandidate() {
    return this.autowireCandidate;
  }

  /**
   * Set whether this bean is a primary autowire candidate.
   * If this value is true for exactly one bean among multiple
   * matching candidates, it will serve as a tie-breaker.
   */
  public void setPrimary(boolean primary) {
    this.primary = primary;
  }

  /**
   * Return whether this bean is a primary autowire candidate.
   * If this value is true for exactly one bean among multiple
   * matching candidates, it will serve as a tie-breaker.
   */
  public boolean isPrimary() {
    return this.primary;
  }

  /**
   * Register a qualifier to be used for autowire candidate resolution,
   * keyed by the qualifier's type name.
   @see AutowireCandidateQualifier#getTypeName()
   */
  public void addQualifier(AutowireCandidateQualifier qualifier) {
    this.qualifiers.put(qualifier.getTypeName(), qualifier);
  }

  /**
   * Return whether this bean has the specified qualifier.
   */
  public boolean hasQualifier(String typeName) {
    return this.qualifiers.keySet().contains(typeName);
  }

  /**
   * Return the qualifier mapped to the provided type name.
   */
  public AutowireCandidateQualifier getQualifier(String typeName) {
    return this.qualifiers.get(typeName);
  }

  /**
   * Return all registered qualifiers.
   @return the Set of {@link AutowireCandidateQualifier} objects.
   */
  public Set<AutowireCandidateQualifier> getQualifiers() {
    return new LinkedHashSet<AutowireCandidateQualifier>(this.qualifiers.values());
  }

  /**
   * Copy the qualifiers from the supplied AbstractBeanDefinition to this bean definition.
   @param source the AbstractBeanDefinition to copy from
   */
  public void copyQualifiersFrom(AbstractBeanDefinition source) {
    Assert.notNull(source, "Source must not be null");
    this.qualifiers.putAll(source.qualifiers);
  }


  /**
   * Specify whether to allow access to non-public constructors and methods,
   * for the case of externalized metadata pointing to those.
   <p>This applies to constructor resolution, factory method resolution,
   * and also init/destroy methods. Bean property accessors have to be public
   * in any case and are not affected by this setting.
   <p>Note that annotation-driven configuration will still access non-public
   * members as far as they have been annotated. This setting applies to
   * externalized metadata in this bean definition only.
   */
  public void setNonPublicAccessAllowed(boolean nonPublicAccessAllowed) {
    this.nonPublicAccessAllowed = nonPublicAccessAllowed;
  }

  /**
   * Return whether to allow access to non-public constructors and methods.
   */
  public boolean isNonPublicAccessAllowed() {
    return this.nonPublicAccessAllowed;
  }

  /**
   * Specify whether to resolve constructors in lenient mode (<code>true</code>,
   * which is the default) or to switch to strict resolution (throwing an exception
   * in case of ambigious constructors that all match when converting the arguments,
   * whereas lenient mode would use the one with the 'closest' type matches).
   */
  public void setLenientConstructorResolution(boolean lenientConstructorResolution) {
    this.lenientConstructorResolution = lenientConstructorResolution;
  }

  /**
   * Return whether to resolve constructors in lenient mode or in strict mode.
   */
  public boolean isLenientConstructorResolution() {
    return this.lenientConstructorResolution;
  }

  /**
   * Specify constructor argument values for this bean.
   */
  public void setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) {
    this.constructorArgumentValues =
        (constructorArgumentValues != null ? constructorArgumentValues : new ConstructorArgumentValues());
  }

  /**
   * Return constructor argument values for this bean (never <code>null</code>).
   */
  public ConstructorArgumentValues getConstructorArgumentValues() {
    return this.constructorArgumentValues;
  }

  /**
   * Return if there are constructor argument values defined for this bean.
   */
  public boolean hasConstructorArgumentValues() {
    return !this.constructorArgumentValues.isEmpty();
  }

  /**
   * Specify property values for this bean, if any.
   */
  public void setPropertyValues(MutablePropertyValues propertyValues) {
    this.propertyValues = (propertyValues != null ? propertyValues : new MutablePropertyValues());
  }

  /**
   * Return property values for this bean (never <code>null</code>).
   */
  public MutablePropertyValues getPropertyValues() {
    return this.propertyValues;
  }

  /**
   * Specify method overrides for the bean, if any.
   */
  public void setMethodOverrides(MethodOverrides methodOverrides) {
    this.methodOverrides = (methodOverrides != null ? methodOverrides : new MethodOverrides());
  }

  /**
   * Return information about methods to be overridden by the IoC
   * container. This will be empty if there are no method overrides.
   * Never returns null.
   */
  public MethodOverrides getMethodOverrides() {
    return this.methodOverrides;
  }


  public void setFactoryBeanName(String factoryBeanName) {
    this.factoryBeanName = factoryBeanName;
  }

  public String getFactoryBeanName() {
    return this.factoryBeanName;
  }

  public void setFactoryMethodName(String factoryMethodName) {
    this.factoryMethodName = factoryMethodName;
  }

  public String getFactoryMethodName() {
    return this.factoryMethodName;
  }

  /**
   * Set the name of the initializer method. The default is <code>null</code>
   * in which case there is no initializer method.
   */
  public void setInitMethodName(String initMethodName) {
    this.initMethodName = initMethodName;
  }

  /**
   * Return the name of the initializer method.
   */
  public String getInitMethodName() {
    return this.initMethodName;
  }

  /**
   * Specify whether or not the configured init method is the default.
   * Default value is <code>false</code>.
   @see #setInitMethodName
   */
  public void setEnforceInitMethod(boolean enforceInitMethod) {
    this.enforceInitMethod = enforceInitMethod;
  }

  /**
   * Indicate whether the configured init method is the default.
   @see #getInitMethodName()
   */
  public boolean isEnforceInitMethod() {
    return this.enforceInitMethod;
  }

  /**
   * Set the name of the destroy method. The default is <code>null</code>
   * in which case there is no destroy method.
   */
  public void setDestroyMethodName(String destroyMethodName) {
    this.destroyMethodName = destroyMethodName;
  }

  /**
   * Return the name of the destroy method.
   */
  public String getDestroyMethodName() {
    return this.destroyMethodName;
  }

  /**
   * Specify whether or not the configured destroy method is the default.
   * Default value is <code>false</code>.
   @see #setDestroyMethodName
   */
  public void setEnforceDestroyMethod(boolean enforceDestroyMethod) {
    this.enforceDestroyMethod = enforceDestroyMethod;
  }

  /**
   * Indicate whether the configured destroy method is the default.
   @see #getDestroyMethodName
   */
  public boolean isEnforceDestroyMethod() {
    return this.enforceDestroyMethod;
  }


  /**
   * Set whether this bean definition is 'synthetic', that is, not defined
   * by the application itself (for example, an infrastructure bean such
   * as a helper for auto-proxying, created through <code>&ltaop:config&gt;</code>).
   */
  public void setSynthetic(boolean synthetic) {
    this.synthetic = synthetic;
  }

  /**
   * Return whether this bean definition is 'synthetic', that is,
   * not defined by the application itself.
   */
  public boolean isSynthetic() {
    return this.synthetic;
  }

  /**
   * Set the role hint for this <code>BeanDefinition</code>.
   */
  public void setRole(int role) {
    this.role = role;
  }

  /**
   * Return the role hint for this <code>BeanDefinition</code>.
   */
  public int getRole() {
    return this.role;
  }


  /**
   * Set a human-readable description of this bean definition.
   */
  public void setDescription(String description) {
    this.description = description;
  }

  public String getDescription() {
    return this.description;
  }

  /**
   * Set the resource that this bean definition came from
   * (for the purpose of showing context in case of errors).
   */
  public void setResource(Resource resource) {
    this.resource = resource;
  }

  /**
   * Return the resource that this bean definition came from.
   */
  public Resource getResource() {
    return this.resource;
  }

  /**
   * Set a description of the resource that this bean definition
   * came from (for the purpose of showing context in case of errors).
   */
  public void setResourceDescription(String resourceDescription) {
    this.resource = new DescriptiveResource(resourceDescription);
  }

  public String getResourceDescription() {
    return (this.resource != null this.resource.getDescription() null);
  }

  /**
   * Set the originating (e.g. decorated) BeanDefinition, if any.
   */
  public void setOriginatingBeanDefinition(BeanDefinition originatingBd) {
    this.resource = new BeanDefinitionResource(originatingBd);
  }

  public BeanDefinition getOriginatingBeanDefinition() {
    return (this.resource instanceof BeanDefinitionResource ?
        ((BeanDefinitionResourcethis.resource).getBeanDefinition() null);
  }

  /**
   * Validate this bean definition.
   @throws BeanDefinitionValidationException in case of validation failure
   */
  public void validate() throws BeanDefinitionValidationException {
    if (!getMethodOverrides().isEmpty() && getFactoryMethodName() != null) {
      throw new BeanDefinitionValidationException(
          "Cannot combine static factory method with method overrides: " +
          "the static factory method must create the instance");
    }

    if (hasBeanClass()) {
      prepareMethodOverrides();
    }
  }

  /**
   * Validate and prepare the method overrides defined for this bean.
   * Checks for existence of a method with the specified name.
   @throws BeanDefinitionValidationException in case of validation failure
   */
  public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exists.
    MethodOverrides methodOverrides = getMethodOverrides();
    if (!methodOverrides.isEmpty()) {
      for (MethodOverride mo : methodOverrides.getOverrides()) {
        prepareMethodOverride(mo);
      }
    }
  }

  /**
   * Validate and prepare the given method override.
   * Checks for existence of a method with the specified name,
   * marking it as not overloaded if none found.
   @param mo the MethodOverride object to validate
   @throws BeanDefinitionValidationException in case of validation failure
   */
  protected void prepareMethodOverride(MethodOverride mothrows BeanDefinitionValidationException {
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    if (count == 0) {
      throw new BeanDefinitionValidationException(
          "Invalid method override: no method with name '" + mo.getMethodName() +
          "' on class [" + getBeanClassName() "]");
    }
    else if (count == 1) {
      // Mark override as not overloaded, to avoid the overhead of arg type checking.
      mo.setOverloaded(false);
    }
  }


  /**
   * Public declaration of Object's <code>clone()</code> method.
   * Delegates to {@link #cloneBeanDefinition()}.
   @see java.lang.Object#clone()
   */
  @Override
  public Object clone() {
    return cloneBeanDefinition();
  }

  /**
   * Clone this bean definition.
   * To be implemented by concrete subclasses.
   @return the cloned bean definition object
   */
  public abstract AbstractBeanDefinition cloneBeanDefinition();


  @Override
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    }
    if (!(other instanceof AbstractBeanDefinition)) {
      return false;
    }

    AbstractBeanDefinition that = (AbstractBeanDefinitionother;

    if (!ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName())) return false;
    if (!ObjectUtils.nullSafeEquals(this.scope, that.scope)) return false;
    if (this.abstractFlag != that.abstractFlagreturn false;
    if (this.lazyInit != that.lazyInitreturn false;

    if (this.autowireMode != that.autowireModereturn false;
    if (this.dependencyCheck != that.dependencyCheckreturn false;
    if (!Arrays.equals(this.dependsOn, that.dependsOn)) return false;
    if (this.autowireCandidate != that.autowireCandidatereturn false;
    if (!ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers)) return false;
    if (this.primary != that.primaryreturn false;

    if (this.nonPublicAccessAllowed != that.nonPublicAccessAllowedreturn false;
    if (this.lenientConstructorResolution != that.lenientConstructorResolutionreturn false;
    if (!ObjectUtils.nullSafeEquals(this.constructorArgumentValues, that.constructorArgumentValues)) return false;
    if (!ObjectUtils.nullSafeEquals(this.propertyValues, that.propertyValues)) return false;
    if (!ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides)) return false;

    if (!ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName)) return false;
    if (!ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName)) return false;
    if (!ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName)) return false;
    if (this.enforceInitMethod != that.enforceInitMethodreturn false;
    if (!ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName)) return false;
    if (this.enforceDestroyMethod != that.enforceDestroyMethodreturn false;

    if (this.synthetic != that.syntheticreturn false;
    if (this.role != that.rolereturn false;

    return super.equals(other);
  }

  @Override
  public int hashCode() {
    int hashCode = ObjectUtils.nullSafeHashCode(getBeanClassName());
    hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.scope);
    hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.constructorArgumentValues);
    hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.propertyValues);
    hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryBeanName);
    hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.factoryMethodName);
    hashCode = 29 * hashCode + super.hashCode();
    return hashCode;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder("class [");
    sb.append(getBeanClassName()).append("]");
    sb.append("; scope=").append(this.scope);
    sb.append("; abstract=").append(this.abstractFlag);
    sb.append("; lazyInit=").append(this.lazyInit);
    sb.append("; autowireMode=").append(this.autowireMode);
    sb.append("; dependencyCheck=").append(this.dependencyCheck);
    sb.append("; autowireCandidate=").append(this.autowireCandidate);
    sb.append("; primary=").append(this.primary);
    sb.append("; factoryBeanName=").append(this.factoryBeanName);
    sb.append("; factoryMethodName=").append(this.factoryMethodName);
    sb.append("; initMethodName=").append(this.initMethodName);
    sb.append("; destroyMethodName=").append(this.destroyMethodName);
    if (this.resource != null) {
      sb.append("; defined in ").append(this.resource.getDescription());
    }
    return sb.toString();
  }

}