org.springframework.beans.factory.support.AbstractBeanDefinition Maven / Gradle / Ivy
/*
* Copyright 2002-2019 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
*
* https://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 BeanDefinition} classes,
* factoring out common properties of {@link GenericBeanDefinition},
* {@link RootBeanDefinition}, and {@link ChildBeanDefinition}.
*
* 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 GenericBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
@SuppressWarnings("serial")
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
/**
* Constant for the default scope name: {@code ""}, equivalent to singleton
* status unless 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;
/**
* Constant that indicates the container should attempt to infer the
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
* explicit specification of a method name. The value {@value} is specifically
* designed to include characters otherwise illegal in a method name, ensuring
* no possibility of collisions with legitimately named methods having the same
* name.
*
Currently, the method names detected during destroy method inference
* are "close" and "shutdown", if present on the specific bean class.
*/
public static final String INFER_METHOD = "(inferred)";
private volatile Object beanClass;
private String scope = SCOPE_DEFAULT;
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 qualifiers =
new LinkedHashMap(0);
private boolean nonPublicAccessAllowed = true;
private boolean lenientConstructorResolution = true;
private String factoryBeanName;
private String factoryMethodName;
private ConstructorArgumentValues constructorArgumentValues;
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides = new MethodOverrides();
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 a 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());
setScope(original.getScope());
setAbstract(original.isAbstract());
setLazyInit(original.isLazyInit());
setFactoryBeanName(original.getFactoryBeanName());
setFactoryMethodName(original.getFactoryMethodName());
setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
setRole(original.getRole());
setSource(original.getSource());
copyAttributesFrom(original);
if (original instanceof AbstractBeanDefinition) {
AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original;
if (originalAbd.hasBeanClass()) {
setBeanClass(originalAbd.getBeanClass());
}
setAutowireMode(originalAbd.getAutowireMode());
setDependencyCheck(originalAbd.getDependencyCheck());
setDependsOn(originalAbd.getDependsOn());
setAutowireCandidate(originalAbd.isAutowireCandidate());
setPrimary(originalAbd.isPrimary());
copyQualifiersFrom(originalAbd);
setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
setInitMethodName(originalAbd.getInitMethodName());
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
setDestroyMethodName(originalAbd.getDestroyMethodName());
setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
setSynthetic(originalAbd.isSynthetic());
setResource(originalAbd.getResource());
}
else {
setResourceDescription(original.getResourceDescription());
}
}
/**
* Override settings in this bean definition (presumably a copied parent
* from a parent-child inheritance relationship) from the given bean
* definition (presumably the child).
*
* - Will override beanClass if specified in the given bean definition.
*
- Will always take {@code abstract}, {@code scope},
* {@code lazyInit}, {@code autowireMode}, {@code dependencyCheck},
* and {@code dependsOn} from the given bean definition.
*
- Will add {@code constructorArgumentValues}, {@code propertyValues},
* {@code methodOverrides} from the given bean definition to existing ones.
*
- Will override {@code factoryBeanName}, {@code factoryMethodName},
* {@code initMethodName}, and {@code destroyMethodName} if specified
* in the given bean definition.
*
*/
public void overrideFrom(BeanDefinition other) {
if (StringUtils.hasLength(other.getBeanClassName())) {
setBeanClassName(other.getBeanClassName());
}
if (StringUtils.hasLength(other.getScope())) {
setScope(other.getScope());
}
setAbstract(other.isAbstract());
setLazyInit(other.isLazyInit());
if (StringUtils.hasLength(other.getFactoryBeanName())) {
setFactoryBeanName(other.getFactoryBeanName());
}
if (StringUtils.hasLength(other.getFactoryMethodName())) {
setFactoryMethodName(other.getFactoryMethodName());
}
getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
getPropertyValues().addPropertyValues(other.getPropertyValues());
setRole(other.getRole());
setSource(other.getSource());
copyAttributesFrom(other);
if (other instanceof AbstractBeanDefinition) {
AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other;
if (otherAbd.hasBeanClass()) {
setBeanClass(otherAbd.getBeanClass());
}
setAutowireMode(otherAbd.getAutowireMode());
setDependencyCheck(otherAbd.getDependencyCheck());
setDependsOn(otherAbd.getDependsOn());
setAutowireCandidate(otherAbd.isAutowireCandidate());
setPrimary(otherAbd.isPrimary());
copyQualifiersFrom(otherAbd);
setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
if (StringUtils.hasLength(otherAbd.getInitMethodName())) {
setInitMethodName(otherAbd.getInitMethodName());
setEnforceInitMethod(otherAbd.isEnforceInitMethod());
}
if (otherAbd.getDestroyMethodName() != null) {
setDestroyMethodName(otherAbd.getDestroyMethodName());
setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
}
setSynthetic(otherAbd.isSynthetic());
setResource(otherAbd.getResource());
}
else {
setResourceDescription(other.getResourceDescription());
}
}
/**
* Apply the provided default values to this bean.
* @param defaults the default settings to apply
* @since 2.5
*/
public void applyDefaults(BeanDefinitionDefaults defaults) {
setLazyInit(defaults.isLazyInit());
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
/**
* Specify the bean class name of this bean definition.
*/
@Override
public void setBeanClassName(String beanClassName) {
this.beanClass = beanClassName;
}
/**
* Return the current bean class name of this bean definition.
*/
@Override
public String getBeanClassName() {
Object beanClassObject = this.beanClass;
if (beanClassObject instanceof Class) {
return ((Class) beanClassObject).getName();
}
else {
return (String) beanClassObject;
}
}
/**
* 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} 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 (Class) beanClassObject;
}
/**
* Return whether this definition specifies a bean class.
*/
public boolean hasBeanClass() {
return (this.beanClass instanceof Class);
}
/**
* 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 classLoader) throws 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.
* The 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 definition.
* For this reason, the default scope name is an empty string (i.e., {@code ""}),
* with singleton status being assumed until a resolved scope is set.
* @see #SCOPE_SINGLETON
* @see #SCOPE_PROTOTYPE
*/
@Override
public void setScope(String scope) {
this.scope = scope;
}
/**
* Return the name of the target scope for the bean.
*/
@Override
public String getScope() {
return this.scope;
}
/**
* Return whether this a Singleton, with a single shared instance
* returned from all calls.
* @see #SCOPE_SINGLETON
*/
@Override
public boolean isSingleton() {
return SCOPE_SINGLETON.equals(this.scope) || SCOPE_DEFAULT.equals(this.scope);
}
/**
* Return whether this a Prototype, with an independent instance
* returned for each call.
* @see #SCOPE_PROTOTYPE
*/
@Override
public boolean isPrototype() {
return SCOPE_PROTOTYPE.equals(this.scope);
}
/**
* 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.
*
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.
*/
@Override
public boolean isAbstract() {
return this.abstractFlag;
}
/**
* Set whether this bean should be lazily initialized.
*
If {@code false}, the bean will get instantiated on startup by bean
* factories that perform eager initialization of singletons.
*/
@Override
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.
* @return whether to apply lazy-init semantics ({@code false} by default)
*/
@Override
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 won't be convention-based autowiring by name or type
* (however, there may still be explicit annotation-driven autowiring).
* @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.
*
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.
*/
@Override
public void setDependsOn(String... dependsOn) {
this.dependsOn = dependsOn;
}
/**
* Return the bean names that this bean depends on.
*/
@Override
public String[] getDependsOn() {
return this.dependsOn;
}
/**
* Set whether this bean is a candidate for getting autowired into some other bean.
*
Note that this flag is designed to only affect type-based autowiring.
* It does not affect explicit references by name, which will get resolved even
* if the specified bean is not marked as an autowire candidate. As a consequence,
* autowiring by name will nevertheless inject a bean if the name matches.
* @see #AUTOWIRE_BY_TYPE
* @see #AUTOWIRE_BY_NAME
*/
@Override
public void setAutowireCandidate(boolean autowireCandidate) {
this.autowireCandidate = autowireCandidate;
}
/**
* Return whether this bean is a candidate for getting autowired into some other bean.
*/
@Override
public boolean isAutowireCandidate() {
return this.autowireCandidate;
}
/**
* Set whether this bean is a primary autowire candidate.
*
If this value is {@code true} for exactly one bean among multiple
* matching candidates, it will serve as a tie-breaker.
*/
@Override
public void setPrimary(boolean primary) {
this.primary = primary;
}
/**
* Return whether this bean is a primary autowire candidate.
*/
@Override
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.containsKey(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 getQualifiers() {
return new LinkedHashSet(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. The default is
* {@code true}; switch this to {@code false} for public access only.
* 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.
*
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},
* which is the default) or to switch to strict resolution (throwing an exception
* in case of ambiguous 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 the factory bean to use, if any.
* This the name of the bean to call the specified factory method on.
* @see #setFactoryMethodName
*/
@Override
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
/**
* Return the factory bean name, if any.
*/
@Override
public String getFactoryBeanName() {
return this.factoryBeanName;
}
/**
* Specify a factory method, if any. This method will be invoked with
* constructor arguments, or with no arguments if none are specified.
* The method will be invoked on the specified factory bean, if any,
* or otherwise as a static method on the local bean class.
* @see #setFactoryBeanName
* @see #setBeanClassName
*/
@Override
public void setFactoryMethodName(String factoryMethodName) {
this.factoryMethodName = factoryMethodName;
}
/**
* Return a factory method, if any.
*/
@Override
public String getFactoryMethodName() {
return this.factoryMethodName;
}
/**
* 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}).
*/
@Override
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}).
*/
@Override
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 {@code null}.
*/
public MethodOverrides getMethodOverrides() {
return this.methodOverrides;
}
/**
* Set the name of the initializer method.
*
The default is {@code null} 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.
*
The default value is {@code false}.
* @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} 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.
*
The default value is {@code false}.
* @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 }).
*/
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}.
*/
public void setRole(int role) {
this.role = role;
}
/**
* Return the role hint for this {@code BeanDefinition}.
*/
@Override
public int getRole() {
return this.role;
}
/**
* Set a human-readable description of this bean definition.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Return a human-readable description of this bean definition.
*/
@Override
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);
}
/**
* Return a description of the resource that this bean definition
* came from (for the purpose of showing context in case of errors).
*/
@Override
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);
}
/**
* Return the originating BeanDefinition, or {@code null} if none.
* Allows for retrieving the decorated bean definition, if any.
* Note that this method returns the immediate originator. Iterate through the
* originator chain to find the original BeanDefinition as defined by the user.
*/
@Override
public BeanDefinition getOriginatingBeanDefinition() {
return (this.resource instanceof BeanDefinitionResource ?
((BeanDefinitionResource) this.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()) {
Set overrides = methodOverrides.getOverrides();
synchronized (overrides) {
for (MethodOverride mo : overrides) {
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 mo) throws 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()} method.
* Delegates to {@link #cloneBeanDefinition()}.
* @see 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 = (AbstractBeanDefinition) other;
if (!ObjectUtils.nullSafeEquals(getBeanClassName(), that.getBeanClassName())) return false;
if (!ObjectUtils.nullSafeEquals(this.scope, that.scope)) return false;
if (this.abstractFlag != that.abstractFlag) return false;
if (this.lazyInit != that.lazyInit) return false;
if (this.autowireMode != that.autowireMode) return false;
if (this.dependencyCheck != that.dependencyCheck) return false;
if (!Arrays.equals(this.dependsOn, that.dependsOn)) return false;
if (this.autowireCandidate != that.autowireCandidate) return false;
if (!ObjectUtils.nullSafeEquals(this.qualifiers, that.qualifiers)) return false;
if (this.primary != that.primary) return false;
if (this.nonPublicAccessAllowed != that.nonPublicAccessAllowed) return false;
if (this.lenientConstructorResolution != that.lenientConstructorResolution) return 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.enforceInitMethod) return false;
if (!ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName)) return false;
if (this.enforceDestroyMethod != that.enforceDestroyMethod) return false;
if (this.synthetic != that.synthetic) return false;
if (this.role != that.role) return 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();
}
}