Do not silently return null when no constructor candidate is found
This commit updates ConstructorOrFactoryMethodResolver to throw an exception if no constructor or factory method can be found for a given bean definition. This prevents code generation to happen on an incomplete view of the bean to instantiate. Closes gh-29052
This commit is contained in:
parent
8fbd2141b7
commit
903078a5b2
|
|
@ -18,7 +18,6 @@ package org.springframework.beans.factory.aot;
|
|||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -74,7 +73,6 @@ class ConstructorOrFactoryMethodResolver {
|
|||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
Executable resolve(BeanDefinition beanDefinition) {
|
||||
Supplier<ResolvableType> beanType = () -> getBeanType(beanDefinition);
|
||||
List<ResolvableType> valueTypes = (beanDefinition.hasConstructorArgumentValues() ?
|
||||
|
|
@ -93,7 +91,13 @@ class ConstructorOrFactoryMethodResolver {
|
|||
Assert.state(isCompatible, () -> String.format(
|
||||
"Incompatible target type '%s' for factory bean '%s'",
|
||||
resolvableType.toClass().getName(), factoryBeanClass.getName()));
|
||||
return resolveConstructor(() -> ResolvableType.forClass(factoryBeanClass), valueTypes);
|
||||
Executable executable = resolveConstructor(() -> ResolvableType.forClass(factoryBeanClass), valueTypes);
|
||||
if (executable != null) {
|
||||
return executable;
|
||||
}
|
||||
throw new IllegalStateException("No suitable FactoryBean constructor found for "
|
||||
+ beanDefinition + " and argument types " + valueTypes);
|
||||
|
||||
}
|
||||
|
||||
Executable resolvedConstructor = resolveConstructor(beanType, valueTypes);
|
||||
|
|
@ -101,13 +105,8 @@ class ConstructorOrFactoryMethodResolver {
|
|||
return resolvedConstructor;
|
||||
}
|
||||
|
||||
Field field = ReflectionUtils.findField(RootBeanDefinition.class, "resolvedConstructorOrFactoryMethod");
|
||||
if (field != null) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return (Executable) ReflectionUtils.getField(field, beanDefinition);
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new IllegalStateException("No constructor or factory method candidate found for "
|
||||
+ beanDefinition + " and argument types " + valueTypes);
|
||||
}
|
||||
|
||||
private List<ResolvableType> determineParameterValueTypes(
|
||||
|
|
@ -390,7 +389,6 @@ class ConstructorOrFactoryMethodResolver {
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Executable resolve(RegisteredBean registeredBean) {
|
||||
return new ConstructorOrFactoryMethodResolver(registeredBean.getBeanFactory())
|
||||
.resolve(registeredBean.getMergedBeanDefinition());
|
||||
|
|
|
|||
|
|
@ -200,8 +200,9 @@ class ConstructorOrFactoryMethodResolverTests {
|
|||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.addConstructorArgValue(Locale.ENGLISH).getBeanDefinition();
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNull();
|
||||
assertThatIllegalStateException().isThrownBy(() -> resolve(new DefaultListableBeanFactory(), beanDefinition))
|
||||
.withMessageContaining(MultiConstructorSample.class.getName())
|
||||
.withMessageContaining("and argument types [java.util.Locale]");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -212,8 +213,9 @@ class ConstructorOrFactoryMethodResolverTests {
|
|||
.rootBeanDefinition(Locale.class, "getDefault")
|
||||
.getBeanDefinition())
|
||||
.getBeanDefinition();
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNull();
|
||||
assertThatIllegalStateException().isThrownBy(() -> resolve(new DefaultListableBeanFactory(), beanDefinition))
|
||||
.withMessageContaining(MultiConstructorSample.class.getName())
|
||||
.withMessageContaining("and argument types [java.util.Locale]");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -338,7 +340,6 @@ class ConstructorOrFactoryMethodResolverTests {
|
|||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private Executable resolve(DefaultListableBeanFactory beanFactory, BeanDefinition beanDefinition) {
|
||||
return new ConstructorOrFactoryMethodResolver(beanFactory).resolve(beanDefinition);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue