Add InstanceSupplier and RegisteredBean support
Add a new `InstanceSupplier` interface that can be used as an alternative to a regular bean `Supplier` when details about the bean being supplied are required to instantiate it. The new interface accepts a `RegisteredBean` instance which provides access to the bean name, the bean factory creating the bean and the bean definition. This interface is primarily designed to allow AOT generated code to autowire dependencies into the instance. See gh-28414
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.util.function.ThrowingSupplier;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractAutowireCapableBeanFactory} instance supplier
|
||||
* support.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class BeanFactorySupplierTests {
|
||||
|
||||
@Test
|
||||
void getBeanWhenUsingRegularSupplier() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||
beanDefinition.setInstanceSupplier(() -> "I am supplied");
|
||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||
assertThat(beanFactory.getBean("test")).isEqualTo("I am supplied");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanWhenUsingInstanceSupplier() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||
beanDefinition.setInstanceSupplier(InstanceSupplier
|
||||
.of(registeredBean -> "I am bean " + registeredBean.getBeanName()));
|
||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||
assertThat(beanFactory.getBean("test")).isEqualTo("I am bean test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanWhenUsingThrowableSupplier() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||
beanDefinition.setInstanceSupplier(ThrowingSupplier.of(() -> "I am supplied"));
|
||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||
assertThat(beanFactory.getBean("test")).isEqualTo("I am supplied");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanWhenUsingThrowableSupplierThatThrowsCheckedException() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||
beanDefinition.setInstanceSupplier(ThrowingSupplier.of(() -> {
|
||||
throw new IOException("fail");
|
||||
}));
|
||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> beanFactory.getBean("test"))
|
||||
.withCauseInstanceOf(IOException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanWhenUsingThrowableSupplierThatThrowsRuntimeException() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||
beanDefinition.setInstanceSupplier(ThrowingSupplier.of(() -> {
|
||||
throw new IllegalStateException("fail");
|
||||
}));
|
||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> beanFactory.getBean("test"))
|
||||
.withCauseInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.util.function.ThrowingBiFunction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link InstanceSupplier}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class InstanceSupplierTests {
|
||||
|
||||
private final RegisteredBean registeredBean = RegisteredBean
|
||||
.of(new DefaultListableBeanFactory(), "test");
|
||||
|
||||
@Test
|
||||
void getWithoutRegisteredBeanThrowsException() {
|
||||
InstanceSupplier<String> supplier = registeredBean -> "test";
|
||||
assertThatIllegalStateException().isThrownBy(() -> supplier.get())
|
||||
.withMessage("No RegisteredBean parameter provided");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithExceptionWithoutRegisteredBeanThrowsException() {
|
||||
InstanceSupplier<String> supplier = registeredBean -> "test";
|
||||
assertThatIllegalStateException().isThrownBy(() -> supplier.getWithException())
|
||||
.withMessage("No RegisteredBean parameter provided");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getReturnsResult() throws Exception {
|
||||
InstanceSupplier<String> supplier = registeredBean -> "test";
|
||||
assertThat(supplier.get(this.registeredBean)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void andThenWithBiFunctionWhenFunctionIsNullThrowsException() {
|
||||
InstanceSupplier<String> supplier = registeredBean -> "test";
|
||||
ThrowingBiFunction<RegisteredBean, String, String> after = null;
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> supplier.andThen(after))
|
||||
.withMessage("After must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void andThenWithBiFunctionAppliesFunctionToObtainResult() throws Exception {
|
||||
InstanceSupplier<String> supplier = registeredBean -> "bean";
|
||||
supplier = supplier.andThen(
|
||||
(registeredBean, string) -> registeredBean.getBeanName() + "-" + string);
|
||||
assertThat(supplier.get(this.registeredBean)).isEqualTo("test-bean");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofSupplierWhenInstanceSupplierReturnsSameInstance() {
|
||||
InstanceSupplier<String> supplier = registeredBean -> "test";
|
||||
assertThat(InstanceSupplier.of(supplier)).isSameAs(supplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
void usingSupplierAdaptsToInstanceSupplier() throws Exception {
|
||||
InstanceSupplier<String> instanceSupplier = InstanceSupplier.using(() -> "test");
|
||||
assertThat(instanceSupplier.get(this.registeredBean)).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofInstanceSupplierAdaptsToInstanceSupplier() throws Exception {
|
||||
InstanceSupplier<String> instanceSupplier = InstanceSupplier
|
||||
.of(registeredBean -> "test");
|
||||
assertThat(instanceSupplier.get(this.registeredBean)).isEqualTo("test");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link RegisteredBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 6.0
|
||||
*/
|
||||
class RegisteredBeanTests {
|
||||
|
||||
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
this.beanFactory.registerBeanDefinition("bd",
|
||||
new RootBeanDefinition(TestBean.class));
|
||||
this.beanFactory.registerSingleton("sb", new TestBean());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofWhenBeanFactoryIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> RegisteredBean.of(null, "bd"))
|
||||
.withMessage("BeanFactory must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofWhenBeanNameIsEmptyThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> RegisteredBean.of(this.beanFactory, null))
|
||||
.withMessage("BeanName must not be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofInnerBeanWhenInnerBeanIsNullThrowsException() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> RegisteredBean.ofInnerBean(parent, (BeanDefinitionHolder) null))
|
||||
.withMessage("InnerBean must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofInnerBeanWhenParentIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> RegisteredBean.ofInnerBean(null,
|
||||
new RootBeanDefinition(TestInnerBean.class)))
|
||||
.withMessage("Parent must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofInnerBeanWhenInnerBeanDefinitionIsNullThrowsException() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> RegisteredBean.ofInnerBean(parent, "ib", null))
|
||||
.withMessage("InnerBeanDefinition must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNameReturnsBeanName() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.getBeanName()).isEqualTo("bd");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNameWhenNamedInnerBeanReturnsBeanName() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent, "ib",
|
||||
new RootBeanDefinition(TestInnerBean.class));
|
||||
assertThat(registeredBean.getBeanName()).isEqualTo("ib");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNameWhenUnnamedInnerBeanReturnsBeanName() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent,
|
||||
new RootBeanDefinition(TestInnerBean.class));
|
||||
assertThat(registeredBean.getBeanName()).startsWith("(inner bean)#");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanClassReturnsBeanClass() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.getBeanClass()).isEqualTo(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanClassWhenSingletonReturnsBeanClass() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "sb");
|
||||
assertThat(registeredBean.getBeanClass()).isEqualTo(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanTypeReturnsBeanType() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.getBeanType().toClass()).isEqualTo(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanTypeWhenSingletonReturnsBeanType() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "sb");
|
||||
assertThat(registeredBean.getBeanType().toClass()).isEqualTo(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMergedBeanDefinitionReturnsMergedBeanDefinition() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.getMergedBeanDefinition().getBeanClass())
|
||||
.isEqualTo(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMergedBeanDefinitionWhenSingletonThrowsException() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "sb");
|
||||
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
|
||||
.isThrownBy(() -> registeredBean.getMergedBeanDefinition());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMergedBeanDefinitionWhenInnerBeanReturnsMergedBeanDefinition() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent,
|
||||
new RootBeanDefinition(TestInnerBean.class));
|
||||
assertThat(registeredBean.getMergedBeanDefinition().getBeanClass())
|
||||
.isEqualTo(TestInnerBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isInnerBeanWhenInnerBeanReturnsTrue() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent,
|
||||
new RootBeanDefinition(TestInnerBean.class));
|
||||
assertThat(registeredBean.isInnerBean()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isInnerBeanWhenNotInnerBeanReturnsTrue() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.isInnerBean()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getParentWhenInnerBeanReturnsParent() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent,
|
||||
new RootBeanDefinition(TestInnerBean.class));
|
||||
assertThat(registeredBean.getParent()).isSameAs(parent);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getParentWhenNotInnerBeanReturnsNull() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.getParent()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGeneratedBeanNameWhenInnerBeanWithoutNameReturnsTrue() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent,
|
||||
new RootBeanDefinition(TestInnerBean.class));
|
||||
assertThat(registeredBean.isGeneratedBeanName()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGeneratedBeanNameWhenInnerBeanWithNameReturnsFalse() {
|
||||
RegisteredBean parent = RegisteredBean.of(this.beanFactory, "bd");
|
||||
RegisteredBean registeredBean = RegisteredBean.ofInnerBean(parent,
|
||||
new BeanDefinitionHolder(new RootBeanDefinition(TestInnerBean.class),
|
||||
"test"));
|
||||
assertThat(registeredBean.isGeneratedBeanName()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isGeneratedBeanNameWhenNotInnerBeanReturnsFalse() {
|
||||
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, "bd");
|
||||
assertThat(registeredBean.isGeneratedBeanName()).isFalse();
|
||||
}
|
||||
|
||||
static class TestBean {
|
||||
|
||||
}
|
||||
|
||||
static class TestInnerBean {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user