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:
Phillip Webb 2022-04-13 17:13:17 -07:00
parent d31eb4c0f1
commit 3209d7f126
6 changed files with 789 additions and 11 deletions

View File

@ -79,6 +79,7 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodCallback;
import org.springframework.util.StringUtils;
import org.springframework.util.function.ThrowingSupplier;
/**
* Abstract bean factory superclass that implements default bean creation,
@ -1199,19 +1200,40 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/**
* Obtain a bean instance from the given supplier.
* @param instanceSupplier the configured supplier
* @param supplier the configured supplier
* @param beanName the corresponding bean name
* @return a BeanWrapper for the new instance
* @since 5.0
* @see #getObjectForBeanInstance
*/
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
protected BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName) {
Object instance = obtainInstanceFromSupplier(supplier, beanName);
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName) {
String outerBean = this.currentlyCreatedBean.get();
this.currentlyCreatedBean.set(beanName);
try {
instance = instanceSupplier.get();
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
return instanceSupplier.get(RegisteredBean.of(this, beanName));
}
if (supplier instanceof ThrowingSupplier<?> throwableSupplier) {
return throwableSupplier.getWithException();
}
return supplier.get();
}
catch (Throwable ex) {
if (ex instanceof BeansException beansException) {
throw beansException;
}
throw new BeanCreationException(beanName,
"Instantiation of supplied bean failed", ex);
}
finally {
if (outerBean != null) {
@ -1221,13 +1243,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
this.currentlyCreatedBean.remove();
}
}
if (instance == null) {
instance = new NullBean();
}
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
/**

View File

@ -0,0 +1,97 @@
/*
* 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.util.function.Supplier;
import org.springframework.util.Assert;
import org.springframework.util.function.ThrowingBiFunction;
import org.springframework.util.function.ThrowingSupplier;
/**
* Specialized {@link Supplier} that can be set on a
* {@link AbstractBeanDefinition#setInstanceSupplier(Supplier) BeanDefinition}
* when details about the {@link RegisteredBean registered bean} are needed to
* supply the instance.
*
* @author Phillip Webb
* @since 6.0
* @param <T> the type of instance supplied by this supplier
* @see RegisteredBean
*/
@FunctionalInterface
public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
@Override
default T getWithException() {
throw new IllegalStateException("No RegisteredBean parameter provided");
}
/**
* Gets the supplied instance.
* @param registeredBean the registered bean requesting the instance
* @return the supplied instance
* @throws Exception on error
*/
T get(RegisteredBean registeredBean) throws Exception;
/**
* Return a composed instance supplier that first obtains the instance from
* this supplier, and then applied the {@code after} function to obtain the
* result.
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after the instance is obtained
* @return a composed instance supplier
*/
default <V> InstanceSupplier<V> andThen(
ThrowingBiFunction<RegisteredBean, ? super T, ? extends V> after) {
Assert.notNull(after, "After must not be null");
return registeredBean -> after.applyWithException(registeredBean,
get(registeredBean));
}
/**
* Factory method to create an {@link InstanceSupplier} from a
* {@link ThrowingSupplier}.
* @param <T> the type of instance supplied by this supplier
* @param supplier the source supplier
* @return a new {@link InstanceSupplier}
*/
static <T> InstanceSupplier<T> using(ThrowingSupplier<T> supplier) {
Assert.notNull(supplier, "Supplier must not be null");
if (supplier instanceof InstanceSupplier<T> instanceSupplier) {
return instanceSupplier;
}
return registeredBean -> supplier.getWithException();
}
/**
* Lambda friendly method that can be used to create a
* {@link InstanceSupplier} and add post processors in a single call. For
* example: {@code
* InstanceSupplier.of(registeredBean -> ...).withPostProcessor(...)}.
* @param <T> the type of instance supplied by this supplier
* @param instanceSupplier the source instance supplier
* @return a new {@link InstanceSupplier}
*/
static <T> InstanceSupplier<T> of(InstanceSupplier<T> instanceSupplier) {
Assert.notNull(instanceSupplier, "InstanceSupplier must not be null");
return instanceSupplier;
}
}

View File

@ -0,0 +1,268 @@
/*
* 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.util.function.BiFunction;
import java.util.function.Supplier;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* A {@code RegisteredBean} represents a bean that has been registered with a
* {@link BeanFactory}, but has not necessarily been instantiated. It provides
* access to the bean factory that contains the bean as well as the bean name.
* In the case of inner-beans, the bean name may have been generated.
*
* @author Phillip Webb
* @since 6.0
*/
public final class RegisteredBean {
private final ConfigurableBeanFactory beanFactory;
private final Supplier<String> beanName;
private final boolean generatedBeanName;
private final Supplier<RootBeanDefinition> mergedBeanDefinition;
@Nullable
private final RegisteredBean parent;
private RegisteredBean(ConfigurableBeanFactory beanFactory, Supplier<String> beanName,
boolean generatedBeanName, Supplier<RootBeanDefinition> mergedBeanDefinition,
@Nullable RegisteredBean parent) {
this.beanFactory = beanFactory;
this.beanName = beanName;
this.generatedBeanName = generatedBeanName;
this.mergedBeanDefinition = mergedBeanDefinition;
this.parent = parent;
}
/**
* Create a new {@link RegisteredBean} instance for a regular bean.
* @param beanFactory the source bean factory
* @param beanName the bean name
* @return a new {@link RegisteredBean} instance
*/
public static RegisteredBean of(ConfigurableBeanFactory beanFactory,
String beanName) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
Assert.hasLength(beanName, "BeanName must not be empty");
return new RegisteredBean(beanFactory, () -> beanName, false,
() -> (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName),
null);
}
/**
* Create a new {@link RegisteredBean} instance for an inner-bean.
* @param parent the parent of the inner-bean
* @param innerBean a {@link BeanDefinitionHolder} for the inner bean
* @return a new {@link RegisteredBean} instance
*/
public static RegisteredBean ofInnerBean(RegisteredBean parent,
BeanDefinitionHolder innerBean) {
Assert.notNull(innerBean, "InnerBean must not be null");
return ofInnerBean(parent, innerBean.getBeanName(),
innerBean.getBeanDefinition());
}
/**
* Create a new {@link RegisteredBean} instance for an inner-bean.
* @param parent the parent of the inner-bean
* @param innerBeanDefinition the inner-bean definition
* @return a new {@link RegisteredBean} instance
*/
public static RegisteredBean ofInnerBean(RegisteredBean parent,
BeanDefinition innerBeanDefinition) {
return ofInnerBean(parent, null, innerBeanDefinition);
}
/**
* Create a new {@link RegisteredBean} instance for an inner-bean.
* @param parent the parent of the inner-bean
* @param innerBeanName the name of the inner bean or {@code null} to
* generate a name
* @param innerBeanDefinition the inner-bean definition
* @return a new {@link RegisteredBean} instance
*/
public static RegisteredBean ofInnerBean(RegisteredBean parent,
@Nullable String innerBeanName, BeanDefinition innerBeanDefinition) {
Assert.notNull(parent, "Parent must not be null");
Assert.notNull(innerBeanDefinition, "InnerBeanDefinition must not be null");
InnerBeanResolver resolver = new InnerBeanResolver(parent, innerBeanName,
innerBeanDefinition);
Supplier<String> beanName = StringUtils.hasLength(innerBeanName)
? () -> innerBeanName : resolver::resolveBeanName;
return new RegisteredBean(parent.getBeanFactory(), beanName,
innerBeanName == null, resolver::resolveMergedBeanDefinition, parent);
}
/**
* Return the name of the bean.
* @return the beanName the bean name
*/
public String getBeanName() {
return this.beanName.get();
}
/**
* Return if the bean name is generated.
* @return {@code true} if the name was generated
*/
public boolean isGeneratedBeanName() {
return this.generatedBeanName;
}
/**
* Return the bean factory containing the bean.
* @return the bean factory
*/
public ConfigurableBeanFactory getBeanFactory() {
return this.beanFactory;
}
/**
* Return the user-defined class of the bean.
* @return the bean class
*/
public Class<?> getBeanClass() {
if (this.beanFactory.containsSingleton(getBeanName())) {
return this.beanFactory.getSingleton(getBeanName()).getClass();
}
return ClassUtils.getUserClass(getBeanType().toClass());
}
/**
* Return the {@link ResolvableType} of the bean.
* @return the bean type
*/
public ResolvableType getBeanType() {
if (this.beanFactory.containsSingleton(getBeanName())) {
return ResolvableType
.forInstance(this.beanFactory.getSingleton(getBeanName()));
}
return getMergedBeanDefinition().getResolvableType();
}
/**
* Return the merged bean definition of the bean.
* @return the merged bean definition
* @see ConfigurableBeanFactory#getMergedBeanDefinition(String)
*/
public RootBeanDefinition getMergedBeanDefinition() {
return this.mergedBeanDefinition.get();
}
/**
* Return if this instance is for an inner-bean.
* @return if an inner-bean
*/
public boolean isInnerBean() {
return this.parent != null;
}
/**
* Return the parent of this instance or {@code null} if not an inner-bean.
* @return the parent
*/
@Nullable
public RegisteredBean getParent() {
return this.parent;
}
@Override
public String toString() {
return new ToStringCreator(this).append("beanName", getBeanName())
.append("mergedBeanDefinition", getMergedBeanDefinition()).toString();
}
/**
* Resolver used to obtain inner-bean details.
*/
private static class InnerBeanResolver {
private final RegisteredBean parent;
@Nullable
private final String innerBeanName;
private final BeanDefinition innerBeanDefinition;
@Nullable
private volatile String resolvedBeanName;
InnerBeanResolver(RegisteredBean parent, @Nullable String innerBeanName,
BeanDefinition innerBeanDefinition) {
Assert.isInstanceOf(AbstractAutowireCapableBeanFactory.class,
parent.getBeanFactory());
this.parent = parent;
this.innerBeanName = innerBeanName;
this.innerBeanDefinition = innerBeanDefinition;
}
String resolveBeanName() {
String resolvedBeanName = this.resolvedBeanName;
if (resolvedBeanName != null) {
return resolvedBeanName;
}
resolvedBeanName = resolveInnerBean(
(beanName, mergedBeanDefinition) -> beanName);
this.resolvedBeanName = resolvedBeanName;
return resolvedBeanName;
}
RootBeanDefinition resolveMergedBeanDefinition() {
return resolveInnerBean(
(beanName, mergedBeanDefinition) -> mergedBeanDefinition);
}
private <T> T resolveInnerBean(
BiFunction<String, RootBeanDefinition, T> resolver) {
// Always use a fresh BeanDefinitionValueResolver in case the parent merged bean definition has changed.
BeanDefinitionValueResolver beanDefinitionValueResolver = new BeanDefinitionValueResolver(
(AbstractAutowireCapableBeanFactory) this.parent.getBeanFactory(),
this.parent.getBeanName(), this.parent.getMergedBeanDefinition());
return beanDefinitionValueResolver.resolveInnerBean(this.innerBeanName,
this.innerBeanDefinition, resolver);
}
}
}

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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 {
}
}