11/*
2- * Copyright 2012-2020 the original author or authors.
2+ * Copyright 2012-2024 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.
1616
1717package org .springframework .cloud .context .named ;
1818
19+ import java .lang .annotation .Documented ;
20+ import java .lang .annotation .ElementType ;
21+ import java .lang .annotation .Inherited ;
22+ import java .lang .annotation .Retention ;
23+ import java .lang .annotation .RetentionPolicy ;
24+ import java .lang .annotation .Target ;
1925import java .util .Arrays ;
26+ import java .util .List ;
2027import java .util .Map ;
2128import java .util .concurrent .ExecutionException ;
2229import java .util .concurrent .ExecutorService ;
2330import java .util .concurrent .Executors ;
2431import java .util .concurrent .TimeUnit ;
2532import java .util .concurrent .TimeoutException ;
2633
27- import org .assertj .core .api .Assertions ;
2834import org .junit .jupiter .api .Test ;
2935
3036import org .springframework .boot .autoconfigure .condition .ConditionalOnClass ;
3137import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
3238import org .springframework .context .annotation .Bean ;
3339import org .springframework .context .support .GenericApplicationContext ;
40+ import org .springframework .core .ResolvableType ;
3441import org .springframework .util .ClassUtils ;
3542
43+ import static org .assertj .core .api .Assertions .assertThat ;
44+ import static org .assertj .core .api .Assertions .assertThatIllegalStateException ;
3645import static org .assertj .core .api .BDDAssertions .then ;
3746
3847/**
@@ -50,6 +59,64 @@ public void testChildContexts() {
5059 testChildContexts (parent );
5160 }
5261
62+ @ Test
63+ void testBadThreadContextClassLoader () throws InterruptedException , ExecutionException , TimeoutException {
64+ AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
65+ parent .setClassLoader (ClassUtils .getDefaultClassLoader ());
66+ parent .register (BaseConfig .class );
67+ parent .refresh ();
68+
69+ ExecutorService es = Executors .newSingleThreadExecutor (r -> {
70+ Thread t = new Thread (r );
71+ t .setContextClassLoader (new ThrowingClassLoader ());
72+ return t ;
73+ });
74+ es .submit (() -> this .testChildContexts (parent )).get (5 , TimeUnit .SECONDS );
75+
76+ }
77+
78+ @ Test
79+ void testGetAnnotatedBeanInstance () {
80+ AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
81+ parent .register (BaseConfig .class );
82+ parent .refresh ();
83+ TestClientFactory factory = new TestClientFactory ();
84+ factory .setApplicationContext (parent );
85+ factory .setConfigurations (List .of (getSpec ("annotated" , AnnotatedConfig .class )));
86+
87+ TestType annotatedBean = factory .getAnnotatedInstance ("annotated" , ResolvableType .forType (TestType .class ),
88+ TestBean .class );
89+
90+ assertThat (annotatedBean .value ()).isEqualTo (2 );
91+ }
92+
93+ @ Test
94+ void testNoAnnotatedBeanInstance () {
95+ AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
96+ parent .register (BaseConfig .class );
97+ parent .refresh ();
98+ TestClientFactory factory = new TestClientFactory ();
99+ factory .setApplicationContext (parent );
100+ factory .setConfigurations (List .of (getSpec ("not-annotated" , NotAnnotatedConfig .class )));
101+
102+ TestType annotatedBean = factory .getAnnotatedInstance ("not-annotated" , ResolvableType .forType (TestType .class ),
103+ TestBean .class );
104+ assertThat (annotatedBean ).isNull ();
105+ }
106+
107+ @ Test
108+ void testMoreThanOneAnnotatedBeanInstance () {
109+ AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
110+ parent .register (BaseConfig .class );
111+ parent .refresh ();
112+ TestClientFactory factory = new TestClientFactory ();
113+ factory .setApplicationContext (parent );
114+ factory .setConfigurations (List .of (getSpec ("many-annotated" , ManyAnnotatedConfig .class )));
115+
116+ assertThatIllegalStateException ().isThrownBy (() -> factory .getAnnotatedInstance ("many-annotated" ,
117+ ResolvableType .forType (TestType .class ), TestBean .class ));
118+ }
119+
53120 private void testChildContexts (GenericApplicationContext parent ) {
54121 TestClientFactory factory = new TestClientFactory ();
55122 factory .setApplicationContext (parent );
@@ -97,7 +164,7 @@ private void testChildContexts(GenericApplicationContext parent) {
97164 .as ("foo context bean factory classloader does not match parent" )
98165 .isSameAs (parent .getBeanFactory ().getBeanClassLoader ());
99166
100- Assertions . assertThat (fooContext ).hasFieldOrPropertyWithValue ("customClassLoader" , true );
167+ assertThat (fooContext ).hasFieldOrPropertyWithValue ("customClassLoader" , true );
101168
102169 factory .destroy ();
103170
@@ -106,22 +173,6 @@ private void testChildContexts(GenericApplicationContext parent) {
106173 then (barContext .isActive ()).as ("bar context wasn't closed" ).isFalse ();
107174 }
108175
109- @ Test
110- void testBadThreadContextClassLoader () throws InterruptedException , ExecutionException , TimeoutException {
111- AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
112- parent .setClassLoader (ClassUtils .getDefaultClassLoader ());
113- parent .register (BaseConfig .class );
114- parent .refresh ();
115-
116- ExecutorService es = Executors .newSingleThreadExecutor (r -> {
117- Thread t = new Thread (r );
118- t .setContextClassLoader (new ThrowingClassLoader ());
119- return t ;
120- });
121-
122- es .submit (() -> this .testChildContexts (parent )).get (5 , TimeUnit .SECONDS );
123- }
124-
125176 private TestSpec getSpec (String name , Class <?> configClass ) {
126177 return new TestSpec (name , new Class [] { configClass });
127178 }
@@ -236,18 +287,81 @@ static class Bar {
236287
237288 }
238289
239- static class Container <T > {
290+ record Container <T > (T item ) {
291+
292+ }
293+
294+ static class AnnotatedConfig {
295+
296+ @ Bean
297+ TestType test1 () {
298+ return new TestType (1 );
299+ }
240300
241- private final T item ;
301+ @ TestBean
302+ @ Bean
303+ TestType test2 () {
304+ return new TestType (2 );
305+ }
242306
243- Container (T item ) {
244- this .item = item ;
307+ @ TestBean
308+ @ Bean
309+ Bar bar () {
310+ return new Bar ();
245311 }
246312
247- public T getItem () {
248- return this .item ;
313+ }
314+
315+ static class NotAnnotatedConfig {
316+
317+ @ Bean
318+ TestType test1 () {
319+ return new TestType (1 );
249320 }
250321
322+ @ Bean
323+ TestType test2 () {
324+ return new TestType (2 );
325+ }
326+
327+ @ TestBean
328+ @ Bean
329+ Bar bar () {
330+ return new Bar ();
331+ }
332+
333+ }
334+
335+ static class ManyAnnotatedConfig {
336+
337+ @ TestBean
338+ @ Bean
339+ TestType test1 () {
340+ return new TestType (1 );
341+ }
342+
343+ @ TestBean
344+ @ Bean
345+ TestType test2 () {
346+ return new TestType (2 );
347+ }
348+
349+ @ Bean
350+ Bar bar () {
351+ return new Bar ();
352+ }
353+
354+ }
355+
356+ record TestType (int value ) {
357+ }
358+
359+ @ Target ({ ElementType .TYPE , ElementType .METHOD })
360+ @ Retention (RetentionPolicy .RUNTIME )
361+ @ Documented
362+ @ Inherited
363+ @interface TestBean {
364+
251365 }
252366
253367}
0 commit comments