33
33
import org .springframework .beans .factory .support .BeanDefinitionRegistry ;
34
34
import org .springframework .beans .factory .support .RootBeanDefinition ;
35
35
import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
36
- import org .springframework .context .annotation .Bean ;
37
- import org .springframework .context .annotation .Configuration ;
38
36
import org .springframework .context .support .SimpleThreadScope ;
39
37
import org .springframework .core .Ordered ;
40
38
import org .springframework .core .ResolvableType ;
41
39
import org .springframework .test .context .MergedContextConfiguration ;
42
- import org .springframework .test .context .bean .override .example .ExampleBeanOverrideAnnotation ;
43
- import org .springframework .test .context .bean .override .example .ExampleService ;
44
- import org .springframework .test .context .bean .override .example .FailingExampleService ;
45
- import org .springframework .test .context .bean .override .example .RealExampleService ;
46
40
import org .springframework .test .util .ReflectionTestUtils ;
47
41
import org .springframework .util .Assert ;
48
42
56
50
* {@link BeanOverrideRegistrar}.
57
51
*
58
52
* @author Simon Baslé
53
+ * @author Stephane Nicoll
59
54
*/
60
55
class BeanOverrideBeanFactoryPostProcessorTests {
61
56
62
57
@ Test
63
58
void canReplaceExistingBeanDefinitions () {
64
- AnnotationConfigApplicationContext context = createContext (ReplaceBeans .class );
65
- context .register (ReplaceBeans .class );
66
- context .registerBean ("explicit" , ExampleService .class , () -> new RealExampleService ("unexpected" ));
67
- context .registerBean ("implicitName" , ExampleService .class , () -> new RealExampleService ("unexpected" ));
68
-
59
+ AnnotationConfigApplicationContext context = createContext (CaseByNameAndByType .class );
60
+ context .registerBean ("descriptionBean" , String .class , () -> "Original" );
61
+ context .registerBean ("someInteger" , Integer .class , () -> 1 );
69
62
context .refresh ();
70
63
71
- assertThat (context .getBean ("explicit " )).isSameAs ( OVERRIDE_SERVICE );
72
- assertThat (context .getBean ("implicitName " )).isSameAs (OVERRIDE_SERVICE );
64
+ assertThat (context .getBean ("descriptionBean " )).isEqualTo ( "overridden" );
65
+ assertThat (context .getBean ("someInteger " )).isSameAs (42 );
73
66
}
74
67
75
68
@ Test
76
- void cannotReplaceIfNoBeanMatching () {
77
- AnnotationConfigApplicationContext context = createContext (ReplaceBeans .class );
78
- context .register (ReplaceBeans .class );
79
- //note we don't register any original bean here
69
+ void cannotReplaceIfNoBeanNameMatching () {
70
+ AnnotationConfigApplicationContext context = createContext (CaseByName .class );
80
71
81
72
assertThatIllegalStateException ()
82
73
.isThrownBy (context ::refresh )
83
- .withMessage ("Unable to override bean 'explicit ': there is no bean definition " +
84
- "to replace with that name of type org.springframework.test.context.bean.override.example.ExampleService " );
74
+ .withMessage ("Unable to override bean 'descriptionBean ': there is no bean definition " +
75
+ "to replace with that name of type java.lang.String " );
85
76
}
86
77
87
78
@ Test
88
- void canReplaceExistingBeanDefinitionsWithCreateReplaceStrategy () {
89
- AnnotationConfigApplicationContext context = createContext (CreateIfOriginalIsMissingBean .class );
90
- context .register (CreateIfOriginalIsMissingBean .class );
91
- context .registerBean ("explicit" , ExampleService .class , () -> new RealExampleService ("unexpected" ));
92
- context .registerBean ("implicitName" , ExampleService .class , () -> new RealExampleService ("unexpected" ));
79
+ void cannotReplaceIfNoBeanTypeMatching () {
80
+ AnnotationConfigApplicationContext context = createContext (CaseByType .class );
93
81
82
+ assertThatIllegalStateException ()
83
+ .isThrownBy (context ::refresh )
84
+ .withMessage ("Unable to override bean: no bean definitions of type java.lang.Integer " +
85
+ "(as required by annotated field 'CaseByType.counter')" );
86
+ }
87
+
88
+ @ Test
89
+ void canReplaceExistingBeanDefinitionsWithCreateReplaceStrategy () {
90
+ AnnotationConfigApplicationContext context = createContext (CaseByNameAndByTypeWithReplaceOrCreateStrategy .class );
91
+ context .register (CaseByNameAndByTypeWithReplaceOrCreateStrategy .class );
92
+ context .registerBean ("descriptionBean" , String .class , () -> "Original" );
93
+ context .registerBean ("someInteger" , Integer .class , () -> 1 );
94
94
context .refresh ();
95
95
96
- assertThat (context .getBean ("explicit " )).isSameAs ( OVERRIDE_SERVICE );
97
- assertThat (context .getBean ("implicitName " )).isSameAs ( OVERRIDE_SERVICE );
96
+ assertThat (context .getBean ("descriptionBean " )).isEqualTo ( "overridden" );
97
+ assertThat (context .getBean ("someInteger " )).isEqualTo ( 42 );
98
98
}
99
99
100
100
@ Test
101
101
void canCreateIfOriginalMissingWithCreateReplaceStrategy () {
102
- AnnotationConfigApplicationContext context = createContext (CreateIfOriginalIsMissingBean .class );
103
- context .register (CreateIfOriginalIsMissingBean .class );
104
- //note we don't register original beans here
105
-
102
+ AnnotationConfigApplicationContext context = createContext (CaseByNameAndByTypeWithReplaceOrCreateStrategy .class );
106
103
context .refresh ();
107
104
108
- assertThat (context .getBean ("explicit" )).isSameAs (OVERRIDE_SERVICE );
109
- assertThat (context .getBean ("implicitName" )).isSameAs (OVERRIDE_SERVICE );
105
+ String byTypeGeneratedBeanName = "java.lang.Integer#0" ;
106
+ assertThat (context .getBeanDefinitionNames ()).contains ("descriptionBean" , byTypeGeneratedBeanName );
107
+ assertThat (context .getBean ("descriptionBean" )).isEqualTo ("overridden" );
108
+ assertThat (context .getBean (byTypeGeneratedBeanName )).isEqualTo (42 );
110
109
}
111
110
112
111
@ Test
113
112
void canOverrideBeanProducedByFactoryBeanWithClassObjectTypeAttribute () {
114
- AnnotationConfigApplicationContext context = createContext (OverriddenFactoryBean .class );
115
- RootBeanDefinition factoryBeanDefinition = new RootBeanDefinition (TestFactoryBean .class );
116
- factoryBeanDefinition .setAttribute (FactoryBean .OBJECT_TYPE_ATTRIBUTE , SomeInterface .class );
117
- context .registerBeanDefinition ("beanToBeOverridden" , factoryBeanDefinition );
118
- context .register (OverriddenFactoryBean .class );
119
-
113
+ AnnotationConfigApplicationContext context = prepareContextWithFactoryBean (CharSequence .class );
120
114
context .refresh ();
121
115
122
- assertThat (context .getBean ("beanToBeOverridden" )).isSameAs ( OVERRIDE );
116
+ assertThat (context .getBean ("beanToBeOverridden" )).isEqualTo ( "overridden" );
123
117
}
124
118
125
119
@ Test
126
120
void canOverrideBeanProducedByFactoryBeanWithResolvableTypeObjectTypeAttribute () {
127
- AnnotationConfigApplicationContext context = createContext (OverriddenFactoryBean .class );
128
- RootBeanDefinition factoryBeanDefinition = new RootBeanDefinition (TestFactoryBean .class );
129
- ResolvableType objectType = ResolvableType .forClass (SomeInterface .class );
130
- factoryBeanDefinition .setAttribute (FactoryBean .OBJECT_TYPE_ATTRIBUTE , objectType );
131
- context .registerBeanDefinition ("beanToBeOverridden" , factoryBeanDefinition );
132
- context .register (OverriddenFactoryBean .class );
133
-
121
+ AnnotationConfigApplicationContext context = prepareContextWithFactoryBean (ResolvableType .forClass (CharSequence .class ));
134
122
context .refresh ();
135
123
136
- assertThat (context .getBean ("beanToBeOverridden" )).isSameAs (OVERRIDE );
124
+ assertThat (context .getBean ("beanToBeOverridden" )).isEqualTo ("overridden" );
125
+ }
126
+
127
+ private AnnotationConfigApplicationContext prepareContextWithFactoryBean (Object objectTypeAttribute ) {
128
+ AnnotationConfigApplicationContext context = createContext (CaseOverrideBeanProducedByFactoryBean .class );
129
+ context .registerBean ("testFactoryBean" , TestFactoryBean .class , TestFactoryBean ::new );
130
+ RootBeanDefinition factoryBeanDefinition = new RootBeanDefinition (TestFactoryBean .class );
131
+ factoryBeanDefinition .setAttribute (FactoryBean .OBJECT_TYPE_ATTRIBUTE , objectTypeAttribute );
132
+ context .registerBeanDefinition ("beanToBeOverridden" , factoryBeanDefinition );
133
+ return context ;
137
134
}
138
135
139
136
@ Test
140
137
void postProcessorShouldNotTriggerEarlyInitialization () {
141
- AnnotationConfigApplicationContext context = createContext (EagerInitBean .class );
138
+ AnnotationConfigApplicationContext context = createContext (CaseByTypeWithReplaceOrCreateStrategy .class );
142
139
143
140
context .register (FactoryBeanRegisteringPostProcessor .class );
144
141
context .register (EarlyBeanInitializationDetector .class );
145
- context .register (EagerInitBean .class );
146
142
147
143
assertThatNoException ().isThrownBy (context ::refresh );
148
144
}
149
145
150
146
@ Test
151
147
void allowReplaceDefinitionWhenSingletonDefinitionPresent () {
152
- AnnotationConfigApplicationContext context = createContext (SingletonBean .class );
148
+ AnnotationConfigApplicationContext context = createContext (CaseByName .class );
153
149
RootBeanDefinition definition = new RootBeanDefinition (String .class , () -> "ORIGINAL" );
154
150
definition .setScope (BeanDefinition .SCOPE_SINGLETON );
155
- context .registerBeanDefinition ("singleton" , definition );
156
- context .register (SingletonBean .class );
151
+ context .registerBeanDefinition ("descriptionBean" , definition );
157
152
158
153
assertThatNoException ().isThrownBy (context ::refresh );
159
- assertThat (context .isSingleton ("singleton " )).as ("isSingleton" ).isTrue ();
160
- assertThat (context .getBean ("singleton " )).as ( "overridden" ). isEqualTo ("USED THIS " );
154
+ assertThat (context .isSingleton ("descriptionBean " )).as ("isSingleton" ).isTrue ();
155
+ assertThat (context .getBean ("descriptionBean " )).isEqualTo ("overridden " );
161
156
}
162
157
163
158
@ Test
164
159
void copyDefinitionPrimaryFallbackAndScope () {
165
- AnnotationConfigApplicationContext context = createContext (SingletonBean .class );
160
+ AnnotationConfigApplicationContext context = createContext (CaseByName .class );
166
161
context .getBeanFactory ().registerScope ("customScope" , new SimpleThreadScope ());
167
162
RootBeanDefinition definition = new RootBeanDefinition (String .class , () -> "ORIGINAL" );
168
163
definition .setScope ("customScope" );
169
164
definition .setPrimary (true );
170
165
definition .setFallback (true );
171
- context .registerBeanDefinition ("singleton" , definition );
172
- context .register (SingletonBean .class );
166
+ context .registerBeanDefinition ("descriptionBean" , definition );
173
167
174
168
assertThatNoException ().isThrownBy (context ::refresh );
175
- assertThat (context .getBeanDefinition ("singleton " ))
169
+ assertThat (context .getBeanDefinition ("descriptionBean " ))
176
170
.isNotSameAs (definition )
177
171
.matches (BeanDefinition ::isPrimary , "isPrimary" )
178
172
.matches (BeanDefinition ::isFallback , "isFallback" )
@@ -183,22 +177,20 @@ void copyDefinitionPrimaryFallbackAndScope() {
183
177
184
178
@ Test
185
179
void createDefinitionShouldSetQualifierElement () {
186
- AnnotationConfigApplicationContext context = createContext (QualifiedBean .class );
187
- context .registerBeanDefinition ("singleton" , new RootBeanDefinition (String .class , () -> "ORIGINAL" ));
188
- context .register (QualifiedBean .class );
180
+ AnnotationConfigApplicationContext context = createContext (CaseByNameWithQualifier .class );
181
+ context .registerBeanDefinition ("descriptionBean" , new RootBeanDefinition (String .class , () -> "ORIGINAL" ));
189
182
190
183
assertThatNoException ().isThrownBy (context ::refresh );
191
-
192
- assertThat (context .getBeanDefinition ("singleton" ))
184
+ assertThat (context .getBeanDefinition ("descriptionBean" ))
193
185
.isInstanceOfSatisfying (RootBeanDefinition .class , this ::isTheValueField );
194
186
}
195
187
196
188
197
189
private void isTheValueField (RootBeanDefinition def ) {
198
190
assertThat (def .getQualifiedElement ()).isInstanceOfSatisfying (Field .class , field -> {
199
- assertThat (field .getDeclaringClass ()).isEqualTo (QualifiedBean .class );
191
+ assertThat (field .getDeclaringClass ()).isEqualTo (CaseByNameWithQualifier .class );
200
192
assertThat (field .getName ()).as ("annotated field name" )
201
- .isEqualTo ("value " );
193
+ .isEqualTo ("description " );
202
194
});
203
195
}
204
196
@@ -210,99 +202,67 @@ private AnnotationConfigApplicationContext createContext(Class<?> testClass) {
210
202
}
211
203
212
204
213
- /*
214
- Classes to parse and register with the bean post processor
215
- -----
216
- Note that some of these are both a @Configuration class and bean override field holder.
217
- This is for this test convenience, as typically the bean override annotated fields
218
- should not be in configuration classes but rather in test case classes
219
- (where a TestExecutionListener automatically discovers and parses them).
220
- */
205
+ static class CaseByName {
221
206
222
- static final SomeInterface OVERRIDE = new SomeImplementation ();
207
+ @ DummyBean (beanName = "descriptionBean" )
208
+ private String description ;
223
209
224
- static final ExampleService OVERRIDE_SERVICE = new FailingExampleService ();
225
-
226
- static class ReplaceBeans {
210
+ }
227
211
228
- @ ExampleBeanOverrideAnnotation (value = "useThis" , beanName = "explicit" )
229
- private ExampleService explicitName ;
212
+ static class CaseByType {
230
213
231
- @ ExampleBeanOverrideAnnotation ( value = "useThis" )
232
- private ExampleService implicitName ;
214
+ @ DummyBean
215
+ private Integer counter ;
233
216
234
- static ExampleService useThis () {
235
- return OVERRIDE_SERVICE ;
236
- }
237
217
}
238
218
239
- static class CreateIfOriginalIsMissingBean {
219
+ static class CaseByNameAndByType {
240
220
241
- @ ExampleBeanOverrideAnnotation ( value = "useThis" , createIfMissing = true , beanName = "explicit " )
242
- private ExampleService explicitName ;
221
+ @ DummyBean ( beanName = "descriptionBean " )
222
+ private String description ;
243
223
244
- @ ExampleBeanOverrideAnnotation ( value = "useThis" , createIfMissing = true )
245
- private ExampleService implicitName ;
224
+ @ DummyBean
225
+ private Integer counter ;
246
226
247
- static ExampleService useThis () {
248
- return OVERRIDE_SERVICE ;
249
- }
250
227
}
251
228
252
- @ Configuration (proxyBeanMethods = false )
253
- static class OverriddenFactoryBean {
229
+ static class CaseByTypeWithReplaceOrCreateStrategy {
254
230
255
- @ ExampleBeanOverrideAnnotation (value = "fOverride" , beanName = "beanToBeOverridden" )
256
- SomeInterface f ;
257
-
258
- static SomeInterface fOverride () {
259
- return OVERRIDE ;
260
- }
231
+ @ DummyBean (strategy = BeanOverrideStrategy .REPLACE_OR_CREATE_DEFINITION )
232
+ private String description ;
261
233
262
- @ Bean
263
- TestFactoryBean testFactoryBean () {
264
- return new TestFactoryBean ();
265
- }
266
234
}
267
235
268
- static class EagerInitBean {
236
+ static class CaseByNameAndByTypeWithReplaceOrCreateStrategy {
269
237
270
- @ ExampleBeanOverrideAnnotation (value = "useThis" , createIfMissing = true )
271
- private ExampleService service ;
238
+ @ DummyBean (beanName = "descriptionBean" , strategy = BeanOverrideStrategy .REPLACE_OR_CREATE_DEFINITION )
239
+ private String description ;
240
+
241
+ @ DummyBean (strategy = BeanOverrideStrategy .REPLACE_OR_CREATE_DEFINITION )
242
+ private Integer counter ;
272
243
273
- static ExampleService useThis () {
274
- return OVERRIDE_SERVICE ;
275
- }
276
244
}
277
245
278
- static class SingletonBean {
246
+ static class CaseOverrideBeanProducedByFactoryBean {
279
247
280
- @ ExampleBeanOverrideAnnotation (beanName = "singleton" ,
281
- value = "useThis" , createIfMissing = false )
282
- private String value ;
248
+ @ DummyBean (beanName = "beanToBeOverridden" )
249
+ CharSequence description ;
283
250
284
- static String useThis () {
285
- return "USED THIS" ;
286
- }
287
251
}
288
252
289
- static class QualifiedBean {
253
+ static class CaseByNameWithQualifier {
290
254
291
255
@ Qualifier ("preferThis" )
292
- @ ExampleBeanOverrideAnnotation (beanName = "singleton" ,
293
- value = "useThis" , createIfMissing = false )
294
- private String value ;
256
+ @ DummyBean (beanName = "descriptionBean" )
257
+ private String description ;
295
258
296
- static String useThis () {
297
- return "USED THIS" ;
298
- }
299
259
}
300
260
301
261
static class TestFactoryBean implements FactoryBean <Object > {
302
262
303
263
@ Override
304
264
public Object getObject () {
305
- return new SomeImplementation () ;
265
+ return "test" ;
306
266
}
307
267
308
268
@ Override
@@ -341,10 +301,4 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
341
301
}
342
302
}
343
303
344
- interface SomeInterface {
345
- }
346
-
347
- static class SomeImplementation implements SomeInterface {
348
- }
349
-
350
304
}
0 commit comments