11/*
2- * Copyright 2002-2024 the original author or authors.
2+ * Copyright 2002-2025 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.
1818
1919import java .io .IOException ;
2020import java .io .InputStream ;
21+ import java .net .URL ;
22+ import java .net .URLClassLoader ;
23+ import java .security .ProtectionDomain ;
2124import java .security .SecureClassLoader ;
2225
2326import org .junit .jupiter .api .Test ;
2427
28+ import org .springframework .core .OverridingClassLoader ;
2529import org .springframework .core .SmartClassLoader ;
30+ import org .springframework .lang .Nullable ;
2631import org .springframework .util .StreamUtils ;
2732
2833import static org .assertj .core .api .Assertions .assertThat ;
@@ -36,29 +41,138 @@ class ConfigurationClassEnhancerTests {
3641 @ Test
3742 void enhanceReloadedClass () throws Exception {
3843 ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer ();
44+
3945 ClassLoader parentClassLoader = getClass ().getClassLoader ();
40- CustomClassLoader classLoader = new CustomClassLoader (parentClassLoader );
46+ ClassLoader classLoader = new CustomSmartClassLoader (parentClassLoader );
4147 Class <?> myClass = parentClassLoader .loadClass (MyConfig .class .getName ());
42- configurationClassEnhancer .enhance (myClass , parentClassLoader );
43- Class <?> myReloadedClass = classLoader .loadClass (MyConfig .class .getName ());
44- Class <?> enhancedReloadedClass = configurationClassEnhancer .enhance (myReloadedClass , classLoader );
45- assertThat (enhancedReloadedClass .getClassLoader ()).isEqualTo (classLoader );
48+ Class <?> enhancedClass = configurationClassEnhancer .enhance (myClass , parentClassLoader );
49+ assertThat (myClass ).isAssignableFrom (enhancedClass );
50+
51+ myClass = classLoader .loadClass (MyConfig .class .getName ());
52+ enhancedClass = configurationClassEnhancer .enhance (myClass , classLoader );
53+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader );
54+ assertThat (myClass ).isAssignableFrom (enhancedClass );
55+ }
56+
57+ @ Test
58+ void withPublicClass () {
59+ ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer ();
60+
61+ ClassLoader classLoader = new URLClassLoader (new URL [0 ], getClass ().getClassLoader ());
62+ Class <?> enhancedClass = configurationClassEnhancer .enhance (MyConfigWithPublicClass .class , classLoader );
63+ assertThat (MyConfigWithPublicClass .class ).isAssignableFrom (enhancedClass );
64+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader );
65+
66+ classLoader = new OverridingClassLoader (getClass ().getClassLoader ());
67+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithPublicClass .class , classLoader );
68+ assertThat (MyConfigWithPublicClass .class ).isAssignableFrom (enhancedClass );
69+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
70+
71+ classLoader = new CustomSmartClassLoader (getClass ().getClassLoader ());
72+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithPublicClass .class , classLoader );
73+ assertThat (MyConfigWithPublicClass .class ).isAssignableFrom (enhancedClass );
74+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
75+
76+ classLoader = new BasicSmartClassLoader (getClass ().getClassLoader ());
77+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithPublicClass .class , classLoader );
78+ assertThat (MyConfigWithPublicClass .class ).isAssignableFrom (enhancedClass );
79+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
80+ }
81+
82+ @ Test
83+ void withNonPublicClass () {
84+ ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer ();
85+
86+ ClassLoader classLoader = new URLClassLoader (new URL [0 ], getClass ().getClassLoader ());
87+ Class <?> enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicClass .class , classLoader );
88+ assertThat (MyConfigWithNonPublicClass .class ).isAssignableFrom (enhancedClass );
89+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
90+
91+ classLoader = new OverridingClassLoader (getClass ().getClassLoader ());
92+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicClass .class , classLoader );
93+ assertThat (MyConfigWithNonPublicClass .class ).isAssignableFrom (enhancedClass );
94+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
95+
96+ classLoader = new CustomSmartClassLoader (getClass ().getClassLoader ());
97+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicClass .class , classLoader );
98+ assertThat (MyConfigWithNonPublicClass .class ).isAssignableFrom (enhancedClass );
99+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
100+
101+ classLoader = new BasicSmartClassLoader (getClass ().getClassLoader ());
102+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicClass .class , classLoader );
103+ assertThat (MyConfigWithNonPublicClass .class ).isAssignableFrom (enhancedClass );
104+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
105+ }
106+
107+ @ Test
108+ void withNonPublicMethod () {
109+ ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer ();
110+
111+ ClassLoader classLoader = new URLClassLoader (new URL [0 ], getClass ().getClassLoader ());
112+ Class <?> enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicMethod .class , classLoader );
113+ assertThat (MyConfigWithNonPublicMethod .class ).isAssignableFrom (enhancedClass );
114+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader );
115+
116+ classLoader = new OverridingClassLoader (getClass ().getClassLoader ());
117+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicMethod .class , classLoader );
118+ assertThat (MyConfigWithNonPublicMethod .class ).isAssignableFrom (enhancedClass );
119+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
120+
121+ classLoader = new CustomSmartClassLoader (getClass ().getClassLoader ());
122+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicMethod .class , classLoader );
123+ assertThat (MyConfigWithNonPublicMethod .class ).isAssignableFrom (enhancedClass );
124+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
125+
126+ classLoader = new BasicSmartClassLoader (getClass ().getClassLoader ());
127+ enhancedClass = configurationClassEnhancer .enhance (MyConfigWithNonPublicMethod .class , classLoader );
128+ assertThat (MyConfigWithNonPublicMethod .class ).isAssignableFrom (enhancedClass );
129+ assertThat (enhancedClass .getClassLoader ()).isEqualTo (classLoader .getParent ());
46130 }
47131
48132
49133 @ Configuration
50134 static class MyConfig {
51135
136+ @ Bean
137+ String myBean () {
138+ return "bean" ;
139+ }
140+ }
141+
142+
143+ @ Configuration
144+ public static class MyConfigWithPublicClass {
145+
52146 @ Bean
53147 public String myBean () {
54148 return "bean" ;
55149 }
56150 }
57151
58152
59- static class CustomClassLoader extends SecureClassLoader implements SmartClassLoader {
153+ @ Configuration
154+ static class MyConfigWithNonPublicClass {
60155
61- CustomClassLoader (ClassLoader parent ) {
156+ @ Bean
157+ public String myBean () {
158+ return "bean" ;
159+ }
160+ }
161+
162+
163+ @ Configuration
164+ public static class MyConfigWithNonPublicMethod {
165+
166+ @ Bean
167+ String myBean () {
168+ return "bean" ;
169+ }
170+ }
171+
172+
173+ static class CustomSmartClassLoader extends SecureClassLoader implements SmartClassLoader {
174+
175+ CustomSmartClassLoader (ClassLoader parent ) {
62176 super (parent );
63177 }
64178
@@ -82,6 +196,29 @@ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundE
82196 public boolean isClassReloadable (Class <?> clazz ) {
83197 return clazz .getName ().contains ("MyConfig" );
84198 }
199+
200+ @ Override
201+ public ClassLoader getOriginalClassLoader () {
202+ return getParent ();
203+ }
204+
205+ @ Override
206+ public Class <?> publicDefineClass (String name , byte [] b , @ Nullable ProtectionDomain protectionDomain ) {
207+ return defineClass (name , b , 0 , b .length , protectionDomain );
208+ }
209+ }
210+
211+
212+ static class BasicSmartClassLoader extends SecureClassLoader implements SmartClassLoader {
213+
214+ BasicSmartClassLoader (ClassLoader parent ) {
215+ super (parent );
216+ }
217+
218+ @ Override
219+ public Class <?> publicDefineClass (String name , byte [] b , @ Nullable ProtectionDomain protectionDomain ) {
220+ return defineClass (name , b , 0 , b .length , protectionDomain );
221+ }
85222 }
86223
87224}
0 commit comments