From 7eabd2da563a4e95928e89f72f7a207804eef0ab Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 16 Jul 2009 15:52:27 +0000 Subject: [PATCH] introduced "nonPublicAccessAllowed" flag (SPR-5882) --- .../org/springframework/beans/BeanUtils.java | 10 +-- .../AbstractAutowireCapableBeanFactory.java | 21 ++++--- .../support/AbstractBeanDefinition.java | 63 +++++++++++++------ .../factory/support/ConstructorResolver.java | 6 +- .../support/DisposableBeanAdapter.java | 25 ++++---- 5 files changed, 80 insertions(+), 45 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/BeanUtils.java b/org.springframework.beans/src/main/java/org/springframework/beans/BeanUtils.java index e13ae5fdbe5..2e4bbc6c57a 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -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. *

Checks Class.getMethods first, falling back to - * findDeclaredMethodWithMinimalParameters. This allows to find public + * findDeclaredMethodWithMinimalParameters. 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; diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index c7e5f8b15d7..947521f8349 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -1388,10 +1388,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac ((InitializingBean) bean).afterPropertiesSet(); } - String initMethodName = (mbd != null ? mbd.getInitMethodName() : null); - if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && - !mbd.isExternallyManagedInitMethod(initMethodName)) { - invokeCustomInitMethod(beanName, bean, initMethodName, mbd.isEnforceInitMethod()); + if (mbd != null) { + String initMethodName = mbd.getInitMethodName(); + if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && + !mbd.isExternallyManagedInitMethod(initMethodName)) { + 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 + "'"); } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java index 0dc8f487091..9f28b41d17e 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java @@ -141,10 +141,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private final Map qualifiers = new LinkedHashMap(); - 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. + *

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 (true, + * 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 (true, - * 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; diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index 6972e847b79..63462f3f477 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -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 candidateSet = new ArrayList(); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java index e8b8d5d99ab..9d2a42c0a6f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java @@ -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 null) - * @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 (null if there is none) - * @param postProcessors the List of DestructionAwareBeanPostProcessors, if any */ private DisposableBeanAdapter(Object bean, String beanName, boolean invokeDisposableBean, - String destroyMethodName, List postProcessors) { + boolean nonPublicAccessAllowed, String destroyMethodName, + List 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); } }