diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationEvaluationContextFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationEvaluationContextFactoryBean.java index d594318784..2ef8380f81 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationEvaluationContextFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationEvaluationContextFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-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. @@ -101,7 +101,7 @@ public class IntegrationEvaluationContextFactoryBean implements FactoryBean getPropertyAccessors() { - return propertyAccessors; + return this.propertyAccessors; } public void setFunctions(Map functionsArg) { @@ -111,6 +111,10 @@ public class IntegrationEvaluationContextFactoryBean implements FactoryBean(functionsArg); } + public Map getFunctions() { + return this.functions; + } + public void setTypeLocator(TypeLocator typeLocator) { this.typeLocator = typeLocator; } @@ -134,7 +138,8 @@ public class IntegrationEvaluationContextFactoryBean implements FactoryBean entry : propertyAccessorRegistrar.getPropertyAccessors().entrySet()) { if (!this.propertyAccessors.containsKey(entry.getKey())) { this.propertyAccessors.put(entry.getKey(), entry.getValue()); @@ -157,6 +162,12 @@ public class IntegrationEvaluationContextFactoryBean implements FactoryBean entry : parentFactoryBean.getFunctions().entrySet()) { + if (!this.functions.containsKey(entry.getKey())) { + this.functions.put(entry.getKey(), entry.getValue()); + } + } } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml index dc2aa2e6be..cd70ed0d50 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml @@ -21,6 +21,16 @@ + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java index 3481d6732c..122b1a11ff 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java @@ -33,6 +33,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.hamcrest.Matchers; +import org.junit.Test; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -53,9 +56,6 @@ import org.springframework.messaging.MessageChannel; import org.springframework.messaging.PollableChannel; import org.springframework.messaging.support.GenericMessage; -import org.hamcrest.Matchers; -import org.junit.Test; - /** * @author Gary Russell * @author Artem Bilan @@ -87,10 +87,10 @@ public class ParentContextTests { Object parentEvaluationContextFactoryBean = parent.getBean(IntegrationEvaluationContextFactoryBean.class); Map parentFunctions = TestUtils.getPropertyValue(parentEvaluationContextFactoryBean, "functions", Map.class); - assertEquals(3, parentFunctions.size()); + assertEquals(4, parentFunctions.size()); Object jsonPath = parentFunctions.get("jsonPath"); assertNotNull(jsonPath); - assertThat((Method) jsonPath, Matchers.isOneOf(JsonPathUtils.class.getMethods())); + assertThat(jsonPath, Matchers.isOneOf(JsonPathUtils.class.getMethods())); assertEquals(2, evalContexts.size()); ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(parent); child.setConfigLocation("org/springframework/integration/expression/ChildContext-context.xml"); @@ -99,8 +99,9 @@ public class ParentContextTests { Object childEvaluationContextFactoryBean = child.getBean(IntegrationEvaluationContextFactoryBean.class); Map childFunctions = TestUtils.getPropertyValue(childEvaluationContextFactoryBean, "functions", Map.class); - assertEquals(4, childFunctions.size()); + assertEquals(5, childFunctions.size()); assertTrue(childFunctions.containsKey("barParent")); + assertTrue(childFunctions.containsKey("fooFunc")); jsonPath = childFunctions.get("jsonPath"); assertNotNull(jsonPath); assertThat((Method) jsonPath, Matchers.not(Matchers.isOneOf(JsonPathUtils.class.getMethods()))); @@ -117,9 +118,10 @@ public class ParentContextTests { Map variables = (Map) TestUtils.getPropertyValue(evalContexts.get(0), "variables"); - assertEquals(3, variables.size()); + assertEquals(4, variables.size()); assertTrue(variables.containsKey("bar")); assertTrue(variables.containsKey("barParent")); + assertTrue(variables.containsKey("fooFunc")); assertTrue(variables.containsKey("jsonPath")); assertNotSame(evalContexts.get(1).getBeanResolver(), evalContexts.get(2).getBeanResolver()); @@ -128,9 +130,10 @@ public class ParentContextTests { assertTrue(propertyAccessors.contains(parentPropertyAccessorOverride)); variables = (Map) TestUtils.getPropertyValue(evalContexts.get(1), "variables"); - assertEquals(3, variables.size()); + assertEquals(4, variables.size()); assertTrue(variables.containsKey("bar")); assertTrue(variables.containsKey("barParent")); + assertTrue(variables.containsKey("fooFunc")); assertTrue(variables.containsKey("jsonPath")); propertyAccessors = evalContexts.get(2).getPropertyAccessors(); @@ -142,9 +145,10 @@ public class ParentContextTests { assertTrue(propertyAccessors.indexOf(childPropertyAccessor) < propertyAccessors.indexOf(parentPropertyAccessor)); variables = (Map) TestUtils.getPropertyValue(evalContexts.get(2), "variables"); - assertEquals(4, variables.size()); + assertEquals(5, variables.size()); assertTrue(variables.containsKey("bar")); assertTrue(variables.containsKey("barParent")); + assertTrue(variables.containsKey("fooFunc")); assertTrue(variables.containsKey("barChild")); assertTrue(variables.containsKey("jsonPath")); diff --git a/src/reference/asciidoc/spel.adoc b/src/reference/asciidoc/spel.adoc index b88ace58d4..e4aa0dabfa 100644 --- a/src/reference/asciidoc/spel.adoc +++ b/src/reference/asciidoc/spel.adoc @@ -57,7 +57,7 @@ In the above example, the custom function is a static method `calc` on class `My Say you have a `Message` with a payload that has a type `MyFoo` on which you need to perform some action to create a `MyBar` object from it, and you then want to invoke a custom function `calc` on that object. The standard property accessors wouldn't know how to get a `MyBar` from a `MyFoo` so you could write and configure a custom property accessor to do so. -So, your final expression might be`"#barcalc(payload.myBar)"`. +So, your final expression might be `"#barcalc(payload.myBar)"`. The factory bean has another property `typeLocator` which allows you to customize the `TypeLocator` used during SpEL evaluation. This might be necessary when running in some environments that use a non-standard `ClassLoader`.