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

View File

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

View File

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

View File

@ -142,7 +142,8 @@ class ConstructorResolver {
if (candidates == null) { if (candidates == null) {
Class beanClass = mbd.getBeanClass(); Class beanClass = mbd.getBeanClass();
try { try {
candidates = beanClass.getDeclaredConstructors(); candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
} }
catch (Throwable ex) { catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, throw new BeanCreationException(mbd.getResourceDescription(), beanName,
@ -354,7 +355,8 @@ class ConstructorResolver {
// Need to determine the factory method... // Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments. // Try all methods with this name to see if they match the given arguments.
factoryClass = ClassUtils.getUserClass(factoryClass); factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] rawCandidates = ReflectionUtils.getAllDeclaredMethods(factoryClass); Method[] rawCandidates = (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
List<Method> candidateSet = new ArrayList<Method>(); List<Method> candidateSet = new ArrayList<Method>();
for (Method candidate : rawCandidates) { for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && 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 invokeDisposableBean;
private final boolean nonPublicAccessAllowed;
private String destroyMethodName; private String destroyMethodName;
private transient Method destroyMethod; private transient Method destroyMethod;
@ -81,12 +83,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.beanName = beanName; this.beanName = beanName;
this.invokeDisposableBean = this.invokeDisposableBean =
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy")); (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
String destroyMethodName = beanDefinition.getDestroyMethodName(); String destroyMethodName = beanDefinition.getDestroyMethodName();
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
this.destroyMethodName = destroyMethodName; this.destroyMethodName = destroyMethodName;
try { 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) { catch (IllegalArgumentException ex) {
throw new BeanDefinitionValidationException("Couldn't find a unique destroy method on bean with name '" + 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. * 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, private DisposableBeanAdapter(Object bean, String beanName, boolean invokeDisposableBean,
String destroyMethodName, List<DestructionAwareBeanPostProcessor> postProcessors) { boolean nonPublicAccessAllowed, String destroyMethodName,
List<DestructionAwareBeanPostProcessor> postProcessors) {
this.bean = bean; this.bean = bean;
this.beanName = beanName; this.beanName = beanName;
this.invokeDisposableBean = invokeDisposableBean; this.invokeDisposableBean = invokeDisposableBean;
this.nonPublicAccessAllowed = nonPublicAccessAllowed;
this.destroyMethodName = destroyMethodName; this.destroyMethodName = destroyMethodName;
this.beanPostProcessors = postProcessors; this.beanPostProcessors = postProcessors;
} }
@ -184,9 +186,10 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
invokeCustomDestroyMethod(this.destroyMethod); invokeCustomDestroyMethod(this.destroyMethod);
} }
else if (this.destroyMethodName != null) { else if (this.destroyMethodName != null) {
Method destroyMethod = this.destroyMethod = (this.nonPublicAccessAllowed ?
BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), this.destroyMethodName); BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), this.destroyMethodName) :
invokeCustomDestroyMethod(destroyMethod); 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, return new DisposableBeanAdapter(this.bean, this.beanName, this.invokeDisposableBean,
this.destroyMethodName, serializablePostProcessors); this.nonPublicAccessAllowed, this.destroyMethodName, serializablePostProcessors);
} }
} }