diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 258f66bf4d..e9b200a43b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -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> candidates = new ArrayList>(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 autowiredBeanNames = new LinkedHashSet(paramTypes.length); + Set autowiredBeans = new LinkedHashSet(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 it = autowiredBeanNames.iterator(); + registerDependentBeans(beanName, autowiredBeans); + if (autowiredBeans.size() == paramTypes.length) { + Iterator 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); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java index ebc3cbf53c..0d7eb6ee3b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java @@ -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)) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessorAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessorAdapter.java index 3e02846fcb..3f7e1746b7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessorAdapter.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessorAdapter.java @@ -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; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 3c2f4ddbd3..e6c86f793e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -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) : diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 303484e646..104d91c1ba 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -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() { @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)) { diff --git a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java index 301ad5a71a..d1e72b4827 100644 --- a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java @@ -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 methods = new ArrayList(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 methods = new ArrayList(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 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 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) {