1818
1919import java .util .Arrays ;
2020import java .util .Map ;
21+ import java .util .concurrent .ExecutionException ;
22+ import java .util .concurrent .ExecutorService ;
23+ import java .util .concurrent .Executors ;
24+ import java .util .concurrent .TimeUnit ;
25+ import java .util .concurrent .TimeoutException ;
2126
2227import org .assertj .core .api .Assertions ;
2328import org .junit .jupiter .api .Test ;
2429
30+ import org .springframework .boot .autoconfigure .condition .ConditionalOnClass ;
2531import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
2632import org .springframework .context .annotation .Bean ;
33+ import org .springframework .context .support .GenericApplicationContext ;
34+ import org .springframework .util .ClassUtils ;
2735
2836import static org .assertj .core .api .BDDAssertions .then ;
2937
3038/**
3139 * @author Spencer Gibb
40+ * @author Tommy Karlsson
3241 */
3342public class NamedContextFactoryTests {
3443
@@ -37,6 +46,10 @@ public void testChildContexts() {
3746 AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
3847 parent .register (BaseConfig .class );
3948 parent .refresh ();
49+ testChildContexts (parent );
50+ }
51+
52+ private void testChildContexts (GenericApplicationContext parent ) {
4053 TestClientFactory factory = new TestClientFactory ();
4154 factory .setApplicationContext (parent );
4255 factory .setConfigurations (Arrays .asList (getSpec ("foo" , FooConfig .class ), getSpec ("bar" , BarConfig .class )));
@@ -79,6 +92,10 @@ public void testChildContexts() {
7992 then (fooContext .getClassLoader ()).as ("foo context classloader does not match parent" )
8093 .isSameAs (parent .getClassLoader ());
8194
95+ then (fooContext .getBeanFactory ().getBeanClassLoader ())
96+ .as ("foo context bean factory classloader does not match parent" )
97+ .isSameAs (parent .getBeanFactory ().getBeanClassLoader ());
98+
8299 Assertions .assertThat (fooContext ).hasFieldOrPropertyWithValue ("customClassLoader" , true );
83100
84101 factory .destroy ();
@@ -88,10 +105,39 @@ public void testChildContexts() {
88105 then (barContext .isActive ()).as ("bar context wasn't closed" ).isFalse ();
89106 }
90107
108+ @ Test
109+ void testBadThreadContextClassLoader () throws InterruptedException , ExecutionException , TimeoutException {
110+ AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
111+ parent .setClassLoader (ClassUtils .getDefaultClassLoader ());
112+ parent .register (BaseConfig .class );
113+ parent .refresh ();
114+
115+ ExecutorService es = Executors .newSingleThreadExecutor (r -> {
116+ Thread t = new Thread (r );
117+ t .setContextClassLoader (new ThrowingClassLoader ());
118+ return t ;
119+ });
120+
121+ es .submit (() -> this .testChildContexts (parent )).get (5 , TimeUnit .SECONDS );
122+ }
123+
91124 private TestSpec getSpec (String name , Class <?> configClass ) {
92125 return new TestSpec (name , new Class [] { configClass });
93126 }
94127
128+ static class ThrowingClassLoader extends ClassLoader {
129+
130+ ThrowingClassLoader () {
131+ super (null );
132+ }
133+
134+ @ Override
135+ public Class <?> loadClass (String name ) throws ClassNotFoundException {
136+ throw new ClassNotFoundException (name );
137+ }
138+
139+ }
140+
95141 static class TestClientFactory extends NamedContextFactory <TestSpec > {
96142
97143 TestClientFactory () {
@@ -147,6 +193,7 @@ static class Baz {
147193
148194 }
149195
196+ @ ConditionalOnClass (Object .class )
150197 static class FooConfig {
151198
152199 @ Bean
0 commit comments