diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java index 0e32bc975a..4933f1adf0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2013 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. @@ -20,9 +20,9 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.expression.DynamicExpression; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; - import org.w3c.dom.Element; /** @@ -30,9 +30,10 @@ import org.w3c.dom.Element; * expression evaluator when handling consumed Messages. These classes * use a FactoryBean implementation to construct the actual endpoint * instance. - * + * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell */ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumerEndpointParser { @@ -50,7 +51,8 @@ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumer if (innerDefinition != null) { if (hasRef || hasExpression || expressionElement != null) { parserContext.getReaderContext().error( - "Neither 'ref' nor 'expression' are permitted when an inner bean () is configured.", source); + "Neither 'ref' nor 'expression' are permitted when an inner bean () is configured on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); return null; } builder.addPropertyValue("targetObject", innerDefinition); @@ -58,7 +60,8 @@ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumer else if (scriptElement != null) { if (hasRef || hasExpression || expressionElement != null) { parserContext.getReaderContext().error( - "Neither 'ref' nor 'expression' are permitted when an inner script element is configured.", source); + "Neither 'ref' nor 'expression' are permitted when an inner script element is configured on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); return null; } BeanDefinition scriptBeanDefinition = parserContext.getDelegate().parseCustomElement(scriptElement, builder.getBeanDefinition()); @@ -67,17 +70,24 @@ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumer else if (expressionElement != null) { if (hasRef || hasExpression) { parserContext.getReaderContext().error( - "Neither 'ref' nor 'expression' are permitted when an inner 'expression' element is configured.", source); + "Neither 'ref' nor 'expression' are permitted when an inner 'expression' element is configured on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); return null; } BeanDefinitionBuilder dynamicExpressionBuilder = BeanDefinitionBuilder.genericBeanDefinition( - "org.springframework.integration.expression.DynamicExpression"); + DynamicExpression.class); String key = expressionElement.getAttribute("key"); String expressionSourceReference = expressionElement.getAttribute("source"); dynamicExpressionBuilder.addConstructorArgValue(key); dynamicExpressionBuilder.addConstructorArgReference(expressionSourceReference); builder.addPropertyValue("expression", dynamicExpressionBuilder.getBeanDefinition()); } + else if (hasRef && hasExpression) { + parserContext.getReaderContext().error( + "Only one of 'ref' or 'expression' is permitted, not both, on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); + return null; + } else if (hasRef) { builder.addPropertyReference("targetObject", ref); } @@ -87,21 +97,23 @@ abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumer else if (!this.hasDefaultOption()) { parserContext.getReaderContext().error("Exactly one of the 'ref' attribute, 'expression' attribute, " + "or inner bean () definition is required for element " + - IntegrationNamespaceUtils.createElementDescription(element) + ".", element); + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); return null; } String method = element.getAttribute(METHOD_ATTRIBUTE); if (StringUtils.hasText(method)) { - if (hasExpression) { + if (hasExpression || expressionElement != null) { parserContext.getReaderContext().error( - "A 'method' attribute is not permitted when configuring an 'expression'.", element); + "A 'method' attribute is not permitted when configuring an 'expression' on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); } if (hasRef || innerDefinition != null) { builder.addPropertyValue("targetMethodName", method); } else { parserContext.getReaderContext().error("A 'method' attribute is only permitted when either " + - "a 'ref' or inner-bean definition is provided.", element); + "a 'ref' or inner-bean definition is provided on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", source); } } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply"); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultRouterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultRouterParser.java index d434544a6b..4cdfb45701 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultRouterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DefaultRouterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2013 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. @@ -18,25 +18,26 @@ package org.springframework.integration.config.xml; import java.util.List; -import org.w3c.dom.Element; - import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.RouterFactoryBean; import org.springframework.util.CollectionUtils; import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; /** * Parser for the <router/> element. - * + * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell */ public class DefaultRouterParser extends AbstractDelegatingConsumerEndpointParser { @Override String getFactoryBeanClassName() { - return IntegrationNamespaceUtils.BASE_PACKAGE + ".config.RouterFactoryBean"; + return RouterFactoryBean.class.getName(); } @Override diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/FilterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/FilterParser.java index d315c3f6d3..b8d33f68fb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/FilterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/FilterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2013 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,21 +16,22 @@ package org.springframework.integration.config.xml; -import org.w3c.dom.Element; - import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.FilterFactoryBean; +import org.w3c.dom.Element; /** * Parser for the <filter/> element. - * + * * @author Mark Fisher + * @author Gary Russell */ public class FilterParser extends AbstractDelegatingConsumerEndpointParser { @Override String getFactoryBeanClassName() { - return IntegrationNamespaceUtils.BASE_PACKAGE + ".config.FilterFactoryBean"; + return FilterFactoryBean.class.getName(); } @Override diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java index 1f0c3b15cd..98a6a00a8c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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 @@ -285,10 +285,13 @@ public abstract class IntegrationNamespaceUtils { innerComponentDefinition = new BeanComponentDefinition(inDef, bdHolder.getBeanName()); } String ref = element.getAttribute(REF_ATTRIBUTE); - Assert.isTrue(!(StringUtils.hasText(ref) && innerComponentDefinition != null), + if (StringUtils.hasText(ref) && innerComponentDefinition != null) { + parserContext.getReaderContext().error( "Ambiguous definition. Inner bean " + (innerComponentDefinition == null ? innerComponentDefinition : innerComponentDefinition.getBeanDefinition().getBeanClassName()) - + " declaration and \"ref\" " + ref + " are not allowed together."); + + " declaration and \"ref\" " + ref + " are not allowed together on element " + + IntegrationNamespaceUtils.createElementDescription(element) + ".", parserContext.extractSource(element)); + } return innerComponentDefinition; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java index aa71ea9355..86ef91cb3c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ServiceActivatorParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2013 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,17 +16,20 @@ package org.springframework.integration.config.xml; +import org.springframework.integration.config.ServiceActivatorFactoryBean; + /** * Parser for the <service-activator> element. - * + * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell */ public class ServiceActivatorParser extends AbstractDelegatingConsumerEndpointParser { @Override String getFactoryBeanClassName() { - return "org.springframework.integration.config.ServiceActivatorFactoryBean"; + return ServiceActivatorFactoryBean.class.getName(); } @Override diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/SplitterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/SplitterParser.java index 61c30902e9..acad5f04ea 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/SplitterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/SplitterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2013 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. @@ -18,19 +18,21 @@ package org.springframework.integration.config.xml; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.SplitterFactoryBean; import org.w3c.dom.Element; /** * Parser for the <splitter/> element. - * + * * @author Mark Fisher * @author Iwein Fuld + * @author Gary Russell */ public class SplitterParser extends AbstractDelegatingConsumerEndpointParser { @Override String getFactoryBeanClassName() { - return IntegrationNamespaceUtils.BASE_PACKAGE + ".config.SplitterFactoryBean"; + return SplitterFactoryBean.class.getName(); } @Override diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/TransformerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/TransformerParser.java index 5566be709d..b16930aa4f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/TransformerParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/TransformerParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2013 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,16 +16,19 @@ package org.springframework.integration.config.xml; +import org.springframework.integration.config.TransformerFactoryBean; + /** * Parser for the <transformer/> element. - * + * * @author Mark Fisher + * @author Gary Russell */ public class TransformerParser extends AbstractDelegatingConsumerEndpointParser { @Override String getFactoryBeanClassName() { - return IntegrationNamespaceUtils.BASE_PACKAGE + ".config.TransformerFactoryBean"; + return TransformerFactoryBean.class.getName(); } @Override diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-expression-and-bean-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-expression-and-bean-context.xml new file mode 100644 index 0000000000..4372483cc0 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-expression-and-bean-context.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-expression-and-expression-element-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-expression-and-expression-element-context.xml new file mode 100644 index 0000000000..21e5c060b8 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-expression-and-expression-element-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-method-and-expression-element-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-method-and-expression-element-context.xml new file mode 100644 index 0000000000..e9968bd67c --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-method-and-expression-element-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-no-service-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-no-service-context.xml new file mode 100644 index 0000000000..d9ce4f6c18 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-no-service-context.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-ref-and-bean-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-ref-and-bean-context.xml new file mode 100644 index 0000000000..e739b3c2be --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-ref-and-bean-context.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-ref-and-expression-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-ref-and-expression-context.xml new file mode 100644 index 0000000000..5979dc0709 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests-fail-ref-and-expression-context.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java index 6dca7a109f..7b980e8832 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ServiceActivatorParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,11 +17,15 @@ package org.springframework.integration.config.xml; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.integration.core.MessagingTemplate; @@ -112,6 +116,89 @@ public class ServiceActivatorParserTests { assertEquals("bar", result); } + @Test + public void failRefAndExpression() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-ref-and-expression-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: Only one of 'ref' or 'expression' is permitted, not both, " + + "on element 'service-activator' with id='test'.")); + } + } + + @Test + public void failRefAndBean() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-ref-and-bean-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: Ambiguous definition. " + + "Inner bean org.springframework.integration.config.xml.ServiceActivatorParserTests$TestBean " + + "declaration and \"ref\" testBean are not allowed together on element " + + "'service-activator' with id='test'.")); + } + } + + @Test + public void failExpressionAndBean() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-expression-and-bean-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: Neither 'ref' nor 'expression' " + + "are permitted when an inner bean () is configured on element " + + "'service-activator' with id='test'.")); + } + } + + @Test + public void failNoService() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-no-service-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: Exactly one of the 'ref' " + + "attribute, 'expression' attribute, or inner bean () definition " + + "is required for element 'service-activator' with id='test'.")); + } + } + + @Test + public void failExpressionAndExpression() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-expression-and-expression-element-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: Neither 'ref' nor 'expression' are permitted when " + + "an inner 'expression' element is configured on element " + + "'service-activator' with id='test'.")); + } + } + + @Test + public void failMethodAndExpressionElement() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-method-and-expression-element-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: A 'method' attribute is not permitted when configuring " + + "an 'expression' on element 'service-activator' with id='test'.")); + } + } + private Object sendAndReceive(MessageChannel channel, Object payload) { MessagingTemplate template = new MessagingTemplate(channel); return template.convertSendAndReceive(payload); diff --git a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/ServiceActivatorParserTests-fail-expression-and-script-context.xml b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/ServiceActivatorParserTests-fail-expression-and-script-context.xml new file mode 100644 index 0000000000..2a78ec331b --- /dev/null +++ b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/ServiceActivatorParserTests-fail-expression-and-script-context.xml @@ -0,0 +1,16 @@ + + + + + + payload + + + + diff --git a/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/ServiceActivatorParserTests.java b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/ServiceActivatorParserTests.java new file mode 100644 index 0000000000..202325ab68 --- /dev/null +++ b/spring-integration-groovy/src/test/java/org/springframework/integration/groovy/config/ServiceActivatorParserTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2013 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.groovy.config; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Gary Russell + * @since 2.2 + */ +public class ServiceActivatorParserTests { + + @Test + public void failExpressionAndScript() { + try { + new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-expression-and-script-context.xml", + this.getClass()); + fail("Expected exception"); + } + catch (BeanDefinitionParsingException e) { + assertTrue(e.getMessage().startsWith("Configuration problem: Neither 'ref' nor 'expression' are permitted when " + + "an inner script element is configured on element 'service-activator' with id='test'.")); + } + } + +}