|
|
|
|
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
|
|
|
|
/* |
|
|
|
|
* Copyright 2002-2024 the original author or authors. |
|
|
|
|
* Copyright 2002-2025 the original author or authors. |
|
|
|
|
* |
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
|
@ -18,11 +18,16 @@ package org.springframework.context.annotation;
@@ -18,11 +18,16 @@ package org.springframework.context.annotation;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.io.InputStream; |
|
|
|
|
import java.net.URL; |
|
|
|
|
import java.net.URLClassLoader; |
|
|
|
|
import java.security.ProtectionDomain; |
|
|
|
|
import java.security.SecureClassLoader; |
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
|
|
|
|
|
|
import org.springframework.core.OverridingClassLoader; |
|
|
|
|
import org.springframework.core.SmartClassLoader; |
|
|
|
|
import org.springframework.lang.Nullable; |
|
|
|
|
import org.springframework.util.StreamUtils; |
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
|
@ -36,19 +41,108 @@ class ConfigurationClassEnhancerTests {
@@ -36,19 +41,108 @@ class ConfigurationClassEnhancerTests {
|
|
|
|
|
@Test |
|
|
|
|
void enhanceReloadedClass() throws Exception { |
|
|
|
|
ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer(); |
|
|
|
|
|
|
|
|
|
ClassLoader parentClassLoader = getClass().getClassLoader(); |
|
|
|
|
CustomClassLoader classLoader = new CustomClassLoader(parentClassLoader); |
|
|
|
|
ClassLoader classLoader = new CustomSmartClassLoader(parentClassLoader); |
|
|
|
|
Class<?> myClass = parentClassLoader.loadClass(MyConfig.class.getName()); |
|
|
|
|
configurationClassEnhancer.enhance(myClass, parentClassLoader); |
|
|
|
|
Class<?> myReloadedClass = classLoader.loadClass(MyConfig.class.getName()); |
|
|
|
|
Class<?> enhancedReloadedClass = configurationClassEnhancer.enhance(myReloadedClass, classLoader); |
|
|
|
|
assertThat(enhancedReloadedClass.getClassLoader()).isEqualTo(classLoader); |
|
|
|
|
Class<?> enhancedClass = configurationClassEnhancer.enhance(myClass, parentClassLoader); |
|
|
|
|
assertThat(myClass).isAssignableFrom(enhancedClass); |
|
|
|
|
|
|
|
|
|
myClass = classLoader.loadClass(MyConfig.class.getName()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(myClass, classLoader); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader); |
|
|
|
|
assertThat(myClass).isAssignableFrom(enhancedClass); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void withPublicClass() { |
|
|
|
|
ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer(); |
|
|
|
|
|
|
|
|
|
ClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader()); |
|
|
|
|
Class<?> enhancedClass = configurationClassEnhancer.enhance(MyConfigWithPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader); |
|
|
|
|
|
|
|
|
|
classLoader = new OverridingClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new CustomSmartClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new BasicSmartClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void withNonPublicClass() { |
|
|
|
|
ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer(); |
|
|
|
|
|
|
|
|
|
ClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader()); |
|
|
|
|
Class<?> enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new OverridingClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new CustomSmartClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new BasicSmartClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicClass.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicClass.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void withNonPublicMethod() { |
|
|
|
|
ConfigurationClassEnhancer configurationClassEnhancer = new ConfigurationClassEnhancer(); |
|
|
|
|
|
|
|
|
|
ClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader()); |
|
|
|
|
Class<?> enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicMethod.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicMethod.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader); |
|
|
|
|
|
|
|
|
|
classLoader = new OverridingClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicMethod.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicMethod.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new CustomSmartClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicMethod.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicMethod.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
|
|
|
|
|
classLoader = new BasicSmartClassLoader(getClass().getClassLoader()); |
|
|
|
|
enhancedClass = configurationClassEnhancer.enhance(MyConfigWithNonPublicMethod.class, classLoader); |
|
|
|
|
assertThat(MyConfigWithNonPublicMethod.class).isAssignableFrom(enhancedClass); |
|
|
|
|
assertThat(enhancedClass.getClassLoader()).isEqualTo(classLoader.getParent()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
static class MyConfig { |
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
String myBean() { |
|
|
|
|
return "bean"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
public static class MyConfigWithPublicClass { |
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
public String myBean() { |
|
|
|
|
return "bean"; |
|
|
|
|
@ -56,9 +150,29 @@ class ConfigurationClassEnhancerTests {
@@ -56,9 +150,29 @@ class ConfigurationClassEnhancerTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static class CustomClassLoader extends SecureClassLoader implements SmartClassLoader { |
|
|
|
|
@Configuration |
|
|
|
|
static class MyConfigWithNonPublicClass { |
|
|
|
|
|
|
|
|
|
CustomClassLoader(ClassLoader parent) { |
|
|
|
|
@Bean |
|
|
|
|
public String myBean() { |
|
|
|
|
return "bean"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
public static class MyConfigWithNonPublicMethod { |
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
String myBean() { |
|
|
|
|
return "bean"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static class CustomSmartClassLoader extends SecureClassLoader implements SmartClassLoader { |
|
|
|
|
|
|
|
|
|
CustomSmartClassLoader(ClassLoader parent) { |
|
|
|
|
super(parent); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -82,6 +196,29 @@ class ConfigurationClassEnhancerTests {
@@ -82,6 +196,29 @@ class ConfigurationClassEnhancerTests {
|
|
|
|
|
public boolean isClassReloadable(Class<?> clazz) { |
|
|
|
|
return clazz.getName().contains("MyConfig"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ClassLoader getOriginalClassLoader() { |
|
|
|
|
return getParent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) { |
|
|
|
|
return defineClass(name, b, 0, b.length, protectionDomain); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static class BasicSmartClassLoader extends SecureClassLoader implements SmartClassLoader { |
|
|
|
|
|
|
|
|
|
BasicSmartClassLoader(ClassLoader parent) { |
|
|
|
|
super(parent); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) { |
|
|
|
|
return defineClass(name, b, 0, b.length, protectionDomain); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|