Skip to content

Commit 3b6beca

Browse files
committed
Check for package-visible constructor in case of ClassLoader mismatch
Closes gh-34950 (cherry picked from commit 15d1455)
1 parent 59ffbd7 commit 3b6beca

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.context.annotation;
1818

19+
import java.lang.reflect.Constructor;
1920
import java.lang.reflect.Field;
2021
import java.lang.reflect.Method;
2122
import java.lang.reflect.Modifier;
@@ -139,14 +140,20 @@ public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader)
139140
}
140141

141142
/**
142-
* Checks whether the given config class relies on package visibility,
143-
* either for the class itself or for any of its {@code @Bean} methods.
143+
* Checks whether the given config class relies on package visibility, either for
144+
* the class and any of its constructors or for any of its {@code @Bean} methods.
144145
*/
145146
private boolean reliesOnPackageVisibility(Class<?> configSuperClass) {
146147
int mod = configSuperClass.getModifiers();
147148
if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod)) {
148149
return true;
149150
}
151+
for (Constructor<?> ctor : configSuperClass.getDeclaredConstructors()) {
152+
mod = ctor.getModifiers();
153+
if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod)) {
154+
return true;
155+
}
156+
}
150157
for (Method method : ReflectionUtils.getDeclaredMethods(configSuperClass)) {
151158
if (BeanAnnotationHelper.isBeanAnnotated(method)) {
152159
mod = method.getModifiers();

spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassEnhancerTests.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,31 @@ void withNonPublicClass() {
104104
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent());
105105
}
106106

107+
@Test
108+
void withNonPublicConstructor() {
109+
ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer();
110+
111+
ClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());
112+
Class<?> enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicConstructor.class, classLoader);
113+
assertThat(MyConfigWithNonPublicConstructor.class).isAssignableFrom(enhancedClass);
114+
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent());
115+
116+
classLoader = new OverridingClassLoader(getClass().getClassLoader());
117+
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicConstructor.class, classLoader);
118+
assertThat(MyConfigWithNonPublicConstructor.class).isAssignableFrom(enhancedClass);
119+
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent());
120+
121+
classLoader = new CustomSmartClassLoader(getClass().getClassLoader());
122+
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicConstructor.class, classLoader);
123+
assertThat(MyConfigWithNonPublicConstructor.class).isAssignableFrom(enhancedClass);
124+
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent());
125+
126+
classLoader = new BasicSmartClassLoader(getClass().getClassLoader());
127+
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicConstructor.class, classLoader);
128+
assertThat(MyConfigWithNonPublicConstructor.class).isAssignableFrom(enhancedClass);
129+
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent());
130+
}
131+
107132
@Test
108133
void withNonPublicMethod() {
109134
ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer();
@@ -160,6 +185,19 @@ public String myBean() {
160185
}
161186

162187

188+
@Configuration
189+
public static class MyConfigWithNonPublicConstructor {
190+
191+
MyConfigWithNonPublicConstructor() {
192+
}
193+
194+
@Bean
195+
public String myBean() {
196+
return "bean";
197+
}
198+
}
199+
200+
163201
@Configuration
164202
public static class MyConfigWithNonPublicMethod {
165203

0 commit comments

Comments
 (0)