Skip to content

Commit 3118f14

Browse files
committed
Fix NPE when OnExpressionCondition is invoked with a null BeanFactory
Closes gh-13249
1 parent 2140196 commit 3118f14

File tree

2 files changed

+53
-11
lines changed

2 files changed

+53
-11
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnExpressionCondition.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* A Condition that evaluates a SpEL expression.
3030
*
3131
* @author Dave Syer
32+
* @author Stephane Nicoll
3233
* @see ConditionalOnExpression
3334
*/
3435
@Order(Ordered.LOWEST_PRECEDENCE - 20)
@@ -43,18 +44,28 @@ public ConditionOutcome getMatchOutcome(ConditionContext context,
4344
expression = wrapIfNecessary(expression);
4445
String rawExpression = expression;
4546
expression = context.getEnvironment().resolvePlaceholders(expression);
47+
ConditionMessage.Builder messageBuilder = ConditionMessage
48+
.forCondition(ConditionalOnExpression.class, "(" + rawExpression + ")");
4649
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
47-
BeanExpressionResolver resolver = (beanFactory != null
48-
? beanFactory.getBeanExpressionResolver() : null);
49-
BeanExpressionContext expressionContext = (beanFactory != null
50-
? new BeanExpressionContext(beanFactory, null) : null);
50+
if (beanFactory != null) {
51+
boolean result = evaluateExpression(beanFactory, expression);
52+
return new ConditionOutcome(result, messageBuilder.resultedIn(result));
53+
}
54+
else {
55+
return ConditionOutcome
56+
.noMatch(messageBuilder.because("no BeanFactory available."));
57+
}
58+
}
59+
60+
private Boolean evaluateExpression(ConfigurableListableBeanFactory beanFactory,
61+
String expression) {
62+
BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();
5163
if (resolver == null) {
5264
resolver = new StandardBeanExpressionResolver();
5365
}
54-
boolean result = (Boolean) resolver.evaluate(expression, expressionContext);
55-
return new ConditionOutcome(result, ConditionMessage
56-
.forCondition(ConditionalOnExpression.class, "(" + rawExpression + ")")
57-
.resultedIn(result));
66+
BeanExpressionContext expressionContext = new BeanExpressionContext(beanFactory,
67+
null);
68+
return (Boolean) resolver.evaluate(expression, expressionContext);
5869
}
5970

6071
/**

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnExpressionTests.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,38 +16,69 @@
1616

1717
package org.springframework.boot.autoconfigure.condition;
1818

19+
import java.util.HashMap;
20+
import java.util.Map;
21+
1922
import org.junit.Test;
2023

2124
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2225
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.ConditionContext;
2327
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.core.type.AnnotatedTypeMetadata;
29+
import org.springframework.mock.env.MockEnvironment;
2430

2531
import static org.assertj.core.api.Assertions.assertThat;
32+
import static org.mockito.BDDMockito.given;
33+
import static org.mockito.Mockito.mock;
2634

2735
/**
2836
* Tests for {@link ConditionalOnExpression}.
2937
*
3038
* @author Dave Syer
39+
* @author Stephane Nicoll
3140
*/
3241
public class ConditionalOnExpressionTests {
3342

3443
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
3544

3645
@Test
37-
public void testResourceExists() {
46+
public void expressionEvaluatesToTrueRegisterBean() {
3847
this.context.register(BasicConfiguration.class);
3948
this.context.refresh();
4049
assertThat(this.context.containsBean("foo")).isTrue();
4150
assertThat(this.context.getBean("foo")).isEqualTo("foo");
4251
}
4352

4453
@Test
45-
public void testResourceNotExists() {
54+
public void expressionEvaluatesToFalseDoesNotRegisterBean() {
4655
this.context.register(MissingConfiguration.class);
4756
this.context.refresh();
4857
assertThat(this.context.containsBean("foo")).isFalse();
4958
}
5059

60+
@Test
61+
public void expressionEvaluationWithNoBeanFactoryDoesNotMatch() {
62+
OnExpressionCondition condition = new OnExpressionCondition();
63+
MockEnvironment environment = new MockEnvironment();
64+
ConditionContext conditionContext = mock(ConditionContext.class);
65+
given(conditionContext.getEnvironment()).willReturn(environment);
66+
ConditionOutcome outcome = condition.getMatchOutcome(conditionContext,
67+
mockMetaData("invalid-spel"));
68+
assertThat(outcome.isMatch()).isFalse();
69+
assertThat(outcome.getMessage()).contains("invalid-spel")
70+
.contains("no BeanFactory available");
71+
}
72+
73+
private AnnotatedTypeMetadata mockMetaData(String value) {
74+
AnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);
75+
Map<String, Object> attributes = new HashMap<String, Object>();
76+
attributes.put("value", value);
77+
given(metadata.getAnnotationAttributes(ConditionalOnExpression.class.getName()))
78+
.willReturn(attributes);
79+
return metadata;
80+
}
81+
5182
@Configuration
5283
@ConditionalOnExpression("false")
5384
protected static class MissingConfiguration {

0 commit comments

Comments
 (0)