resolveFactoryMethodIfPossible considers nonPublicAccessAllowed and SecurityManager
Issue: SPR-11422
(cherry picked from commit 603cdea)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -54,12 +54,9 @@ import org.springframework.util.ReflectionUtils;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for resolving constructors and factory methods.
|
* Delegate for resolving constructors and factory methods.
|
||||||
* Performs constructor resolution through argument matching.
|
* Performs constructor resolution through argument matching.
|
||||||
*
|
*
|
||||||
* <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
|
|
||||||
* Used by {@link AbstractAutowireCapableBeanFactory}.
|
|
||||||
*
|
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Rob Harrop
|
* @author Rob Harrop
|
||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
@@ -103,12 +100,12 @@ class ConstructorResolver {
|
|||||||
* @return a BeanWrapper for the new instance
|
* @return a BeanWrapper for the new instance
|
||||||
*/
|
*/
|
||||||
public BeanWrapper autowireConstructor(
|
public BeanWrapper autowireConstructor(
|
||||||
final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
|
final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) {
|
||||||
|
|
||||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||||
this.beanFactory.initBeanWrapper(bw);
|
this.beanFactory.initBeanWrapper(bw);
|
||||||
|
|
||||||
Constructor constructorToUse = null;
|
Constructor<?> constructorToUse = null;
|
||||||
ArgumentsHolder argsHolderToUse = null;
|
ArgumentsHolder argsHolderToUse = null;
|
||||||
Object[] argsToUse = null;
|
Object[] argsToUse = null;
|
||||||
|
|
||||||
@@ -118,7 +115,7 @@ class ConstructorResolver {
|
|||||||
else {
|
else {
|
||||||
Object[] argsToResolve = null;
|
Object[] argsToResolve = null;
|
||||||
synchronized (mbd.constructorArgumentLock) {
|
synchronized (mbd.constructorArgumentLock) {
|
||||||
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
|
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
|
||||||
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
|
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
|
||||||
// Found a cached constructor...
|
// Found a cached constructor...
|
||||||
argsToUse = mbd.resolvedConstructorArguments;
|
argsToUse = mbd.resolvedConstructorArguments;
|
||||||
@@ -149,7 +146,7 @@ class ConstructorResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Take specified constructors, if any.
|
// Take specified constructors, if any.
|
||||||
Constructor[] candidates = chosenCtors;
|
Constructor<?>[] candidates = chosenCtors;
|
||||||
if (candidates == null) {
|
if (candidates == null) {
|
||||||
Class<?> beanClass = mbd.getBeanClass();
|
Class<?> beanClass = mbd.getBeanClass();
|
||||||
try {
|
try {
|
||||||
@@ -164,7 +161,7 @@ class ConstructorResolver {
|
|||||||
}
|
}
|
||||||
AutowireUtils.sortConstructors(candidates);
|
AutowireUtils.sortConstructors(candidates);
|
||||||
int minTypeDiffWeight = Integer.MAX_VALUE;
|
int minTypeDiffWeight = Integer.MAX_VALUE;
|
||||||
Set<Constructor> ambiguousConstructors = null;
|
Set<Constructor<?>> ambiguousConstructors = null;
|
||||||
List<Exception> causes = null;
|
List<Exception> causes = null;
|
||||||
|
|
||||||
for (int i = 0; i < candidates.length; i++) {
|
for (int i = 0; i < candidates.length; i++) {
|
||||||
@@ -185,7 +182,7 @@ class ConstructorResolver {
|
|||||||
try {
|
try {
|
||||||
String[] paramNames = null;
|
String[] paramNames = null;
|
||||||
if (constructorPropertiesAnnotationAvailable) {
|
if (constructorPropertiesAnnotationAvailable) {
|
||||||
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
|
paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
|
||||||
}
|
}
|
||||||
if (paramNames == null) {
|
if (paramNames == null) {
|
||||||
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
|
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
|
||||||
@@ -239,7 +236,7 @@ class ConstructorResolver {
|
|||||||
}
|
}
|
||||||
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
|
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
|
||||||
if (ambiguousConstructors == null) {
|
if (ambiguousConstructors == null) {
|
||||||
ambiguousConstructors = new LinkedHashSet<Constructor>();
|
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
|
||||||
ambiguousConstructors.add(constructorToUse);
|
ambiguousConstructors.add(constructorToUse);
|
||||||
}
|
}
|
||||||
ambiguousConstructors.add(candidate);
|
ambiguousConstructors.add(candidate);
|
||||||
@@ -267,7 +264,7 @@ class ConstructorResolver {
|
|||||||
Object beanInstance;
|
Object beanInstance;
|
||||||
|
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
final Constructor ctorToUse = constructorToUse;
|
final Constructor<?> ctorToUse = constructorToUse;
|
||||||
final Object[] argumentsToUse = argsToUse;
|
final Object[] argumentsToUse = argsToUse;
|
||||||
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
public Object run() {
|
public Object run() {
|
||||||
@@ -295,18 +292,22 @@ class ConstructorResolver {
|
|||||||
* @param mbd the bean definition to check
|
* @param mbd the bean definition to check
|
||||||
*/
|
*/
|
||||||
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
|
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
|
||||||
Class factoryClass;
|
Class<?> factoryClass;
|
||||||
|
boolean isStatic;
|
||||||
if (mbd.getFactoryBeanName() != null) {
|
if (mbd.getFactoryBeanName() != null) {
|
||||||
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
|
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
|
||||||
|
isStatic = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
factoryClass = mbd.getBeanClass();
|
factoryClass = mbd.getBeanClass();
|
||||||
|
isStatic = true;
|
||||||
}
|
}
|
||||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||||
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
|
|
||||||
|
Method[] candidates = getCandidateMethods(factoryClass, mbd);
|
||||||
Method uniqueCandidate = null;
|
Method uniqueCandidate = null;
|
||||||
for (Method candidate : candidates) {
|
for (Method candidate : candidates) {
|
||||||
if (mbd.isFactoryMethod(candidate)) {
|
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
|
||||||
if (uniqueCandidate == null) {
|
if (uniqueCandidate == null) {
|
||||||
uniqueCandidate = candidate;
|
uniqueCandidate = candidate;
|
||||||
}
|
}
|
||||||
@@ -321,6 +322,27 @@ class ConstructorResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all candidate methods for the given class, considering
|
||||||
|
* the {@link RootBeanDefinition#isNonPublicAccessAllowed()} flag.
|
||||||
|
* Called as the starting point for factory method determination.
|
||||||
|
*/
|
||||||
|
private Method[] getCandidateMethods(final Class<?> factoryClass, final RootBeanDefinition mbd) {
|
||||||
|
if (System.getSecurityManager() != null) {
|
||||||
|
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||||
|
@Override
|
||||||
|
public Method[] run() {
|
||||||
|
return (mbd.isNonPublicAccessAllowed() ?
|
||||||
|
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (mbd.isNonPublicAccessAllowed() ?
|
||||||
|
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate the bean using a named factory method. The method may be static, if the
|
* Instantiate the bean using a named factory method. The method may be static, if the
|
||||||
* bean definition parameter specifies a class, rather than a "factory-bean", or
|
* bean definition parameter specifies a class, rather than a "factory-bean", or
|
||||||
@@ -336,7 +358,9 @@ class ConstructorResolver {
|
|||||||
* method, or {@code null} if none (-> use constructor argument values from bean definition)
|
* method, or {@code null} if none (-> use constructor argument values from bean definition)
|
||||||
* @return a BeanWrapper for the new instance
|
* @return a BeanWrapper for the new instance
|
||||||
*/
|
*/
|
||||||
public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
public BeanWrapper instantiateUsingFactoryMethod(
|
||||||
|
final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
|
||||||
|
|
||||||
BeanWrapperImpl bw = new BeanWrapperImpl();
|
BeanWrapperImpl bw = new BeanWrapperImpl();
|
||||||
this.beanFactory.initBeanWrapper(bw);
|
this.beanFactory.initBeanWrapper(bw);
|
||||||
|
|
||||||
@@ -397,27 +421,11 @@ 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;
|
|
||||||
|
|
||||||
final Class<?> factoryClazz = factoryClass;
|
|
||||||
if (System.getSecurityManager() != null) {
|
|
||||||
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
|
||||||
public Method[] run() {
|
|
||||||
return (mbd.isNonPublicAccessAllowed() ?
|
|
||||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rawCandidates = (mbd.isNonPublicAccessAllowed() ?
|
|
||||||
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
|
||||||
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 && mbd.isFactoryMethod(candidate)) {
|
||||||
candidate.getName().equals(mbd.getFactoryMethodName()) &&
|
|
||||||
mbd.isFactoryMethod(candidate)) {
|
|
||||||
candidateSet.add(candidate);
|
candidateSet.add(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -759,7 +767,7 @@ class ConstructorResolver {
|
|||||||
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
|
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
|
||||||
|
|
||||||
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
|
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
|
||||||
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
|
((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
|
||||||
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
||||||
this.beanFactory.getCustomTypeConverter() : bw);
|
this.beanFactory.getCustomTypeConverter() : bw);
|
||||||
BeanDefinitionValueResolver valueResolver =
|
BeanDefinitionValueResolver valueResolver =
|
||||||
@@ -881,7 +889,7 @@ class ConstructorResolver {
|
|||||||
*/
|
*/
|
||||||
private static class ConstructorPropertiesChecker {
|
private static class ConstructorPropertiesChecker {
|
||||||
|
|
||||||
public static String[] evaluateAnnotation(Constructor<?> candidate, int paramCount) {
|
public static String[] evaluate(Constructor<?> candidate, int paramCount) {
|
||||||
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
|
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
|
||||||
if (cp != null) {
|
if (cp != null) {
|
||||||
String[] names = cp.value();
|
String[] names = cp.value();
|
||||||
|
|||||||
Reference in New Issue
Block a user