/* * Copyright 2002-2016 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.handler; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import java.util.Arrays; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.io.Resource; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; import org.springframework.messaging.support.GenericMessage; /** * @author Dave Syer * @author Mark Fisher * @author Gunnar Hillert * @author Gary Russell * @author Artem Bilan * @since 2.0 */ public class ExpressionEvaluatingMessageProcessorTests { private static final Log logger = LogFactory.getLog(ExpressionEvaluatingMessageProcessorTests.class); private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); @Rule public ExpectedException expected = ExpectedException.none(); @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessage() { Expression expression = expressionParser.parseExpression("payload"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); assertEquals("foo", processor.processMessage(new GenericMessage<String>("foo"))); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithParameterCoercion() throws Exception { @SuppressWarnings("unused") class TestTarget { public String stringify(int number) { return number + ""; } } Expression expression = expressionParser.parseExpression("#target.stringify(payload)"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); processor.afterPropertiesSet(); EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class); evaluationContext.setVariable("target", new TestTarget()); assertEquals("2", processor.processMessage(new GenericMessage<String>("2"))); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithVoidResult() throws Exception { @SuppressWarnings("unused") class TestTarget { public void ping(String input) { } } Expression expression = expressionParser.parseExpression("#target.ping(payload)"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); processor.afterPropertiesSet(); EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class); evaluationContext.setVariable("target", new TestTarget()); assertEquals(null, processor.processMessage(new GenericMessage<String>("2"))); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithParameterCoercionToNonPrimitive() throws Exception { class TestTarget { @SuppressWarnings("unused") public String find(Resource[] resources) { return Arrays.asList(resources).toString(); } } Expression expression = expressionParser.parseExpression("#target.find(payload)"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); AbstractApplicationContext applicationContext = new GenericApplicationContext(); processor.setBeanFactory(applicationContext); IntegrationEvaluationContextFactoryBean factoryBean = new IntegrationEvaluationContextFactoryBean(); factoryBean.setApplicationContext(applicationContext); applicationContext.getBeanFactory().registerSingleton(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME, factoryBean.getObject()); applicationContext.refresh(); processor.afterPropertiesSet(); EvaluationContext evaluationContext = TestUtils.getPropertyValue(processor, "evaluationContext", EvaluationContext.class); evaluationContext.setVariable("target", new TestTarget()); String result = (String) processor.processMessage(new GenericMessage<String>("classpath*:*.properties")); assertTrue("Wrong result: " + result, result.contains("log4j.properties")); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithDollarInBrackets() { Expression expression = expressionParser.parseExpression("headers['$foo_id']"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); Message<String> message = MessageBuilder.withPayload("foo").setHeader("$foo_id", "abc").build(); assertEquals("abc", processor.processMessage(message)); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithDollarPropertyAccess() { Expression expression = expressionParser.parseExpression("headers.$foo_id"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); Message<String> message = MessageBuilder.withPayload("foo").setHeader("$foo_id", "xyz").build(); assertEquals("xyz", processor.processMessage(message)); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithStaticKey() { Expression expression = expressionParser.parseExpression("headers[headers.ID]"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); GenericMessage<String> message = new GenericMessage<String>("foo"); assertEquals(message.getHeaders().getId(), processor.processMessage(message)); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithBeanAsMethodArgument() throws Exception { StaticApplicationContext context = new StaticApplicationContext(); BeanDefinition beanDefinition = new RootBeanDefinition(String.class); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("bar"); context.registerBeanDefinition("testString", beanDefinition); context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME, new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class)); context.refresh(); Expression expression = expressionParser.parseExpression("payload.concat(@testString)"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(context); processor.afterPropertiesSet(); GenericMessage<String> message = new GenericMessage<String>("foo"); assertEquals("foobar", processor.processMessage(message)); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageWithMethodCallOnBean() throws Exception { StaticApplicationContext context = new StaticApplicationContext(); BeanDefinition beanDefinition = new RootBeanDefinition(String.class); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("bar"); context.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME, new RootBeanDefinition(IntegrationEvaluationContextFactoryBean.class)); context.registerBeanDefinition("testString", beanDefinition); context.refresh(); Expression expression = expressionParser.parseExpression("@testString.concat(payload)"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(context); processor.afterPropertiesSet(); GenericMessage<String> message = new GenericMessage<String>("foo"); assertEquals("barfoo", processor.processMessage(message)); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageBadExpression() { expected.expect(new TypeSafeMatcher<Exception>(Exception.class) { private Throwable cause; @Override public boolean matchesSafely(Exception item) { logger.debug(item); cause = item.getCause(); return cause instanceof EvaluationException; } @Override public void describeTo(Description description) { description.appendText("cause to be EvaluationException but was ").appendValue(cause); } }); Expression expression = expressionParser.parseExpression("payload.fixMe()"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); assertEquals("foo", processor.processMessage(new GenericMessage<String>("foo"))); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageExpressionThrowsRuntimeException() { expected.expect(new TypeSafeMatcher<Exception>(Exception.class) { private Throwable cause; @Override public boolean matchesSafely(Exception item) { logger.debug(item); cause = item.getCause(); return cause instanceof UnsupportedOperationException; } @Override public void describeTo(Description description) { description.appendText("cause to be UnsupportedOperationException but was ").appendValue(cause); } }); Expression expression = expressionParser.parseExpression("payload.throwRuntimeException()"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); assertEquals("foo", processor.processMessage(new GenericMessage<TestPayload>(new TestPayload()))); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testProcessMessageExpressionThrowsCheckedException() { expected.expect(new TypeSafeMatcher<Exception>(Exception.class) { private Throwable cause; @Override public boolean matchesSafely(Exception item) { logger.debug(item); cause = item.getCause(); return cause instanceof CheckedException; } @Override public void describeTo(Description description) { description.appendText("cause to be CheckedException but was ").appendValue(cause); } }); Expression expression = expressionParser.parseExpression("payload.throwCheckedException()"); ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor(expression); processor.setBeanFactory(mock(BeanFactory.class)); assertEquals("foo", processor.processMessage(new GenericMessage<TestPayload>(new TestPayload()))); } @SuppressWarnings("unused") private static class TestPayload { TestPayload() { super(); } public String throwRuntimeException() { throw new UnsupportedOperationException("Expected test exception"); } public String throwCheckedException() throws Exception { throw new CheckedException("Expected test exception"); } } @SuppressWarnings("serial") private static final class CheckedException extends Exception { CheckedException(String string) { super(string); } } }