Skip to content

Commit cc57b55

Browse files
committed
Expose a way to resolved a merged inner bean definition
This commit extracts the logic of resolving a merged bean definition for an inner bean to a public method so that other components can reuse it. Closes gh-28093
1 parent fd191d1 commit cc57b55

File tree

2 files changed

+70
-10
lines changed

2 files changed

+70
-10
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Map;
2424
import java.util.Properties;
2525
import java.util.Set;
26+
import java.util.function.BiFunction;
2627

2728
import org.springframework.beans.BeanWrapper;
2829
import org.springframework.beans.BeanWrapperImpl;
@@ -57,6 +58,7 @@
5758
*
5859
* @author Juergen Hoeller
5960
* @author Sam Brannen
61+
* @author Stephane Nicoll
6062
* @since 1.2
6163
* @see AbstractAutowireCapableBeanFactory
6264
*/
@@ -143,13 +145,12 @@ else if (value instanceof RuntimeBeanNameReference ref) {
143145
}
144146
else if (value instanceof BeanDefinitionHolder bdHolder) {
145147
// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
146-
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
148+
return resolveInnerBean(bdHolder.getBeanName(), bdHolder.getBeanDefinition(),
149+
(name, mbd) -> resolveInnerBeanValue(argName, name, mbd));
147150
}
148151
else if (value instanceof BeanDefinition bd) {
149-
// Resolve plain BeanDefinition, without contained name: use dummy name.
150-
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
151-
ObjectUtils.getIdentityHexString(bd);
152-
return resolveInnerBean(argName, innerBeanName, bd);
152+
return resolveInnerBean(null, bd,
153+
(name, mbd) -> resolveInnerBeanValue(argName, name, mbd));
153154
}
154155
else if (value instanceof DependencyDescriptor dependencyDescriptor) {
155156
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
@@ -243,6 +244,23 @@ else if (value instanceof NullBean) {
243244
}
244245
}
245246

247+
/**
248+
* Resolve an inner bean definition and invoke the specified {@code resolver}
249+
* on its merged bean definition.
250+
* @param innerBeanName the inner bean name (or {@code null} to assign one)
251+
* @param innerBd the inner raw bean definition
252+
* @param resolver the function to invoke to resolve
253+
* @param <T> the type of the resolution
254+
* @return a resolved inner bean, as a result of applying the {@code resolver}
255+
*/
256+
public <T> T resolveInnerBean(@Nullable String innerBeanName, BeanDefinition innerBd,
257+
BiFunction<String, RootBeanDefinition, T> resolver) {
258+
String nameToUse = (innerBeanName != null ? innerBeanName : "(inner bean)"
259+
+ BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(innerBd));
260+
return resolver.apply(nameToUse, this.beanFactory.getMergedBeanDefinition(
261+
nameToUse, innerBd, this.beanDefinition));
262+
}
263+
246264
/**
247265
* Evaluate the given value as an expression, if necessary.
248266
* @param value the candidate value (may be an expression)
@@ -362,14 +380,12 @@ private Object resolveReference(Object argName, RuntimeBeanReference ref) {
362380
* Resolve an inner bean definition.
363381
* @param argName the name of the argument that the inner bean is defined for
364382
* @param innerBeanName the name of the inner bean
365-
* @param innerBd the bean definition for the inner bean
383+
* @param mbd the merged bean definition for the inner bean
366384
* @return the resolved inner bean instance
367385
*/
368386
@Nullable
369-
private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefinition innerBd) {
370-
RootBeanDefinition mbd = null;
387+
private Object resolveInnerBeanValue(Object argName, String innerBeanName, RootBeanDefinition mbd) {
371388
try {
372-
mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
373389
// Check given bean name whether it is unique. If not already unique,
374390
// add counter - increasing the counter until the name is unique.
375391
String actualInnerBeanName = innerBeanName;
@@ -400,7 +416,7 @@ private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefini
400416
throw new BeanCreationException(
401417
this.beanDefinition.getResourceDescription(), this.beanName,
402418
"Cannot create inner bean '" + innerBeanName + "' " +
403-
(mbd != null && mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
419+
(mbd.getBeanClassName() != null ? "of type [" + mbd.getBeanClassName() + "] " : "") +
404420
"while setting " + argName, ex);
405421
}
406422
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory.support;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
/**
24+
* Tests for {@link BeanDefinitionValueResolver}.
25+
*
26+
* @author Stephane Nicoll
27+
*/
28+
class BeanDefinitionValueResolverTests {
29+
30+
@Test
31+
void resolveInnerBean() {
32+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
33+
RootBeanDefinition parentBd = new RootBeanDefinition();
34+
GenericBeanDefinition innerBd = new GenericBeanDefinition();
35+
innerBd.setAttribute("test", 42);
36+
BeanDefinitionValueResolver bdvr = new BeanDefinitionValueResolver(beanFactory, "test", parentBd);
37+
RootBeanDefinition resolvedInnerBd = bdvr.resolveInnerBean(null,innerBd, (name, mbd) -> {
38+
assertThat(name).isNotNull().startsWith("(inner bean");
39+
return mbd;
40+
});
41+
assertThat(resolvedInnerBd.getAttribute("test")).isEqualTo(42);
42+
}
43+
44+
}

0 commit comments

Comments
 (0)