Provide dedicated AOT exception hierarchy
This commit adds a number of catch point that provides additional context when an AOT processor fails to execute. Amongst other things, this makes sure that the bean name and its descriptor is consistently provided in the error message when available. Closes gh-32777
This commit is contained in:
@@ -69,7 +69,7 @@ import org.springframework.javapoet.ParameterizedTypeName;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
|
||||
/**
|
||||
@@ -691,9 +691,10 @@ class BeanDefinitionMethodGeneratorTests {
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
|
||||
this.methodGeneratorFactory, registeredBean, null,
|
||||
List.of());
|
||||
assertThatIllegalStateException().isThrownBy(() -> generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode)).withMessage(
|
||||
"Error processing bean with name 'testBean': instance supplier is not supported");
|
||||
assertThatExceptionOfType(AotBeanProcessingException.class)
|
||||
.isThrownBy(() -> generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode))
|
||||
.withMessage("Error processing bean with name 'testBean': instance supplier is not supported");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -709,9 +710,10 @@ class BeanDefinitionMethodGeneratorTests {
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
|
||||
this.methodGeneratorFactory, registeredBean, null,
|
||||
List.of(aotContribution));
|
||||
assertThatIllegalStateException().isThrownBy(() -> generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode)).withMessageStartingWith(
|
||||
"Default code generation is not supported for bean definitions declaring an instance supplier callback");
|
||||
assertThatExceptionOfType(AotBeanProcessingException.class)
|
||||
.isThrownBy(() -> generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode))
|
||||
.withMessage("Error processing bean with name 'testBean': instance supplier is not supported");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -728,9 +730,10 @@ class BeanDefinitionMethodGeneratorTests {
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
|
||||
this.methodGeneratorFactory, registeredBean, null,
|
||||
List.of(aotContribution));
|
||||
assertThatIllegalStateException().isThrownBy(() -> generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode)).withMessage(
|
||||
"Error processing bean with name 'testBean': instance supplier is not supported");
|
||||
assertThatExceptionOfType(AotBeanProcessingException.class)
|
||||
.isThrownBy(() -> generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode))
|
||||
.withMessage("Error processing bean with name 'testBean': instance supplier is not supported");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.aot.generate.ClassNameGenerator;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.generate.MethodReference;
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.generate.ValueCodeGenerationException;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.Registration;
|
||||
@@ -38,6 +39,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.AgeHolder;
|
||||
import org.springframework.beans.testfixture.beans.Employee;
|
||||
import org.springframework.beans.testfixture.beans.ITestBean;
|
||||
import org.springframework.beans.testfixture.beans.NestedTestBean;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanFactoryInitializationCode;
|
||||
import org.springframework.core.test.io.support.MockSpringFactoriesLoader;
|
||||
@@ -50,6 +52,7 @@ import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.javapoet.ParameterizedTypeName;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;
|
||||
|
||||
/**
|
||||
@@ -156,6 +159,57 @@ class BeanRegistrationsAotContributionTests {
|
||||
.accepts(this.generationContext.getRuntimeHints());
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyToFailingDoesNotWrapAotException() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class);
|
||||
beanDefinition.setInstanceSupplier(TestBean::new);
|
||||
RegisteredBean registeredBean = registerBean(beanDefinition);
|
||||
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
|
||||
registeredBean, null, List.of());
|
||||
BeanRegistrationsAotContribution contribution = createContribution(registeredBean, generator, "testAlias");
|
||||
assertThatExceptionOfType(AotProcessingException.class)
|
||||
.isThrownBy(() -> contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode))
|
||||
.withMessage("Error processing bean with name 'testBean': instance supplier is not supported")
|
||||
.withNoCause();
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyToFailingWrapsValueCodeGeneration() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class);
|
||||
beanDefinition.getPropertyValues().addPropertyValue("doctor", new NestedTestBean());
|
||||
RegisteredBean registeredBean = registerBean(beanDefinition);
|
||||
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
|
||||
registeredBean, null, List.of());
|
||||
BeanRegistrationsAotContribution contribution = createContribution(registeredBean, generator, "testAlias");
|
||||
assertThatExceptionOfType(AotProcessingException.class)
|
||||
.isThrownBy(() -> contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode))
|
||||
.withMessage("Error processing bean with name 'testBean': failed to generate code for bean definition")
|
||||
.havingCause().isInstanceOf(ValueCodeGenerationException.class)
|
||||
.withMessageContaining("Failed to generate code for")
|
||||
.withMessageContaining(NestedTestBean.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyToFailingProvidesDedicatedException() {
|
||||
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(TestBean.class));
|
||||
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
|
||||
registeredBean, null, List.of()) {
|
||||
@Override
|
||||
MethodReference generateBeanDefinitionMethod(GenerationContext generationContext,
|
||||
BeanRegistrationsCode beanRegistrationsCode) {
|
||||
throw new IllegalStateException("Test exception");
|
||||
}
|
||||
};
|
||||
BeanRegistrationsAotContribution contribution = createContribution(registeredBean, generator, "testAlias");
|
||||
assertThatExceptionOfType(AotProcessingException.class)
|
||||
.isThrownBy(() -> contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode))
|
||||
.withMessage("Error processing bean with name 'testBean': failed to generate code for bean definition")
|
||||
.havingCause().isInstanceOf(IllegalStateException.class).withMessage("Test exception");
|
||||
}
|
||||
|
||||
private RegisteredBean registerBean(RootBeanDefinition rootBeanDefinition) {
|
||||
String beanName = "testBean";
|
||||
this.beanFactory.registerBeanDefinition(beanName, rootBeanDefinition);
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -72,7 +72,8 @@ class DefaultBeanRegistrationCodeFragmentsTests {
|
||||
beanDefinition.setInstanceSupplier(SimpleBean::new);
|
||||
RegisteredBean registeredBean = registerTestBean(beanDefinition);
|
||||
BeanRegistrationCodeFragments codeFragments = createInstance(registeredBean);
|
||||
assertThatIllegalStateException().isThrownBy(() -> codeFragments.getTarget(registeredBean))
|
||||
assertThatExceptionOfType(AotBeanProcessingException.class)
|
||||
.isThrownBy(() -> codeFragments.getTarget(registeredBean))
|
||||
.withMessageContaining("Error processing bean with name 'testBean': instance supplier is not supported");
|
||||
}
|
||||
|
||||
@@ -83,7 +84,8 @@ class DefaultBeanRegistrationCodeFragmentsTests {
|
||||
beanDefinition.setResourceDescription("my test resource");
|
||||
RegisteredBean registeredBean = registerTestBean(beanDefinition);
|
||||
BeanRegistrationCodeFragments codeFragments = createInstance(registeredBean);
|
||||
assertThatIllegalStateException().isThrownBy(() -> codeFragments.getTarget(registeredBean))
|
||||
assertThatExceptionOfType(AotBeanProcessingException.class)
|
||||
.isThrownBy(() -> codeFragments.getTarget(registeredBean))
|
||||
.withMessageContaining("Error processing bean with name 'testBean' defined in my test resource: "
|
||||
+ "instance supplier is not supported");
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ class InstanceSupplierCodeGeneratorKotlinTests {
|
||||
this.beanFactory.registerBeanDefinition("config", BeanDefinitionBuilder
|
||||
.genericBeanDefinition(KotlinConfiguration::class.java).beanDefinition
|
||||
)
|
||||
Assertions.assertThatIllegalStateException().isThrownBy {
|
||||
Assertions.assertThatExceptionOfType(AotBeanProcessingException::class.java).isThrownBy {
|
||||
compile(beanFactory, beanDefinition) { _, _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user