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
@@ -37,6 +45,10 @@ public void testChildContexts() {
3745 AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext ();
3846 parent .register (BaseConfig .class );
3947 parent .refresh ();
48+ testChildContexts (parent );
49+ }
50+
51+ private void testChildContexts (GenericApplicationContext parent ) {
4052 TestClientFactory factory = new TestClientFactory ();
4153 factory .setApplicationContext (parent );
4254 factory .setConfigurations (Arrays .asList (getSpec ("foo" , FooConfig .class ), getSpec ("bar" , BarConfig .class )));
@@ -79,6 +91,10 @@ public void testChildContexts() {
7991 then (fooContext .getClassLoader ()).as ("foo context classloader does not match parent" )
8092 .isSameAs (parent .getClassLoader ());
8193
94+ then (fooContext .getBeanFactory ().getBeanClassLoader ())
95+ .as ("foo context bean factory classloader does not match parent" )
96+ .isSameAs (parent .getBeanFactory ().getBeanClassLoader ());
97+
8298 Assertions .assertThat (fooContext ).hasFieldOrPropertyWithValue ("customClassLoader" , true );
8399
84100 factory .destroy ();
@@ -88,10 +104,40 @@ public void testChildContexts() {
88104 then (barContext .isActive ()).as ("bar context wasn't closed" ).isFalse ();
89105 }
90106
107+ @ Test
108+ public void testBadThreadContextClassLoader () throws InterruptedException , ExecutionException , TimeoutException {
109+
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 ("Throwing classloader" , 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