introduced "nonPublicAccessAllowed" flag (SPR-5882)

This commit is contained in:
Juergen Hoeller 2009-07-16 15:52:27 +00:00
parent ba27c29dc4
commit 7eabd2da56
5 changed files with 80 additions and 45 deletions

View File

@ -158,7 +158,7 @@ public abstract class BeanUtils {
* @see java.lang.Class#getMethod
* @see #findDeclaredMethod
*/
public static Method findMethod(Class clazz, String methodName, Class[] paramTypes) {
public static Method findMethod(Class clazz, String methodName, Class... paramTypes) {
try {
return clazz.getMethod(methodName, paramTypes);
}
@ -195,7 +195,7 @@ public abstract class BeanUtils {
* declared on the given class or one of its superclasses. Prefers public methods,
* but will return a protected, package access, or private method too.
* <p>Checks <code>Class.getMethods</code> first, falling back to
* <code>findDeclaredMethodWithMinimalParameters</code>. This allows to find public
* <code>findDeclaredMethodWithMinimalParameters</code>. This allows for finding public
* methods without issues even in environments with restricted Java security settings.
* @param clazz the class to check
* @param methodName the name of the method to find
@ -208,7 +208,7 @@ public abstract class BeanUtils {
public static Method findMethodWithMinimalParameters(Class clazz, String methodName)
throws IllegalArgumentException {
Method targetMethod = doFindMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
if (targetMethod == null) {
targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
}
@ -230,7 +230,7 @@ public abstract class BeanUtils {
public static Method findDeclaredMethodWithMinimalParameters(Class clazz, String methodName)
throws IllegalArgumentException {
Method targetMethod = doFindMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
if (targetMethod == null && clazz.getSuperclass() != null) {
targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
}
@ -246,7 +246,7 @@ public abstract class BeanUtils {
* @throws IllegalArgumentException if methods of the given name were found but
* could not be resolved to a unique method with minimal parameters
*/
private static Method doFindMethodWithMinimalParameters(Method[] methods, String methodName)
public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)
throws IllegalArgumentException {
Method targetMethod = null;

View File

@ -1388,10 +1388,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
((InitializingBean) bean).afterPropertiesSet();
}
String initMethodName = (mbd != null ? mbd.getInitMethodName() : null);
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, initMethodName, mbd.isEnforceInitMethod());
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
@ -1406,12 +1408,13 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @param enforceInitMethod indicates whether the defined init method needs to exist
* @see #invokeInitMethods
*/
protected void invokeCustomInitMethod(
String beanName, Object bean, String initMethodName, boolean enforceInitMethod) throws Throwable {
Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd) throws Throwable {
String initMethodName = mbd.getInitMethodName();
Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
if (initMethod == null) {
if (enforceInitMethod) {
if (mbd.isEnforceInitMethod()) {
throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
initMethodName + "' on bean with name '" + beanName + "'");
}

View File

@ -141,10 +141,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
private final Map<String, AutowireCandidateQualifier> qualifiers =
new LinkedHashMap<String, AutowireCandidateQualifier>();
private ConstructorArgumentValues constructorArgumentValues;
private boolean nonPublicAccessAllowed = true;
private boolean lenientConstructorResolution = true;
private ConstructorArgumentValues constructorArgumentValues;
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides = new MethodOverrides();
@ -226,6 +228,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
setAutowireCandidate(originalAbd.isAutowireCandidate());
copyQualifiersFrom(originalAbd);
setPrimary(originalAbd.isPrimary());
setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
setInitMethodName(originalAbd.getInitMethodName());
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
@ -298,6 +301,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
setPrimary(otherAbd.isPrimary());
setDependencyCheck(otherAbd.getDependencyCheck());
setDependsOn(otherAbd.getDependsOn());
setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
if (otherAbd.getInitMethodName() != null) {
setInitMethodName(otherAbd.getInitMethodName());
@ -650,6 +654,44 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
}
/**
* 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.
*/
@ -672,23 +714,6 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
return !this.constructorArgumentValues.isEmpty();
}
/**
* 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 property values for this bean, if any.
*/
@ -976,6 +1001,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
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;

View File

@ -142,7 +142,8 @@ class ConstructorResolver {
if (candidates == null) {
Class beanClass = mbd.getBeanClass();
try {
candidates = beanClass.getDeclaredConstructors();
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
@ -354,7 +355,8 @@ class ConstructorResolver {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] rawCandidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
Method[] rawCandidates = (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
List<Method> candidateSet = new ArrayList<Method>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&

View File

@ -58,6 +58,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private final boolean invokeDisposableBean;
private final boolean nonPublicAccessAllowed;
private String destroyMethodName;
private transient Method destroyMethod;
@ -81,12 +83,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.beanName = beanName;
this.invokeDisposableBean =
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
String destroyMethodName = beanDefinition.getDestroyMethodName();
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
this.destroyMethodName = destroyMethodName;
try {
this.destroyMethod = BeanUtils.findMethodWithMinimalParameters(bean.getClass(), destroyMethodName);
this.destroyMethod = (this.nonPublicAccessAllowed ?
BeanUtils.findMethodWithMinimalParameters(bean.getClass(), destroyMethodName) :
BeanUtils.findMethodWithMinimalParameters(bean.getClass().getMethods(), destroyMethodName));
}
catch (IllegalArgumentException ex) {
throw new BeanDefinitionValidationException("Couldn't find a unique destroy method on bean with name '" +
@ -115,18 +120,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
/**
* Create a new DisposableBeanAdapter for the given bean.
* @param bean the bean instance (never <code>null</code>)
* @param beanName the name of the bean
* @param invokeDisposableBean whether to actually invoke DisposableBean's destroy method here
* @param destroyMethodName the name of the custom destroy method (<code>null</code> if there is none)
* @param postProcessors the List of DestructionAwareBeanPostProcessors, if any
*/
private DisposableBeanAdapter(Object bean, String beanName, boolean invokeDisposableBean,
String destroyMethodName, List<DestructionAwareBeanPostProcessor> postProcessors) {
boolean nonPublicAccessAllowed, String destroyMethodName,
List<DestructionAwareBeanPostProcessor> postProcessors) {
this.bean = bean;
this.beanName = beanName;
this.invokeDisposableBean = invokeDisposableBean;
this.nonPublicAccessAllowed = nonPublicAccessAllowed;
this.destroyMethodName = destroyMethodName;
this.beanPostProcessors = postProcessors;
}
@ -184,9 +186,10 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method destroyMethod =
BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), this.destroyMethodName);
invokeCustomDestroyMethod(destroyMethod);
this.destroyMethod = (this.nonPublicAccessAllowed ?
BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), this.destroyMethodName) :
BeanUtils.findMethodWithMinimalParameters(this.bean.getClass().getMethods(), this.destroyMethodName));
invokeCustomDestroyMethod(this.destroyMethod);
}
}
@ -242,7 +245,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
return new DisposableBeanAdapter(this.bean, this.beanName, this.invokeDisposableBean,
this.destroyMethodName, serializablePostProcessors);
this.nonPublicAccessAllowed, this.destroyMethodName, serializablePostProcessors);
}
}