Skip to content

Commit

Permalink
Avoid duplicate AOP proxy class definition with FilteredClassLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
dreis2211 authored and snicoll committed Nov 6, 2021
1 parent cd5508a commit 7d594aa
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand All @@ -20,12 +20,14 @@
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.function.Predicate;

import org.springframework.core.SmartClassLoader;
import org.springframework.core.io.ClassPathResource;

/**
Expand All @@ -37,7 +39,7 @@
* @author Roy Jacobs
* @since 2.0.0
*/
public class FilteredClassLoader extends URLClassLoader {
public class FilteredClassLoader extends URLClassLoader implements SmartClassLoader {

private final Collection<Predicate<String>> classesFilters;

Expand Down Expand Up @@ -129,6 +131,16 @@ public InputStream getResourceAsStream(String 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.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

/**
* Tests for {@link FilteredClassLoader}.
Expand Down Expand Up @@ -111,4 +112,13 @@ void loadResourceAsStreamWhenNotFilteredShouldLoadResource() throws Exception {
}
}

@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));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

import org.springframework.beans.factory.BeanDefinitionStoreException;
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.assertj.ApplicationContextAssertProvider;
import org.springframework.context.ConfigurableApplicationContext;
Expand All @@ -33,6 +35,7 @@
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
Expand Down Expand Up @@ -165,6 +168,15 @@ void runWithClassLoaderShouldSetClassLoaderOnConditionContext() {
.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
void thrownRuleWorksWithCheckedException() {
get().run((context) -> assertThatIOException().isThrownBy(() -> throwCheckedException("Expected message"))
Expand Down Expand Up @@ -241,6 +253,30 @@ static class ConditionalConfig {

}

@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 {

@Override
Expand Down

0 comments on commit 7d594aa

Please sign in to comment.