Merge pull request #28531 from dreis2211
* pr/28531: Polish contribution Avoid duplicate AOP proxy class definition with FilteredClassLoader Closes gh-28531
This commit is contained in:
commit
034cf6ac34
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,12 +20,14 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.springframework.core.SmartClassLoader;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +39,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||||
* @author Roy Jacobs
|
* @author Roy Jacobs
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public class FilteredClassLoader extends URLClassLoader {
|
public class FilteredClassLoader extends URLClassLoader implements SmartClassLoader {
|
||||||
|
|
||||||
private final Collection<Predicate<String>> classesFilters;
|
private final Collection<Predicate<String>> classesFilters;
|
||||||
|
|
||||||
|
@ -129,6 +131,16 @@ public class FilteredClassLoader extends URLClassLoader {
|
||||||
return super.getResourceAsStream(name);
|
return super.getResourceAsStream(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> publicDefineClass(String name, byte[] b, ProtectionDomain protectionDomain) {
|
||||||
|
for (Predicate<String> filter : this.classesFilters) {
|
||||||
|
if (filter.test(name)) {
|
||||||
|
throw new IllegalArgumentException(String.format("Defining class with name %s is not supported", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defineClass(name, b, 0, b.length, protectionDomain);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter to restrict the classes that can be loaded.
|
* Filter to restrict the classes that can be loaded.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -26,6 +26,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link FilteredClassLoader}.
|
* Tests for {@link FilteredClassLoader}.
|
||||||
|
@ -111,4 +112,13 @@ class FilteredClassLoaderTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void publicDefineClassWhenFilteredThrowsException() throws Exception {
|
||||||
|
Class<FilteredClassLoaderTests> hiddenClass = FilteredClassLoaderTests.class;
|
||||||
|
try (FilteredClassLoader classLoader = new FilteredClassLoader(hiddenClass)) {
|
||||||
|
assertThatIllegalArgumentException()
|
||||||
|
.isThrownBy(() -> classLoader.publicDefineClass(hiddenClass.getName(), new byte[] {}, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,10 @@ import com.google.gson.Gson;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.context.annotation.UserConfigurations;
|
import org.springframework.boot.context.annotation.UserConfigurations;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||||
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
|
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
@ -33,6 +36,7 @@ import org.springframework.context.annotation.Condition;
|
||||||
import org.springframework.context.annotation.ConditionContext;
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
@ -165,6 +169,15 @@ abstract class AbstractApplicationContextRunnerTests<T extends AbstractApplicati
|
||||||
.run((context) -> assertThat(context).hasSingleBean(ConditionalConfig.class));
|
.run((context) -> assertThat(context).hasSingleBean(ConditionalConfig.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void consecutiveRunWithFilteredClassLoaderShouldHaveBeanWithLazyProperties() {
|
||||||
|
get().withClassLoader(new FilteredClassLoader(Gson.class)).withUserConfiguration(LazyConfig.class)
|
||||||
|
.run((context) -> assertThat(context).hasSingleBean(ExampleBeanWithLazyProperties.class));
|
||||||
|
|
||||||
|
get().withClassLoader(new FilteredClassLoader(Gson.class)).withUserConfiguration(LazyConfig.class)
|
||||||
|
.run((context) -> assertThat(context).hasSingleBean(ExampleBeanWithLazyProperties.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void thrownRuleWorksWithCheckedException() {
|
void thrownRuleWorksWithCheckedException() {
|
||||||
get().run((context) -> assertThatIOException().isThrownBy(() -> throwCheckedException("Expected message"))
|
get().run((context) -> assertThatIOException().isThrownBy(() -> throwCheckedException("Expected message"))
|
||||||
|
@ -241,6 +254,30 @@ abstract class AbstractApplicationContextRunnerTests<T extends AbstractApplicati
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableConfigurationProperties(ExampleProperties.class)
|
||||||
|
static class LazyConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ExampleBeanWithLazyProperties exampleBeanWithLazyProperties() {
|
||||||
|
return new ExampleBeanWithLazyProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ExampleBeanWithLazyProperties {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Lazy
|
||||||
|
ExampleProperties exampleProperties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigurationProperties
|
||||||
|
public static class ExampleProperties {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class FilteredClassLoaderCondition implements Condition {
|
static class FilteredClassLoaderCondition implements Condition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue