Skip to content

Commit 859923b

Browse files
committed
Support for fine-grained by-type references and autowired properties
Closes gh-23032
1 parent eeb79c8 commit 859923b

File tree

7 files changed

+299
-57
lines changed

7 files changed

+299
-57
lines changed

spring-beans/src/main/java/org/springframework/beans/BeanMetadataElement.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ public interface BeanMetadataElement {
3232
* (may be {@code null}).
3333
*/
3434
@Nullable
35-
Object getSource();
35+
default Object getSource() {
36+
return null;
37+
}
3638

3739
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2002-2019 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.config;
18+
19+
import java.io.Serializable;
20+
21+
import org.springframework.lang.Nullable;
22+
23+
/**
24+
* Simple marker class for an individually autowired property value, to be added
25+
* to {@link BeanDefinition#getPropertyValues()} for a specific bean property.
26+
*
27+
* <p>At runtime, this will be replaced with a {@link DependencyDescriptor}
28+
* for the corresponding bean property's write method, eventually to be resolved
29+
* through a {@link AutowireCapableBeanFactory#resolveDependency} step.
30+
*
31+
* @author Juergen Hoeller
32+
* @since 5.2
33+
* @see AutowireCapableBeanFactory#resolveDependency
34+
* @see BeanDefinition#getPropertyValues()
35+
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder#addAutowiredProperty
36+
*/
37+
public final class AutowiredPropertyMarker implements Serializable {
38+
39+
/**
40+
* The canonical instance for the autowired marker value.
41+
*/
42+
public static final Object INSTANCE = new AutowiredPropertyMarker();
43+
44+
45+
private AutowiredPropertyMarker() {
46+
}
47+
48+
private Object readResolve() {
49+
return INSTANCE;
50+
}
51+
52+
53+
@Override
54+
public boolean equals(@Nullable Object obj) {
55+
return (this == obj);
56+
}
57+
58+
@Override
59+
public int hashCode() {
60+
return AutowiredPropertyMarker.class.hashCode();
61+
}
62+
63+
@Override
64+
public String toString() {
65+
return "(autowired)";
66+
}
67+
68+
}

spring-beans/src/main/java/org/springframework/beans/factory/config/RuntimeBeanReference.java

+52-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,22 +26,24 @@
2626
* @author Rod Johnson
2727
* @author Juergen Hoeller
2828
* @see BeanDefinition#getPropertyValues()
29-
* @see org.springframework.beans.factory.BeanFactory#getBean
29+
* @see org.springframework.beans.factory.BeanFactory#getBean(String)
30+
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
3031
*/
3132
public class RuntimeBeanReference implements BeanReference {
3233

3334
private final String beanName;
3435

36+
@Nullable
37+
private final Class<?> beanType;
38+
3539
private final boolean toParent;
3640

3741
@Nullable
3842
private Object source;
3943

4044

4145
/**
42-
* Create a new RuntimeBeanReference to the given bean name,
43-
* without explicitly marking it as reference to a bean in
44-
* the parent factory.
46+
* Create a new RuntimeBeanReference to the given bean name.
4547
* @param beanName name of the target bean
4648
*/
4749
public RuntimeBeanReference(String beanName) {
@@ -50,27 +52,64 @@ public RuntimeBeanReference(String beanName) {
5052

5153
/**
5254
* Create a new RuntimeBeanReference to the given bean name,
53-
* with the option to mark it as reference to a bean in
54-
* the parent factory.
55+
* with the option to mark it as reference to a bean in the parent factory.
5556
* @param beanName name of the target bean
56-
* @param toParent whether this is an explicit reference to
57-
* a bean in the parent factory
57+
* @param toParent whether this is an explicit reference to a bean in the
58+
* parent factory
5859
*/
5960
public RuntimeBeanReference(String beanName, boolean toParent) {
6061
Assert.hasText(beanName, "'beanName' must not be empty");
6162
this.beanName = beanName;
63+
this.beanType = null;
6264
this.toParent = toParent;
6365
}
6466

67+
/**
68+
* Create a new RuntimeBeanReference to a bean of the given type.
69+
* @param beanType type of the target bean
70+
* @since 5.2
71+
*/
72+
public RuntimeBeanReference(Class<?> beanType) {
73+
this(beanType, false);
74+
}
6575

76+
/**
77+
* Create a new RuntimeBeanReference to a bean of the given type,
78+
* with the option to mark it as reference to a bean in the parent factory.
79+
* @param beanType type of the target bean
80+
* @param toParent whether this is an explicit reference to a bean in the
81+
* parent factory
82+
* @since 5.2
83+
*/
84+
public RuntimeBeanReference(Class<?> beanType, boolean toParent) {
85+
Assert.notNull(beanType, "'beanType' must not be empty");
86+
this.beanName = beanType.getName();
87+
this.beanType = beanType;
88+
this.toParent = toParent;
89+
}
90+
91+
92+
/**
93+
* Return the requested bean name, or the fully-qualified type name
94+
* in case of by-type resolution.
95+
* @see #getBeanType()
96+
*/
6697
@Override
6798
public String getBeanName() {
6899
return this.beanName;
69100
}
70101

71102
/**
72-
* Return whether this is an explicit reference to a bean
73-
* in the parent factory.
103+
* Return the requested bean type if resolution by type is demanded.
104+
* @since 5.2
105+
*/
106+
@Nullable
107+
public Class<?> getBeanType() {
108+
return this.beanType;
109+
}
110+
111+
/**
112+
* Return whether this is an explicit reference to a bean in the parent factory.
74113
*/
75114
public boolean isToParent() {
76115
return this.toParent;
@@ -100,7 +139,8 @@ public boolean equals(@Nullable Object other) {
100139
return false;
101140
}
102141
RuntimeBeanReference that = (RuntimeBeanReference) other;
103-
return (this.beanName.equals(that.beanName) && this.toParent == that.toParent);
142+
return (this.beanName.equals(that.beanName) && this.beanType == that.beanType &&
143+
this.toParent == that.toParent);
104144
}
105145

106146
@Override

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

+8
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.springframework.beans.factory.InjectionPoint;
6262
import org.springframework.beans.factory.UnsatisfiedDependencyException;
6363
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
64+
import org.springframework.beans.factory.config.AutowiredPropertyMarker;
6465
import org.springframework.beans.factory.config.BeanDefinition;
6566
import org.springframework.beans.factory.config.BeanPostProcessor;
6667
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -1683,6 +1684,13 @@ protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrap
16831684
else {
16841685
String propertyName = pv.getName();
16851686
Object originalValue = pv.getValue();
1687+
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
1688+
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
1689+
if (writeMethod == null) {
1690+
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
1691+
}
1692+
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
1693+
}
16861694
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
16871695
Object convertedValue = resolvedValue;
16881696
boolean convertible = bw.isWritableProperty(propertyName) &&

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.function.Supplier;
2020

21+
import org.springframework.beans.factory.config.AutowiredPropertyMarker;
2122
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
2223
import org.springframework.beans.factory.config.RuntimeBeanReference;
2324
import org.springframework.lang.Nullable;
@@ -209,7 +210,7 @@ public BeanDefinitionBuilder addConstructorArgReference(String beanName) {
209210
}
210211

211212
/**
212-
* Add the supplied property value under the given name.
213+
* Add the supplied property value under the given property name.
213214
*/
214215
public BeanDefinitionBuilder addPropertyValue(String name, @Nullable Object value) {
215216
this.beanDefinition.getPropertyValues().add(name, value);
@@ -226,6 +227,17 @@ public BeanDefinitionBuilder addPropertyReference(String name, String beanName)
226227
return this;
227228
}
228229

230+
/**
231+
* Add an autowired marker for the specified property on the specified bean.
232+
* @param name the name of the property to mark as autowired
233+
* @since 5.2
234+
* @see AutowiredPropertyMarker
235+
*/
236+
public BeanDefinitionBuilder addAutowiredProperty(String name) {
237+
this.beanDefinition.getPropertyValues().add(name, AutowiredPropertyMarker.INSTANCE);
238+
return this;
239+
}
240+
229241
/**
230242
* Set the init method for this definition.
231243
*/

0 commit comments

Comments
 (0)