INT-4443: Use SimpleEC for uriVariablesExpression

JIRA: https://jira.spring.io/browse/INT-4443

**cherry-pick to 5.0.x, 4.3.x**

Polishing; use data binding accessor in test evaluation contexts.

Add `.withInstanceMethods()`

See https://jira.spring.io/browse/SPR-16588?focusedCommentId=158041&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-158041

* Polishing according PR comments

# Conflicts:
#	build.gradle
#	src/reference/asciidoc/changes-4.3-5.0.adoc

# Conflicts:
#	build.gradle
#	spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionUtils.java
#	spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpOutboundChannelAdapterParser.java
#	spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpOutboundGatewayParser.java
#	spring-integration-http/src/main/java/org/springframework/integration/http/outbound/AbstractHttpRequestExecutingMessageHandler.java
#	spring-integration-http/src/main/resources/org/springframework/integration/http/config/spring-integration-http-4.3.xsd
#	spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java
#	spring-integration-http/src/test/java/org/springframework/integration/http/outbound/UriVariableExpressionTests.java
#	src/reference/asciidoc/changes-4.2-4.3.adoc
#	src/reference/asciidoc/http.adoc
This commit is contained in:
Gary Russell
2018-03-23 16:03:22 -04:00
committed by Artem Bilan
parent ed79a9521c
commit 705d33a30c
16 changed files with 514 additions and 157 deletions

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2018 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.integration.config;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.integration.expression.SpelPropertyAccessorRegistrar;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.util.Assert;
/**
* Abstract class for integration evaluation context factory beans.
*
* @author Gary Russell
*
* @since 4.3.15
*
*/
public abstract class AbstractEvaluationContextFactoryBean implements ApplicationContextAware, InitializingBean {
private Map<String, PropertyAccessor> propertyAccessors = new LinkedHashMap<String, PropertyAccessor>();
private Map<String, Method> functions = new LinkedHashMap<String, Method>();
private TypeConverter typeConverter = new StandardTypeConverter();
private ApplicationContext applicationContext;
private boolean initialized;
protected TypeConverter getTypeConverter() {
return this.typeConverter;
}
protected ApplicationContext getApplicationContext() {
return this.applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void setPropertyAccessors(Map<String, PropertyAccessor> accessors) {
Assert.isTrue(!this.initialized, "'propertyAccessors' can't be changed after initialization.");
Assert.notNull(accessors, "'accessors' must not be null.");
Assert.noNullElements(accessors.values().toArray(), "'accessors' cannot have null values.");
this.propertyAccessors = new LinkedHashMap<String, PropertyAccessor>(accessors);
}
public Map<String, PropertyAccessor> getPropertyAccessors() {
return this.propertyAccessors;
}
public void setFunctions(Map<String, Method> functionsArg) {
Assert.isTrue(!this.initialized, "'functions' can't be changed after initialization.");
Assert.notNull(functionsArg, "'functions' must not be null.");
Assert.noNullElements(functionsArg.values().toArray(), "'functions' cannot have null values.");
this.functions = new LinkedHashMap<String, Method>(functionsArg);
}
public Map<String, Method> getFunctions() {
return this.functions;
}
protected void initialize(String beanName) throws Exception {
if (this.applicationContext != null) {
ConversionService conversionService = IntegrationUtils.getConversionService(getApplicationContext());
if (conversionService != null) {
this.typeConverter = new StandardTypeConverter(conversionService);
}
Map<String, SpelFunctionFactoryBean> functionFactoryBeanMap = BeanFactoryUtils
.beansOfTypeIncludingAncestors(this.applicationContext, SpelFunctionFactoryBean.class);
for (SpelFunctionFactoryBean spelFunctionFactoryBean : functionFactoryBeanMap.values()) {
if (!getFunctions().containsKey(spelFunctionFactoryBean.getFunctionName())) {
getFunctions().put(spelFunctionFactoryBean.getFunctionName(), spelFunctionFactoryBean.getObject());
}
}
try {
SpelPropertyAccessorRegistrar propertyAccessorRegistrar =
this.applicationContext.getBean(SpelPropertyAccessorRegistrar.class);
for (Entry<String, PropertyAccessor> entry : propertyAccessorRegistrar.getPropertyAccessors()
.entrySet()) {
if (!getPropertyAccessors().containsKey(entry.getKey())) {
getPropertyAccessors().put(entry.getKey(), entry.getValue());
}
}
}
catch (NoSuchBeanDefinitionException e) {
// There is no 'SpelPropertyAccessorRegistrar' bean in the application context.
}
ApplicationContext parent = this.applicationContext.getParent();
if (parent != null && parent.containsBean(beanName)) {
AbstractEvaluationContextFactoryBean parentFactoryBean = parent.getBean("&" + beanName, getClass());
for (Entry<String, PropertyAccessor> entry : parentFactoryBean.getPropertyAccessors().entrySet()) {
if (!getPropertyAccessors().containsKey(entry.getKey())) {
getPropertyAccessors().put(entry.getKey(), entry.getValue());
}
}
for (Entry<String, Method> entry : parentFactoryBean.getFunctions().entrySet()) {
if (!getFunctions().containsKey(entry.getKey())) {
getFunctions().put(entry.getKey(), entry.getValue());
}
}
}
}
this.initialized = true;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2018 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.
@@ -17,17 +17,9 @@
package org.springframework.integration.config;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MapAccessor;
import org.springframework.core.convert.ConversionService;
@@ -36,11 +28,8 @@ import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.expression.SpelPropertyAccessorRegistrar;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.util.Assert;
/**
* <p>
@@ -73,107 +62,28 @@ import org.springframework.util.Assert;
*
* @since 3.0
*/
public class IntegrationEvaluationContextFactoryBean implements FactoryBean<StandardEvaluationContext>,
ApplicationContextAware, InitializingBean {
private volatile Map<String, PropertyAccessor> propertyAccessors = new LinkedHashMap<String, PropertyAccessor>();
private volatile Map<String, Method> functions = new LinkedHashMap<String, Method>();
private TypeConverter typeConverter = new StandardTypeConverter();
public class IntegrationEvaluationContextFactoryBean extends AbstractEvaluationContextFactoryBean
implements FactoryBean<StandardEvaluationContext> {
private volatile TypeLocator typeLocator;
private BeanResolver beanResolver;
private ApplicationContext applicationContext;
private volatile boolean initialized;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void setPropertyAccessors(Map<String, PropertyAccessor> accessors) {
Assert.isTrue(!this.initialized, "'propertyAccessors' can't be changed after initialization.");
Assert.notNull(accessors, "'accessors' must not be null.");
Assert.noNullElements(accessors.values().toArray(), "'accessors' cannot have null values.");
this.propertyAccessors = new LinkedHashMap<String, PropertyAccessor>(accessors);
}
public Map<String, PropertyAccessor> getPropertyAccessors() {
return this.propertyAccessors;
}
public void setFunctions(Map<String, Method> functionsArg) {
Assert.isTrue(!this.initialized, "'functions' can't be changed after initialization.");
Assert.notNull(functionsArg, "'functions' must not be null.");
Assert.noNullElements(functionsArg.values().toArray(), "'functions' cannot have null values.");
this.functions = new LinkedHashMap<String, Method>(functionsArg);
}
public Map<String, Method> getFunctions() {
return this.functions;
}
public void setTypeLocator(TypeLocator typeLocator) {
this.typeLocator = typeLocator;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.applicationContext != null) {
this.beanResolver = new BeanFactoryResolver(this.applicationContext);
ConversionService conversionService = IntegrationUtils.getConversionService(this.applicationContext);
if (conversionService != null) {
this.typeConverter = new StandardTypeConverter(conversionService);
}
Map<String, SpelFunctionFactoryBean> functionFactoryBeanMap =
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, SpelFunctionFactoryBean.class);
for (SpelFunctionFactoryBean spelFunctionFactoryBean : functionFactoryBeanMap.values()) {
if (!this.functions.containsKey(spelFunctionFactoryBean.getFunctionName())) {
this.functions.put(spelFunctionFactoryBean.getFunctionName(), spelFunctionFactoryBean.getObject());
}
}
try {
SpelPropertyAccessorRegistrar propertyAccessorRegistrar =
this.applicationContext.getBean(SpelPropertyAccessorRegistrar.class);
for (Entry<String, PropertyAccessor> entry : propertyAccessorRegistrar.getPropertyAccessors().entrySet()) {
if (!this.propertyAccessors.containsKey(entry.getKey())) {
this.propertyAccessors.put(entry.getKey(), entry.getValue());
}
}
}
catch (NoSuchBeanDefinitionException e) {
// There is no 'SpelPropertyAccessorRegistrar' bean in the application context.
}
ApplicationContext parent = this.applicationContext.getParent();
if (parent != null && parent.containsBean(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME)) {
IntegrationEvaluationContextFactoryBean parentFactoryBean =
parent.getBean("&" + IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME,
IntegrationEvaluationContextFactoryBean.class);
for (Entry<String, PropertyAccessor> entry : parentFactoryBean.getPropertyAccessors().entrySet()) {
if (!this.propertyAccessors.containsKey(entry.getKey())) {
this.propertyAccessors.put(entry.getKey(), entry.getValue());
}
}
for (Entry<String, Method> entry : parentFactoryBean.getFunctions().entrySet()) {
if (!this.functions.containsKey(entry.getKey())) {
this.functions.put(entry.getKey(), entry.getValue());
}
}
}
if (getApplicationContext() != null) {
this.beanResolver = new BeanFactoryResolver(getApplicationContext());
}
this.initialized = true;
initialize(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
}
@Override
@@ -184,15 +94,15 @@ public class IntegrationEvaluationContextFactoryBean implements FactoryBean<Stan
}
evaluationContext.setBeanResolver(this.beanResolver);
evaluationContext.setTypeConverter(this.typeConverter);
evaluationContext.setTypeConverter(getTypeConverter());
for (PropertyAccessor propertyAccessor : this.propertyAccessors.values()) {
for (PropertyAccessor propertyAccessor : getPropertyAccessors().values()) {
evaluationContext.addPropertyAccessor(propertyAccessor);
}
evaluationContext.addPropertyAccessor(new MapAccessor());
for (Entry<String, Method> functionEntry : this.functions.entrySet()) {
for (Entry<String, Method> functionEntry : getFunctions().entrySet()) {
evaluationContext.registerFunction(functionEntry.getKey(), functionEntry.getValue());
}
@@ -204,9 +114,4 @@ public class IntegrationEvaluationContextFactoryBean implements FactoryBean<Stan
return StandardEvaluationContext.class;
}
@Override
public boolean isSingleton() {
return false;
}
}

View File

@@ -194,6 +194,17 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
".expression.IntegrationEvaluationContextAwareBeanPostProcessor");
BeanDefinitionReaderUtils.registerWithGeneratedName(integrationEvalContextBPP, registry);
}
if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_SIMPLE_EVALUATION_CONTEXT_BEAN_NAME)) {
BeanDefinitionBuilder integrationEvaluationContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(IntegrationSimpleEvaluationContextFactoryBean.class);
integrationEvaluationContextBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
BeanDefinitionHolder integrationEvaluationContextHolder =
new BeanDefinitionHolder(integrationEvaluationContextBuilder.getBeanDefinition(),
IntegrationContextUtils.INTEGRATION_SIMPLE_EVALUATION_CONTEXT_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder, registry);
}
}
/**

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2018 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.integration.config;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map.Entry;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.expression.MapAccessor;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.expression.SpelPropertyAccessorRegistrar;
/**
* <p>
* {@link FactoryBean} to populate {@link SimpleEvaluationContext} instances enhanced with:
* <ul>
* <li>
* a {@link TypeConverter} based on the {@link ConversionService} from the application context.
* </li>
* <li>
* a set of provided {@link PropertyAccessor}s including a default {@link MapAccessor}.
* </li>
* <li>
* a set of provided SpEL functions.
* </li>
* </ul>
* <p>
* After initialization this factory populates functions and property accessors from
* {@link SpelFunctionFactoryBean}s and {@link SpelPropertyAccessorRegistrar}, respectively.
* Functions and property accessors are also inherited from any parent context.
* </p>
* <p>
* This factory returns a new instance for each reference - {@link #isSingleton()} returns false.
* </p>
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 4.3.15
*/
public class IntegrationSimpleEvaluationContextFactoryBean extends AbstractEvaluationContextFactoryBean
implements FactoryBean<SimpleEvaluationContext> {
@Override
public boolean isSingleton() {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
initialize(IntegrationContextUtils.INTEGRATION_SIMPLE_EVALUATION_CONTEXT_BEAN_NAME);
}
@Override
public SimpleEvaluationContext getObject() throws Exception {
Collection<PropertyAccessor> accessors = getPropertyAccessors().values();
PropertyAccessor[] accessorArray = accessors.toArray(new PropertyAccessor[accessors.size() + 2]);
accessorArray[accessors.size()] = new MapAccessor();
accessorArray[accessors.size() + 1] = DataBindingPropertyAccessor.forReadOnlyAccess();
SimpleEvaluationContext evaluationContext =
SimpleEvaluationContext.forPropertyAccessors(accessorArray)
.withTypeConverter(getTypeConverter())
.withInstanceMethods()
.build();
for (Entry<String, Method> functionEntry : getFunctions().entrySet()) {
evaluationContext.setVariable(functionEntry.getKey(), functionEntry.getValue());
}
return evaluationContext;
}
@Override
public Class<?> getObjectType() {
return SimpleEvaluationContext.class;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -19,6 +19,7 @@ package org.springframework.integration.context;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.config.IntegrationConfigUtils;
import org.springframework.integration.metadata.MetadataStore;
@@ -48,6 +49,8 @@ public abstract class IntegrationContextUtils {
public static final String INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME = "integrationEvaluationContext";
public static final String INTEGRATION_SIMPLE_EVALUATION_CONTEXT_BEAN_NAME = "integrationSimpleEvaluationContext";
public static final String INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME = "integrationHeaderChannelRegistry";
public static final String INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME = "integrationGlobalProperties";
@@ -120,12 +123,24 @@ public abstract class IntegrationContextUtils {
/**
* @param beanFactory BeanFactory for lookup, must not be null.
* @return the instance of {@link StandardEvaluationContext} bean whose name is "integrationEvaluationContext" .
* @return the instance of {@link StandardEvaluationContext} bean whose name is
* {@value #INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME}.
*/
public static StandardEvaluationContext getEvaluationContext(BeanFactory beanFactory) {
return getBeanOfType(beanFactory, INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME, StandardEvaluationContext.class);
}
/**
* @param beanFactory BeanFactory for lookup, must not be null.
* @return the instance of {@link SimpleEvaluationContext} bean whose name is
* {@value #INTEGRATION_SIMPLE_EVALUATION_CONTEXT_BEAN_NAME}.
* @since 4.3.15
*/
public static SimpleEvaluationContext getSimpleEvaluationContext(BeanFactory beanFactory) {
return getBeanOfType(beanFactory, INTEGRATION_SIMPLE_EVALUATION_CONTEXT_BEAN_NAME,
SimpleEvaluationContext.class);
}
private static <T> T getBeanOfType(BeanFactory beanFactory, String beanName, Class<T> type) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
if (!beanFactory.containsBean(beanName)) {
@@ -149,7 +164,8 @@ public abstract class IntegrationContextUtils {
Properties properties = new Properties();
properties.putAll(IntegrationProperties.defaults());
if (beanFactory != null) {
Properties userProperties = getBeanOfType(beanFactory, INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, Properties.class);
Properties userProperties =
getBeanOfType(beanFactory, INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, Properties.class);
if (userProperties != null) {
properties.putAll(userProperties);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 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.
@@ -16,18 +16,22 @@
package org.springframework.integration.expression;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MapAccessor;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.SimpleEvaluationContext.Builder;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility class with static methods for helping with establishing environments for
* SpEL expressions.
@@ -40,32 +44,22 @@ import org.apache.commons.logging.LogFactory;
public abstract class ExpressionUtils {
private static final Log logger = LogFactory.getLog(ExpressionUtils.class);
/**
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
* property accessor property and the supplied {@link ConversionService} in its
* conversionService property.
* @param conversionService the conversion service.
* @return the evaluation context.
*/
private static StandardEvaluationContext createStandardEvaluationContext(ConversionService conversionService,
BeanFactory beanFactory) {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.addPropertyAccessor(new MapAccessor());
if (conversionService != null) {
evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService));
}
if (beanFactory != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return evaluationContext;
}
/**
* Used to create a context with no BeanFactory, usually in tests.
* @return The evaluation context.
*/
public static StandardEvaluationContext createStandardEvaluationContext() {
return doCreateContext(null);
return (StandardEvaluationContext) doCreateContext(null, false);
}
/**
* Used to create a context with no BeanFactory, usually in tests.
* @return The evaluation context.
* @since 4.3.15
*/
public static SimpleEvaluationContext createSimpleEvaluationContext() {
return (SimpleEvaluationContext) doCreateContext(null, true);
}
/**
@@ -78,22 +72,73 @@ public abstract class ExpressionUtils {
if (beanFactory == null) {
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
}
return doCreateContext(beanFactory);
return (StandardEvaluationContext) doCreateContext(beanFactory, false);
}
private static StandardEvaluationContext doCreateContext(BeanFactory beanFactory) {
/**
* Obtains the context from the beanFactory if not null; emits a warning if the beanFactory
* is null.
* @param beanFactory The bean factory.
* @return The evaluation context.
* @since 4.3.15
*/
public static SimpleEvaluationContext createSimpleEvaluationContext(BeanFactory beanFactory) {
if (beanFactory == null) {
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
}
return (SimpleEvaluationContext) doCreateContext(beanFactory, true);
}
private static EvaluationContext doCreateContext(BeanFactory beanFactory, boolean simple) {
ConversionService conversionService = null;
StandardEvaluationContext evaluationContext = null;
EvaluationContext evaluationContext = null;
if (beanFactory != null) {
evaluationContext = IntegrationContextUtils.getEvaluationContext(beanFactory);
evaluationContext =
simple
? IntegrationContextUtils.getSimpleEvaluationContext(beanFactory)
: IntegrationContextUtils.getEvaluationContext(beanFactory);
}
if (evaluationContext == null) {
if (beanFactory != null) {
conversionService = IntegrationUtils.getConversionService(beanFactory);
}
evaluationContext = createStandardEvaluationContext(conversionService, beanFactory);
evaluationContext = createEvaluationContext(conversionService, beanFactory, simple);
}
return evaluationContext;
}
/**
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
* property accessor property and the supplied {@link ConversionService} in its
* conversionService property.
* @param conversionService the conversion service.
* @param beanFactory the bean factory.
* @param simple true if simple.
* @return the evaluation context.
*/
private static EvaluationContext createEvaluationContext(ConversionService conversionService,
BeanFactory beanFactory, boolean simple) {
if (simple) {
Builder ecBuilder = SimpleEvaluationContext.forPropertyAccessors(
new MapAccessor(), DataBindingPropertyAccessor.forReadOnlyAccess())
.withInstanceMethods();
if (conversionService != null) {
ecBuilder.withConversionService(conversionService);
}
return ecBuilder.build();
}
else {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.addPropertyAccessor(new MapAccessor());
if (conversionService != null) {
evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService));
}
if (beanFactory != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return evaluationContext;
}
}
}

View File

@@ -75,6 +75,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.BridgeFrom;
import org.springframework.integration.annotation.BridgeTo;
@@ -695,7 +696,7 @@ public class EnableIntegrationTests {
@Test
public void testIntegrationEvaluationContextCustomization() {
EvaluationContext evaluationContext = this.context.getBean(EvaluationContext.class);
EvaluationContext evaluationContext = this.context.getBean(StandardEvaluationContext.class);
List<?> propertyAccessors = TestUtils.getPropertyValue(evaluationContext, "propertyAccessors", List.class);
assertEquals(4, propertyAccessors.size());
assertThat(propertyAccessors.get(0), instanceOf(JsonPropertyAccessor.class));