Skip to content

Commit

Permalink
Fail explicitly in AOT transformations of instance supplier
Browse files Browse the repository at this point in the history
It is by design not possible to generate code that handles
bean definitions with user-provided instance suppliers because
the JVM does not allow to get a stable reference reusable at
runtime on the lambda or method reference in the code generated
AOT.

Before this commit, such instance supplier was ignored.
After this commit, an IllegalArgumentException is thrown,
allowing projects to be aware this is not supported and enforce
related refactorings.

The related issue gh-29555 describes how this limitation could
be relaxed in the future.

Closes gh-29556
  • Loading branch information
sdeleuze committed Jan 19, 2023
1 parent 047f660 commit ab0d1c3
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
Expand Down Expand Up @@ -35,6 +35,7 @@
import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.MethodParameter;
import org.springframework.javapoet.ClassName;
import org.springframework.lang.Nullable;
Expand All @@ -45,6 +46,7 @@
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Sebastien Deleuze
* @since 6.0
* @see BeanDefinitionMethodGeneratorFactory
*/
Expand All @@ -68,12 +70,17 @@ class BeanDefinitionMethodGenerator {
* @param registeredBean the registered bean
* @param currentPropertyName the current property name
* @param aotContributions the AOT contributions
* @throws IllegalArgumentException if the bean definition defines an instance supplier since this can't be supported for code generation
*/
BeanDefinitionMethodGenerator(
BeanDefinitionMethodGeneratorFactory methodGeneratorFactory,
RegisteredBean registeredBean, @Nullable String currentPropertyName,
List<BeanRegistrationAotContribution> aotContributions) {

RootBeanDefinition mbd = registeredBean.getMergedBeanDefinition();
if (mbd.getInstanceSupplier() != null) {
throw new IllegalArgumentException("Code generation is not supported for bean definitions declaring an instance supplier callback : " + mbd);
}
this.methodGeneratorFactory = methodGeneratorFactory;
this.registeredBean = registeredBean;
this.constructorOrFactoryMethod = registeredBean.resolveConstructorOrFactoryMethod();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
Expand Down Expand Up @@ -58,13 +58,15 @@
import org.springframework.javapoet.ParameterizedTypeName;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

/**
* Tests for {@link BeanDefinitionMethodGenerator} and
* {@link DefaultBeanRegistrationCodeFragments}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Sebastien Deleuze
*/
class BeanDefinitionMethodGeneratorTests {

Expand Down Expand Up @@ -491,6 +493,14 @@ void generateBeanDefinitionMethodWhenBeanIsOfPrimitiveType() {
testBeanDefinitionMethodInCurrentFile(Boolean.class, beanDefinition);
}

@Test
void throwExceptionWithInstanceSupplier() {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(TestBean.class, TestBean::new));
assertThatIllegalArgumentException().isThrownBy(() -> new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList()));
}

private void testBeanDefinitionMethodInCurrentFile(Class<?> targetType, RootBeanDefinition beanDefinition) {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(beanDefinition));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
Expand Down

0 comments on commit ab0d1c3

Please sign in to comment.