Consistent throwing of BeanCreationExceptions (and reflection exceptions)
Issue: SPR-14883
This commit is contained in:
parent
fd7045adac
commit
b42d731fc8
|
@ -220,7 +220,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalArgumentException(
|
||||
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
|
||||
|
@ -238,7 +238,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeansException {
|
||||
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
|
||||
throws BeanCreationException {
|
||||
|
||||
// Let's check for lookup methods here..
|
||||
if (!this.lookupMethodsChecked.contains(beanName)) {
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
|
@ -263,10 +266,19 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
// Quick check on the concurrent map first, with minimal locking.
|
||||
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
// Fully synchronized resolution now...
|
||||
synchronized (this.candidateConstructorsCache) {
|
||||
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
|
||||
if (candidateConstructors == null) {
|
||||
Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();
|
||||
Constructor<?>[] rawCandidates;
|
||||
try {
|
||||
rawCandidates = beanClass.getDeclaredConstructors();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
|
||||
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
|
||||
}
|
||||
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
|
||||
Constructor<?> requiredConstructor = null;
|
||||
Constructor<?> defaultConstructor = null;
|
||||
|
@ -320,9 +332,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
}
|
||||
else if (candidates.size() == 1 && logger.isWarnEnabled()) {
|
||||
logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +
|
||||
"': single autowire-marked constructor flagged as optional - this constructor " +
|
||||
"is effectively required since there is no default constructor to fall back to: " +
|
||||
candidates.get(0));
|
||||
"': single autowire-marked constructor flagged as optional - " +
|
||||
"this constructor is effectively required since there is no " +
|
||||
"default constructor to fall back to: " + candidates.get(0));
|
||||
}
|
||||
}
|
||||
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
|
||||
|
@ -342,7 +354,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
|
||||
|
||||
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
|
||||
try {
|
||||
|
@ -361,9 +373,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
* 'Native' processing method for direct calls with an arbitrary target instance,
|
||||
* resolving all of its fields and methods which are annotated with {@code @Autowired}.
|
||||
* @param bean the target instance to process
|
||||
* @throws BeansException if autowiring failed
|
||||
* @throws BeanCreationException if autowiring failed
|
||||
*/
|
||||
public void processInjection(Object bean) throws BeansException {
|
||||
public void processInjection(Object bean) throws BeanCreationException {
|
||||
Class<?> clazz = bean.getClass();
|
||||
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
|
||||
try {
|
||||
|
@ -373,7 +385,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||
throw new BeanCreationException(
|
||||
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,7 +459,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
}
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation should be used on methods with parameters: " + method);
|
||||
logger.warn("Autowired annotation should only be used on methods with parameters: " +
|
||||
method);
|
||||
}
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
|
@ -629,7 +643,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
arguments = new Object[paramTypes.length];
|
||||
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
|
||||
Set<String> autowiredBeans = new LinkedHashSet<String>(paramTypes.length);
|
||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(method, i);
|
||||
|
@ -637,7 +651,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
currDesc.setContainingClass(bean.getClass());
|
||||
descriptors[i] = currDesc;
|
||||
try {
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
|
||||
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
|
||||
if (arg == null && !this.required) {
|
||||
arguments = null;
|
||||
break;
|
||||
|
@ -655,9 +669,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
for (int i = 0; i < arguments.length; i++) {
|
||||
this.cachedMethodArguments[i] = descriptors[i];
|
||||
}
|
||||
registerDependentBeans(beanName, autowiredBeanNames);
|
||||
if (autowiredBeanNames.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeanNames.iterator();
|
||||
registerDependentBeans(beanName, autowiredBeans);
|
||||
if (autowiredBeans.size() == paramTypes.length) {
|
||||
Iterator<String> it = autowiredBeans.iterator();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String autowiredBeanName = it.next();
|
||||
if (beanFactory.containsBean(autowiredBeanName)) {
|
||||
|
@ -706,19 +720,19 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
@SuppressWarnings("serial")
|
||||
private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
|
||||
|
||||
private final String shortcutName;
|
||||
private final String shortcut;
|
||||
|
||||
private final Class<?> requiredType;
|
||||
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcutName, Class<?> requiredType) {
|
||||
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
|
||||
super(original);
|
||||
this.shortcutName = shortcutName;
|
||||
this.shortcut = shortcut;
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveShortcut(BeanFactory beanFactory) {
|
||||
return resolveCandidate(this.shortcutName, this.requiredType, beanFactory);
|
||||
return resolveCandidate(this.shortcut, this.requiredType, beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
@ -141,8 +141,7 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
|||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (!this.validatedBeanNames.contains(beanName)) {
|
||||
if (!shouldSkip(this.beanFactory, beanName)) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
@ -66,8 +66,7 @@ public abstract class InstantiationAwareBeanPostProcessorAdapter implements Smar
|
|||
|
||||
@Override
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
|
||||
throws BeansException {
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
return pvs;
|
||||
}
|
||||
|
|
|
@ -479,11 +479,21 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
"BeanPostProcessor before instantiation of bean failed", ex);
|
||||
}
|
||||
|
||||
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Finished creating instance of bean '" + beanName + "'");
|
||||
try {
|
||||
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Finished creating instance of bean '" + beanName + "'");
|
||||
}
|
||||
return beanInstance;
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// A previously detected exception with proper bean creation context already...
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(
|
||||
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
|
||||
}
|
||||
return beanInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -500,7 +510,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
* @see #instantiateUsingFactoryMethod
|
||||
* @see #autowireConstructor
|
||||
*/
|
||||
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
|
||||
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
|
||||
throws BeanCreationException {
|
||||
|
||||
// Instantiate the bean.
|
||||
BeanWrapper instanceWrapper = null;
|
||||
if (mbd.isSingleton()) {
|
||||
|
@ -515,7 +527,13 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
// Allow post-processors to modify the merged bean definition.
|
||||
synchronized (mbd.postProcessingLock) {
|
||||
if (!mbd.postProcessed) {
|
||||
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
|
||||
try {
|
||||
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Post-processing failed of bean type [" + beanType + "] failed", ex);
|
||||
}
|
||||
mbd.postProcessed = true;
|
||||
}
|
||||
}
|
||||
|
@ -550,7 +568,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
throw (BeanCreationException) ex;
|
||||
}
|
||||
else {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,7 +605,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
registerDisposableBeanIfNecessary(beanName, bean, mbd);
|
||||
}
|
||||
catch (BeanDefinitionValidationException ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
|
||||
}
|
||||
|
||||
return exposedObject;
|
||||
|
@ -773,10 +793,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
ReflectionUtils.doWithMethods(fbClass,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
public void doWith(Method method) {
|
||||
if (method.getName().equals(factoryMethodName) &&
|
||||
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
|
||||
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
|
||||
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(
|
||||
method, FactoryBean.class);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -933,18 +954,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
try {
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof MergedBeanDefinitionPostProcessor) {
|
||||
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
|
||||
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
|
||||
}
|
||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||
if (bp instanceof MergedBeanDefinitionPostProcessor) {
|
||||
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
|
||||
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Post-processing failed of bean type [" + beanType + "] failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1107,7 +1122,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
return bw;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
|
||||
throw new BeanCreationException(
|
||||
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1659,7 +1675,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
|||
* methods with arguments.
|
||||
* @see #invokeInitMethods
|
||||
*/
|
||||
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
|
||||
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
|
||||
throws Throwable {
|
||||
|
||||
String initMethodName = mbd.getInitMethodName();
|
||||
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
|
||||
BeanUtils.findMethod(bean.getClass(), initMethodName) :
|
||||
|
|
|
@ -287,13 +287,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
// Guarantee initialization of beans that the current bean depends on.
|
||||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
if (isDependent(beanName, dependsOnBean)) {
|
||||
for (String dep : dependsOn) {
|
||||
if (isDependent(beanName, dep)) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
|
||||
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
|
||||
}
|
||||
registerDependentBean(dependsOnBean, beanName);
|
||||
getBean(dependsOnBean);
|
||||
registerDependentBean(dep, beanName);
|
||||
getBean(dep);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,19 +460,19 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
return false;
|
||||
}
|
||||
if (isFactoryBean(beanName, mbd)) {
|
||||
final FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) ||
|
||||
!factoryBean.isSingleton());
|
||||
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
|
||||
!fb.isSingleton());
|
||||
}
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factoryBean).isPrototype()) ||
|
||||
!factoryBean.isSingleton());
|
||||
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
|
||||
!fb.isSingleton());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1053,11 +1053,11 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
* Destroy the given bean instance (usually a prototype instance
|
||||
* obtained from this factory) according to the given bean definition.
|
||||
* @param beanName the name of the bean definition
|
||||
* @param beanInstance the bean instance to destroy
|
||||
* @param bean the bean instance to destroy
|
||||
* @param mbd the merged bean definition
|
||||
*/
|
||||
protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) {
|
||||
new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy();
|
||||
protected void destroyBean(String beanName, Object bean, RootBeanDefinition mbd) {
|
||||
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1238,12 +1238,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
pbd = getMergedBeanDefinition(parentBeanName);
|
||||
}
|
||||
else {
|
||||
if (getParentBeanFactory() instanceof ConfigurableBeanFactory) {
|
||||
pbd = ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(parentBeanName);
|
||||
BeanFactory parent = getParentBeanFactory();
|
||||
if (parent instanceof ConfigurableBeanFactory) {
|
||||
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(bd.getParentName(),
|
||||
"Parent name '" + bd.getParentName() + "' is equal to bean name '" + beanName +
|
||||
throw new NoSuchBeanDefinitionException(parentBeanName,
|
||||
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
|
||||
"': cannot be resolved without an AbstractBeanFactory parent");
|
||||
}
|
||||
}
|
||||
|
@ -1359,12 +1360,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
catch (ClassNotFoundException ex) {
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
|
||||
}
|
||||
catch (LinkageError err) {
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
|
||||
catch (LinkageError ex) {
|
||||
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
|
||||
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
|
||||
throws ClassNotFoundException {
|
||||
|
||||
ClassLoader beanClassLoader = getBeanClassLoader();
|
||||
ClassLoader classLoaderToUse = beanClassLoader;
|
||||
if (!ObjectUtils.isEmpty(typesToMatch)) {
|
||||
|
|
|
@ -483,6 +483,7 @@ public abstract class ReflectionUtils {
|
|||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @since 4.2
|
||||
* @throws IllegalStateException if introspection fails
|
||||
* @see #doWithMethods
|
||||
*/
|
||||
public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
|
||||
|
@ -504,6 +505,7 @@ public abstract class ReflectionUtils {
|
|||
* twice, unless excluded by a {@link MethodFilter}.
|
||||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @throws IllegalStateException if introspection fails
|
||||
* @see #doWithMethods(Class, MethodCallback, MethodFilter)
|
||||
*/
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc) {
|
||||
|
@ -518,6 +520,7 @@ public abstract class ReflectionUtils {
|
|||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @param mf the filter that determines the methods to apply the callback to
|
||||
* @throws IllegalStateException if introspection fails
|
||||
*/
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
|
||||
// Keep backing up the inheritance hierarchy.
|
||||
|
@ -547,6 +550,7 @@ public abstract class ReflectionUtils {
|
|||
* Get all declared methods on the leaf class and all superclasses.
|
||||
* Leaf class methods are included first.
|
||||
* @param leafClass the class to introspect
|
||||
* @throws IllegalStateException if introspection fails
|
||||
*/
|
||||
public static Method[] getAllDeclaredMethods(Class<?> leafClass) {
|
||||
final List<Method> methods = new ArrayList<Method>(32);
|
||||
|
@ -564,6 +568,7 @@ public abstract class ReflectionUtils {
|
|||
* Leaf class methods are included first and while traversing the superclass hierarchy
|
||||
* any methods found with signatures matching a method already included are filtered out.
|
||||
* @param leafClass the class to introspect
|
||||
* @throws IllegalStateException if introspection fails
|
||||
*/
|
||||
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass) {
|
||||
final List<Method> methods = new ArrayList<Method>(32);
|
||||
|
@ -604,26 +609,33 @@ public abstract class ReflectionUtils {
|
|||
* interfaces, since those are effectively to be treated just like declared methods.
|
||||
* @param clazz the class to introspect
|
||||
* @return the cached array of methods
|
||||
* @throws IllegalStateException if introspection fails
|
||||
* @see Class#getDeclaredMethods()
|
||||
*/
|
||||
private static Method[] getDeclaredMethods(Class<?> clazz) {
|
||||
Method[] result = declaredMethodsCache.get(clazz);
|
||||
if (result == null) {
|
||||
Method[] declaredMethods = clazz.getDeclaredMethods();
|
||||
List<Method> defaultMethods = findConcreteMethodsOnInterfaces(clazz);
|
||||
if (defaultMethods != null) {
|
||||
result = new Method[declaredMethods.length + defaultMethods.size()];
|
||||
System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length);
|
||||
int index = declaredMethods.length;
|
||||
for (Method defaultMethod : defaultMethods) {
|
||||
result[index] = defaultMethod;
|
||||
index++;
|
||||
try {
|
||||
Method[] declaredMethods = clazz.getDeclaredMethods();
|
||||
List<Method> defaultMethods = findConcreteMethodsOnInterfaces(clazz);
|
||||
if (defaultMethods != null) {
|
||||
result = new Method[declaredMethods.length + defaultMethods.size()];
|
||||
System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length);
|
||||
int index = declaredMethods.length;
|
||||
for (Method defaultMethod : defaultMethods) {
|
||||
result[index] = defaultMethod;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = declaredMethods;
|
||||
}
|
||||
declaredMethodsCache.put(clazz, (result.length == 0 ? NO_METHODS : result));
|
||||
}
|
||||
else {
|
||||
result = declaredMethods;
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Failed to introspect Class [" + clazz +
|
||||
"] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
|
||||
}
|
||||
declaredMethodsCache.put(clazz, (result.length == 0 ? NO_METHODS : result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -649,6 +661,7 @@ public abstract class ReflectionUtils {
|
|||
* @param clazz the target class to analyze
|
||||
* @param fc the callback to invoke for each field
|
||||
* @since 4.2
|
||||
* @throws IllegalStateException if introspection fails
|
||||
* @see #doWithFields
|
||||
*/
|
||||
public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
|
||||
|
@ -667,6 +680,7 @@ public abstract class ReflectionUtils {
|
|||
* class hierarchy to get all declared fields.
|
||||
* @param clazz the target class to analyze
|
||||
* @param fc the callback to invoke for each field
|
||||
* @throws IllegalStateException if introspection fails
|
||||
*/
|
||||
public static void doWithFields(Class<?> clazz, FieldCallback fc) {
|
||||
doWithFields(clazz, fc, null);
|
||||
|
@ -678,6 +692,7 @@ public abstract class ReflectionUtils {
|
|||
* @param clazz the target class to analyze
|
||||
* @param fc the callback to invoke for each field
|
||||
* @param ff the filter that determines the fields to apply the callback to
|
||||
* @throws IllegalStateException if introspection fails
|
||||
*/
|
||||
public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff) {
|
||||
// Keep backing up the inheritance hierarchy.
|
||||
|
@ -705,13 +720,20 @@ public abstract class ReflectionUtils {
|
|||
* in order to avoid the JVM's SecurityManager check and defensive array copying.
|
||||
* @param clazz the class to introspect
|
||||
* @return the cached array of fields
|
||||
* @throws IllegalStateException if introspection fails
|
||||
* @see Class#getDeclaredFields()
|
||||
*/
|
||||
private static Field[] getDeclaredFields(Class<?> clazz) {
|
||||
Field[] result = declaredFieldsCache.get(clazz);
|
||||
if (result == null) {
|
||||
result = clazz.getDeclaredFields();
|
||||
declaredFieldsCache.put(clazz, (result.length == 0 ? NO_FIELDS : result));
|
||||
try {
|
||||
result = clazz.getDeclaredFields();
|
||||
declaredFieldsCache.put(clazz, (result.length == 0 ? NO_FIELDS : result));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Failed to introspect Class [" + clazz +
|
||||
"] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -720,6 +742,7 @@ public abstract class ReflectionUtils {
|
|||
* Given the source object and the destination, which must be the same class
|
||||
* or a subclass, copy all fields, including inherited fields. Designed to
|
||||
* work on objects with public no-arg constructors.
|
||||
* @throws IllegalStateException if introspection fails
|
||||
*/
|
||||
public static void shallowCopyFieldState(final Object src, final Object dest) {
|
||||
if (src == null) {
|
||||
|
|
Loading…
Reference in New Issue