2020import java .io .FileOutputStream ;
2121import java .io .IOException ;
2222import java .io .InputStream ;
23+ import java .net .MalformedURLException ;
2324import java .net .URL ;
2425import java .net .URLClassLoader ;
2526import java .nio .charset .StandardCharsets ;
3637import org .junit .jupiter .api .io .TempDir ;
3738
3839import org .springframework .aop .framework .ProxyFactory ;
40+ import org .springframework .aop .support .AopUtils ;
3941import org .springframework .boot .devtools .restart .classloader .ClassLoaderFile .Kind ;
42+ import org .springframework .boot .test .context .runner .ApplicationContextRunner ;
43+ import org .springframework .context .annotation .Bean ;
44+ import org .springframework .context .annotation .Configuration ;
45+ import org .springframework .context .annotation .EnableAspectJAutoProxy ;
46+ import org .springframework .transaction .annotation .EnableTransactionManagement ;
47+ import org .springframework .transaction .annotation .Transactional ;
4048import org .springframework .util .FileCopyUtils ;
4149import org .springframework .util .StreamUtils ;
4250
@@ -210,6 +218,20 @@ void proxyOnClassFromSystemClassLoaderDoesNotYieldWarning() {
210218 // Warning would happen outside the boundary of the test
211219 }
212220
221+ @ Test
222+ void packagePrivateClassLoadedByParentClassLoaderCanBeProxied () throws MalformedURLException {
223+ new ApplicationContextRunner ()
224+ .withClassLoader (new RestartClassLoader (ExampleTransactional .class .getClassLoader (),
225+ new URL [] { this .sampleJarFile .toURI ().toURL () }, this .updatedFiles ))
226+ .withUserConfiguration (ProxyConfiguration .class ).run ((context ) -> {
227+ assertThat (context ).hasNotFailed ();
228+ ExampleTransactional transactional = context .getBean (ExampleTransactional .class );
229+ assertThat (AopUtils .isCglibProxy (transactional )).isTrue ();
230+ assertThat (transactional .getClass ().getClassLoader ())
231+ .isEqualTo (ExampleTransactional .class .getClassLoader ());
232+ });
233+ }
234+
213235 private String readString (InputStream in ) throws IOException {
214236 return new String (FileCopyUtils .copyToByteArray (in ));
215237 }
@@ -218,4 +240,32 @@ private <T> List<T> toList(Enumeration<T> enumeration) {
218240 return (enumeration != null ) ? Collections .list (enumeration ) : Collections .emptyList ();
219241 }
220242
243+ @ Configuration (proxyBeanMethods = false )
244+ @ EnableAspectJAutoProxy (proxyTargetClass = true )
245+ @ EnableTransactionManagement
246+ static class ProxyConfiguration {
247+
248+ @ Bean
249+ ExampleTransactional exampleTransactional () {
250+ return new ExampleTransactional ();
251+ }
252+
253+ }
254+
255+ static class ExampleTransactional implements ExampleInterface {
256+
257+ @ Override
258+ @ Transactional
259+ public String doIt () {
260+ return "hello" ;
261+ }
262+
263+ }
264+
265+ interface ExampleInterface {
266+
267+ String doIt ();
268+
269+ }
270+
221271}
0 commit comments