Skip to content

Commit b42d731

Browse files
committed
Consistent throwing of BeanCreationExceptions (and reflection exceptions)
Issue: SPR-14883
1 parent fd7045a commit b42d731

File tree

6 files changed

+138
-82
lines changed

6 files changed

+138
-82
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public int getOrder() {
220220
}
221221

222222
@Override
223-
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
223+
public void setBeanFactory(BeanFactory beanFactory) {
224224
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
225225
throw new IllegalArgumentException(
226226
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
@@ -238,7 +238,10 @@ public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, C
238238
}
239239

240240
@Override
241-
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeansException {
241+
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
242+
throws BeanCreationException {
243+
244+
// Let's check for lookup methods here..
242245
if (!this.lookupMethodsChecked.contains(beanName)) {
243246
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
244247
@Override
@@ -263,10 +266,19 @@ public void doWith(Method method) throws IllegalArgumentException, IllegalAccess
263266
// Quick check on the concurrent map first, with minimal locking.
264267
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
265268
if (candidateConstructors == null) {
269+
// Fully synchronized resolution now...
266270
synchronized (this.candidateConstructorsCache) {
267271
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
268272
if (candidateConstructors == null) {
269-
Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();
273+
Constructor<?>[] rawCandidates;
274+
try {
275+
rawCandidates = beanClass.getDeclaredConstructors();
276+
}
277+
catch (Throwable ex) {
278+
throw new BeanCreationException(beanName,
279+
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
280+
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
281+
}
270282
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
271283
Constructor<?> requiredConstructor = null;
272284
Constructor<?> defaultConstructor = null;
@@ -320,9 +332,9 @@ else if (candidate.getParameterTypes().length == 0) {
320332
}
321333
else if (candidates.size() == 1 && logger.isWarnEnabled()) {
322334
logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +
323-
"': single autowire-marked constructor flagged as optional - this constructor " +
324-
"is effectively required since there is no default constructor to fall back to: " +
325-
candidates.get(0));
335+
"': single autowire-marked constructor flagged as optional - " +
336+
"this constructor is effectively required since there is no " +
337+
"default constructor to fall back to: " + candidates.get(0));
326338
}
327339
}
328340
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
@@ -342,7 +354,7 @@ else if (rawCandidates.length == 1 && rawCandidates[0].getParameterTypes().lengt
342354

343355
@Override
344356
public PropertyValues postProcessPropertyValues(
345-
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
357+
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
346358

347359
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
348360
try {
@@ -361,9 +373,9 @@ public PropertyValues postProcessPropertyValues(
361373
* 'Native' processing method for direct calls with an arbitrary target instance,
362374
* resolving all of its fields and methods which are annotated with {@code @Autowired}.
363375
* @param bean the target instance to process
364-
* @throws BeansException if autowiring failed
376+
* @throws BeanCreationException if autowiring failed
365377
*/
366-
public void processInjection(Object bean) throws BeansException {
378+
public void processInjection(Object bean) throws BeanCreationException {
367379
Class<?> clazz = bean.getClass();
368380
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
369381
try {
@@ -373,7 +385,8 @@ public void processInjection(Object bean) throws BeansException {
373385
throw ex;
374386
}
375387
catch (Throwable ex) {
376-
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
388+
throw new BeanCreationException(
389+
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
377390
}
378391
}
379392

@@ -446,7 +459,8 @@ public void doWith(Method method) throws IllegalArgumentException, IllegalAccess
446459
}
447460
if (method.getParameterTypes().length == 0) {
448461
if (logger.isWarnEnabled()) {
449-
logger.warn("Autowired annotation should be used on methods with parameters: " + method);
462+
logger.warn("Autowired annotation should only be used on methods with parameters: " +
463+
method);
450464
}
451465
}
452466
boolean required = determineRequiredStatus(ann);
@@ -629,15 +643,15 @@ protected void inject(Object bean, String beanName, PropertyValues pvs) throws T
629643
Class<?>[] paramTypes = method.getParameterTypes();
630644
arguments = new Object[paramTypes.length];
631645
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
632-
Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
646+
Set<String> autowiredBeans = new LinkedHashSet<String>(paramTypes.length);
633647
TypeConverter typeConverter = beanFactory.getTypeConverter();
634648
for (int i = 0; i < arguments.length; i++) {
635649
MethodParameter methodParam = new MethodParameter(method, i);
636650
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
637651
currDesc.setContainingClass(bean.getClass());
638652
descriptors[i] = currDesc;
639653
try {
640-
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
654+
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
641655
if (arg == null && !this.required) {
642656
arguments = null;
643657
break;
@@ -655,9 +669,9 @@ protected void inject(Object bean, String beanName, PropertyValues pvs) throws T
655669
for (int i = 0; i < arguments.length; i++) {
656670
this.cachedMethodArguments[i] = descriptors[i];
657671
}
658-
registerDependentBeans(beanName, autowiredBeanNames);
659-
if (autowiredBeanNames.size() == paramTypes.length) {
660-
Iterator<String> it = autowiredBeanNames.iterator();
672+
registerDependentBeans(beanName, autowiredBeans);
673+
if (autowiredBeans.size() == paramTypes.length) {
674+
Iterator<String> it = autowiredBeans.iterator();
661675
for (int i = 0; i < paramTypes.length; i++) {
662676
String autowiredBeanName = it.next();
663677
if (beanFactory.containsBean(autowiredBeanName)) {
@@ -706,19 +720,19 @@ private Object[] resolveCachedArguments(String beanName) {
706720
@SuppressWarnings("serial")
707721
private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
708722

709-
private final String shortcutName;
723+
private final String shortcut;
710724

711725
private final Class<?> requiredType;
712726

713-
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcutName, Class<?> requiredType) {
727+
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
714728
super(original);
715-
this.shortcutName = shortcutName;
729+
this.shortcut = shortcut;
716730
this.requiredType = requiredType;
717731
}
718732

719733
@Override
720734
public Object resolveShortcut(BeanFactory beanFactory) {
721-
return resolveCandidate(this.shortcutName, this.requiredType, beanFactory);
735+
return resolveCandidate(this.shortcut, this.requiredType, beanFactory);
722736
}
723737
}
724738

spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -141,8 +141,7 @@ public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, C
141141

142142
@Override
143143
public PropertyValues postProcessPropertyValues(
144-
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
145-
throws BeansException {
144+
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
146145

147146
if (!this.validatedBeanNames.contains(beanName)) {
148147
if (!shouldSkip(this.beanFactory, beanName)) {

spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessorAdapter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -66,8 +66,7 @@ public boolean postProcessAfterInstantiation(Object bean, String beanName) throw
6666

6767
@Override
6868
public PropertyValues postProcessPropertyValues(
69-
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
70-
throws BeansException {
69+
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
7170

7271
return pvs;
7372
}

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -479,11 +479,21 @@ protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] ar
479479
"BeanPostProcessor before instantiation of bean failed", ex);
480480
}
481481

482-
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
483-
if (logger.isDebugEnabled()) {
484-
logger.debug("Finished creating instance of bean '" + beanName + "'");
482+
try {
483+
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
484+
if (logger.isDebugEnabled()) {
485+
logger.debug("Finished creating instance of bean '" + beanName + "'");
486+
}
487+
return beanInstance;
488+
}
489+
catch (BeanCreationException ex) {
490+
// A previously detected exception with proper bean creation context already...
491+
throw ex;
492+
}
493+
catch (Throwable ex) {
494+
throw new BeanCreationException(
495+
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
485496
}
486-
return beanInstance;
487497
}
488498

489499
/**
@@ -500,7 +510,9 @@ protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] ar
500510
* @see #instantiateUsingFactoryMethod
501511
* @see #autowireConstructor
502512
*/
503-
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
513+
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
514+
throws BeanCreationException {
515+
504516
// Instantiate the bean.
505517
BeanWrapper instanceWrapper = null;
506518
if (mbd.isSingleton()) {
@@ -515,7 +527,13 @@ protected Object doCreateBean(final String beanName, final RootBeanDefinition mb
515527
// Allow post-processors to modify the merged bean definition.
516528
synchronized (mbd.postProcessingLock) {
517529
if (!mbd.postProcessed) {
518-
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
530+
try {
531+
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
532+
}
533+
catch (Throwable ex) {
534+
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
535+
"Post-processing failed of bean type [" + beanType + "] failed", ex);
536+
}
519537
mbd.postProcessed = true;
520538
}
521539
}
@@ -550,7 +568,8 @@ public Object getObject() throws BeansException {
550568
throw (BeanCreationException) ex;
551569
}
552570
else {
553-
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
571+
throw new BeanCreationException(
572+
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
554573
}
555574
}
556575

@@ -586,7 +605,8 @@ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
586605
registerDisposableBeanIfNecessary(beanName, bean, mbd);
587606
}
588607
catch (BeanDefinitionValidationException ex) {
589-
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
608+
throw new BeanCreationException(
609+
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
590610
}
591611

592612
return exposedObject;
@@ -773,10 +793,11 @@ class Holder { Class<?> value = null; }
773793
ReflectionUtils.doWithMethods(fbClass,
774794
new ReflectionUtils.MethodCallback() {
775795
@Override
776-
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
796+
public void doWith(Method method) {
777797
if (method.getName().equals(factoryMethodName) &&
778798
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
779-
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
799+
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(
800+
method, FactoryBean.class);
780801
}
781802
}
782803
});
@@ -933,18 +954,12 @@ private FactoryBean<?> getNonSingletonFactoryBeanForTypeCheck(String beanName, R
933954
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
934955
throws BeansException {
935956

936-
try {
937-
for (BeanPostProcessor bp : getBeanPostProcessors()) {
938-
if (bp instanceof MergedBeanDefinitionPostProcessor) {
939-
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
940-
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
941-
}
957+
for (BeanPostProcessor bp : getBeanPostProcessors()) {
958+
if (bp instanceof MergedBeanDefinitionPostProcessor) {
959+
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
960+
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
942961
}
943962
}
944-
catch (Exception ex) {
945-
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
946-
"Post-processing failed of bean type [" + beanType + "] failed", ex);
947-
}
948963
}
949964

950965
/**
@@ -1107,7 +1122,8 @@ public Object run() {
11071122
return bw;
11081123
}
11091124
catch (Throwable ex) {
1110-
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
1125+
throw new BeanCreationException(
1126+
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
11111127
}
11121128
}
11131129

@@ -1659,7 +1675,9 @@ public Object run() throws Exception {
16591675
* methods with arguments.
16601676
* @see #invokeInitMethods
16611677
*/
1662-
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
1678+
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
1679+
throws Throwable {
1680+
16631681
String initMethodName = mbd.getInitMethodName();
16641682
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
16651683
BeanUtils.findMethod(bean.getClass(), initMethodName) :

0 commit comments

Comments
 (0)