From 80b1d28be1c8b9a23099b145fe2dcf472bfa9697 Mon Sep 17 00:00:00 2001 From: Eric Bottard Date: Mon, 9 Nov 2015 10:12:16 +0100 Subject: [PATCH] Issue #170 Set the Spring Integration EvaluationContext on Expressions that are parsed when converting String->Expression via the SpelExpressionConverter --- .../SpelExpressionConverterConfiguration.java | 18 +++- ...ExpressionConverterConfigurationTests.java | 85 +++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfigurationTests.java diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfiguration.java index 634153698..8a272cbad 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfiguration.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfiguration.java @@ -16,19 +16,21 @@ package org.springframework.cloud.stream.config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; +import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ParseException; +import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.integration.context.IntegrationContextUtils; /** * Adds a Converter from String to SpEL Expression in the context. - * By default, ConfigurationPropertiesBindingPostProcessor adds all converters it finds - * in the context to its own conversionService, so this is useful for binding properties - * of type Expression in {@literal @}ConfigurationProperties annotated classes. * * @author Eric Bottard */ @@ -50,10 +52,18 @@ public class SpelExpressionConverterConfiguration { private SpelExpressionParser parser = new SpelExpressionParser(); + @Autowired + @Qualifier(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME) + private EvaluationContext evaluationContext; + @Override public Expression convert(String source) { try { - return parser.parseExpression(source); + Expression expression = parser.parseExpression(source); + if (expression instanceof SpelExpression) { + ((SpelExpression) expression).setEvaluationContext(evaluationContext); + } + return expression; } catch (ParseException e) { throw new IllegalArgumentException(String.format("Could not convert '%s' into a SpEL expression", source), e); diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfigurationTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfigurationTests.java new file mode 100644 index 000000000..a0985ea29 --- /dev/null +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/SpelExpressionConverterConfigurationTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.stream.config; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.expression.Expression; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Tests for SpelExpressionConverterConfiguration. + * + * @author Eric Bottard + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = SpelExpressionConverterConfigurationTests.Config.class) +@IntegrationTest("expression: a.b") +public class SpelExpressionConverterConfigurationTests { + + @Autowired + private Pojo pojo; + + @Test + public void converterCorrectlyInstalled() { + assertThat(pojo.getExpression().getValue("{\"a\": {\"b\": 5}}").toString(), is((Object) "5")); + } + + @ConfigurationProperties + public static class Pojo { + + private Expression expression; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + } + + @Configuration + @Import(SpelExpressionConverterConfiguration.class) + @EnableIntegration + @EnableConfigurationProperties(Pojo.class) + public static class Config { + + /** + * Installs some PAs on the EvaluationContext. + */ + @Bean + public static BeanPostProcessor propertyAccessorConfigurer() { + return ChannelBindingServiceConfiguration.PostProcessorConfiguration.propertyAccessorBeanPostProcessor(); + } + } + +}