Ensure that condition evaluator uses runner’s class loader

Closes gh-13319
This commit is contained in:
Andy Wilkinson 2018-06-01 11:53:56 +01:00
parent 152ce145fd
commit 27267a7090
2 changed files with 54 additions and 9 deletions

View File

@ -196,9 +196,8 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
}
/**
* Customize the {@link ClassLoader} that the {@link ApplicationContext} should use.
* Customizing the {@link ClassLoader} is an effective manner to hide resources from
* the classpath.
* Customize the {@link ClassLoader} that the {@link ApplicationContext} should use
* for resource loading and bean class loading.
* @param classLoader the classloader to use (can be null to use the default)
* @return a new instance with the updated class loader
* @see FilteredClassLoader
@ -274,15 +273,34 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
*/
@SuppressWarnings("unchecked")
public SELF run(ContextConsumer<? super A> consumer) {
this.systemProperties.applyToSystemProperties(() -> {
try (A context = createAssertableContext()) {
accept(consumer, context);
}
return null;
withContextClassLoader(this.classLoader, () -> {
this.systemProperties.applyToSystemProperties(() -> {
try (A context = createAssertableContext()) {
accept(consumer, context);
}
return null;
});
});
return (SELF) this;
}
private void withContextClassLoader(ClassLoader classLoader, Runnable action) {
if (classLoader == null) {
action.run();
}
else {
Thread currentThread = Thread.currentThread();
ClassLoader previous = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(classLoader);
try {
action.run();
}
finally {
currentThread.setContextClassLoader(previous);
}
}
}
@SuppressWarnings("unchecked")
private A createAssertableContext() {
ResolvableType resolvableType = ResolvableType

View File

@ -30,8 +30,12 @@ import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -150,7 +154,7 @@ public abstract class AbstractApplicationContextRunnerTests<T extends AbstractAp
}
@Test
public void runWithClassLoaderShouldSetClassLoader() {
public void runWithClassLoaderShouldSetClassLoaderOnContext() {
get().withClassLoader(new FilteredClassLoader(Gson.class.getPackage().getName()))
.run((context) -> {
try {
@ -164,6 +168,14 @@ public abstract class AbstractApplicationContextRunnerTests<T extends AbstractAp
});
}
@Test
public void runWithClassLoaderShouldSetClassLoaderOnConditionContext() {
get().withClassLoader(new FilteredClassLoader(Gson.class.getPackage().getName()))
.withUserConfiguration(ConditionalConfig.class)
.run((context) -> assertThat(context)
.hasSingleBean(ConditionalConfig.class));
}
@Test
public void thrownRuleWorksWithCheckedException() {
get().run((context) -> {
@ -209,4 +221,19 @@ public abstract class AbstractApplicationContextRunnerTests<T extends AbstractAp
}
@Configuration
@Conditional(FilteredClassLoaderCondition.class)
static class ConditionalConfig {
}
static class FilteredClassLoaderCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getClassLoader() instanceof FilteredClassLoader;
}
}
}