INT-2688 Add header-type to xpath-header-enricher

JIRA: https://jira.springsource.org/browse/INT-2688
JIRA: https://jira.springsource.org/browse/INT-3237

Doc Polishing.
This commit is contained in:
Artem Bilan
2014-01-21 16:03:21 +02:00
committed by Gary Russell
parent b817e98a44
commit 16c7ac6134
8 changed files with 89 additions and 23 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2014 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.
@@ -25,22 +25,21 @@ import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractTransformerParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.xml.transformer.XPathHeaderEnricher;
import org.springframework.util.StringUtils;
/**
* Parser for <xpath-header-enricher> elements.
*
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
public class XPathHeaderEnricherParser extends AbstractTransformerParser {
private static final String PACKAGE = "org.springframework.integration.xml.transformer";
@Override
protected final String getTransformerClassName() {
return PACKAGE + ".XPathHeaderEnricher";
return XPathHeaderEnricher.class.getName();
}
@Override
@@ -61,8 +60,8 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser {
Element headerElement = (Element) node;
String elementName = node.getLocalName();
if ("header".equals(elementName)) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
PACKAGE + ".XPathHeaderEnricher$XPathExpressionEvaluatingHeaderValueMessageProcessor");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(IntegrationNamespaceUtils.BASE_PACKAGE
+ ".xml.transformer.XPathHeaderEnricher$XPathExpressionEvaluatingHeaderValueMessageProcessor");
String expressionString = headerElement.getAttribute("xpath-expression");
String expressionRef = headerElement.getAttribute("xpath-expression-ref");
boolean isExpressionString = StringUtils.hasText(expressionString);
@@ -79,6 +78,7 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser {
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, headerElement, "evaluation-type");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, headerElement, "overwrite");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, headerElement, "header-type");
String headerName = headerElement.getAttribute("name");
headers.put(headerName, builder.getBeanDefinition());
}

View File

@@ -20,6 +20,14 @@ import java.util.Map;
import org.w3c.dom.Node;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.transformer.HeaderEnricher;
import org.springframework.integration.transformer.support.HeaderValueMessageProcessor;
import org.springframework.integration.xml.DefaultXmlPayloadConverter;
@@ -37,6 +45,7 @@ import org.springframework.xml.xpath.XPathExpressionFactory;
*
* @author Jonas Partner
* @author Mark Fisher
* @author Artem Bilan
* @since 2.0
*/
public class XPathHeaderEnricher extends HeaderEnricher {
@@ -52,17 +61,21 @@ public class XPathHeaderEnricher extends HeaderEnricher {
}
static class XPathExpressionEvaluatingHeaderValueMessageProcessor implements HeaderValueMessageProcessor<Object> {
static class XPathExpressionEvaluatingHeaderValueMessageProcessor implements HeaderValueMessageProcessor<Object>,
BeanFactoryAware {
private TypeConverter typeConverter = new StandardTypeConverter();
private final XPathExpression expression;
private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter();
private volatile XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT;
private volatile XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT;
private volatile TypeDescriptor headerTypeDescriptor;
private volatile Boolean overwrite = null;
public XPathExpressionEvaluatingHeaderValueMessageProcessor(String expression) {
Assert.hasText(expression, "expression must have text");
this.expression = XPathExpressionFactory.createXPathExpression(expression);
@@ -77,6 +90,12 @@ public class XPathHeaderEnricher extends HeaderEnricher {
this.evaluationType = evaluationType;
}
public void setHeaderType(Class<?> headerType) {
if (headerType != null) {
this.headerTypeDescriptor = TypeDescriptor.valueOf(headerType);
}
}
public void setOverwrite(Boolean overwrite) {
this.overwrite = overwrite;
}
@@ -86,6 +105,14 @@ public class XPathHeaderEnricher extends HeaderEnricher {
return this.overwrite;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
ConversionService conversionService = IntegrationContextUtils.getConversionService(beanFactory);
if (conversionService != null) {
this.typeConverter = new StandardTypeConverter(conversionService);
}
}
@Override
public Object processMessage(Message<?> message) {
Node node = converter.convertToNode(message.getPayload());
@@ -93,7 +120,12 @@ public class XPathHeaderEnricher extends HeaderEnricher {
if (result instanceof String && ((String) result).length() == 0) {
result = null;
}
return result;
if (result != null && this.headerTypeDescriptor != null) {
return this.typeConverter.convertValue(result, TypeDescriptor.forObject(result), this.headerTypeDescriptor);
}
else {
return result;
}
}
}

View File

@@ -441,6 +441,13 @@
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="header-type" type="xsd:string">
<xsd:annotation>
<xsd:documentation source="java:java.lang.Class"><![CDATA[
The fully qualified class name of the header value's expected type.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<!-- XPath Router definition -->

View File

@@ -16,11 +16,11 @@
<xpath-header-enricher input-channel="input" output-channel="output">
<header name="name" xpath-expression="/person/@name" />
<header name="age" xpath-expression="/person/@age" evaluation-type="NUMBER_RESULT" />
<header name="age" xpath-expression="/person/@age" evaluation-type="NUMBER_RESULT" header-type="int"/>
<header name="married" xpath-expression="/person/@married = 'true'" evaluation-type="BOOLEAN_RESULT" />
<header name="node-test" xpath-expression="/person/@age" evaluation-type="NODE_RESULT" />
<header name="node-list-test" xpath-expression="/person/@*" evaluation-type="NODE_LIST_RESULT" />
<header name="ref-test" xpath-expression-ref="testExpression" evaluation-type="NUMBER_RESULT" />
<header name="ref-test" xpath-expression-ref="testExpression" evaluation-type="NUMBER_RESULT" />
</xpath-header-enricher>
<xpath-expression id="testExpression" expression="/person/@age * 2"/>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2014 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.
@@ -28,16 +28,18 @@ import org.w3c.dom.Node;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
* @author Artem Bilan
*
* @since 2.0
*/
@ContextConfiguration
@@ -65,7 +67,7 @@ public class XPathHeaderEnricherParserTests {
@Test
public void numberResult() {
Message<?> result = this.getResultMessage();
assertEquals(new Double(42), result.getHeaders().get("age"));
assertEquals(42, result.getHeaders().get("age"));
}
@Test

View File

@@ -54,6 +54,7 @@
<year>2011</year>
<year>2012</year>
<year>2013</year>
<year>2014</year>
<holder>
GoPivotal, Inc. All Rights Reserved.
</holder>

View File

@@ -20,5 +20,14 @@
<ulink url="https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-3.0-to-4.0-Migration-Guide"
>Migration Guide</ulink>.
</para>
<section id="3.0-xpath-header-enricher-header-type">
<title>Header Type for XPath Header Enricher</title>
<para>
The <code>header-type</code> attribute has been introduced for the <code>header</code> sub-element of the
<code>&lt;int-xml:xpath-header-enricher&gt;</code>. This attribute provides the target type for
the header value to which the result of the XPath expression evaluation will be converted.
For more information see <xref linkend="xml-xpath-header-enricher"/>.
</para>
</section>
</section>
</chapter>

View File

@@ -1051,9 +1051,10 @@
<int:poller></int:poller> ]]><co id="xpath-header-enricher-xml06-co" linkends="xpath-header-enricher-xml06" /><![CDATA[
<int-xml:header name="" ]]><co id="xpath-header-enricher-xml07-co" linkends="xpath-header-enricher-xml07" /><![CDATA[
evaluation-type="STRING_RESULT" ]]><co id="xpath-header-enricher-xml08-co" linkends="xpath-header-enricher-xml08" /><![CDATA[
overwrite="true" ]]><co id="xpath-header-enricher-xml09-co" linkends="xpath-header-enricher-xml09" /><![CDATA[
xpath-expression="" ]]><co id="xpath-header-enricher-xml10-co" linkends="xpath-header-enricher-xml10" /><![CDATA[
xpath-expression-ref=""/> ]]><co id="xpath-header-enricher-xml11-co" linkends="xpath-header-enricher-xml11" /><![CDATA[
header-type="int" ]]><co id="xpath-header-enricher-xml09-co" linkends="xpath-header-enricher-xml09" /><![CDATA[
overwrite="true" ]]><co id="xpath-header-enricher-xml10-co" linkends="xpath-header-enricher-xml10" /><![CDATA[
xpath-expression="" ]]><co id="xpath-header-enricher-xml11-co" linkends="xpath-header-enricher-xml11" /><![CDATA[
xpath-expression-ref=""/> ]]><co id="xpath-header-enricher-xml12-co" linkends="xpath-header-enricher-xml12" /><![CDATA[
</int-xml:xpath-header-enricher>]]>
</programlisting>
<para>
@@ -1102,24 +1103,38 @@
</callout>
<callout arearefs="xpath-header-enricher-xml08-co" id="xpath-header-enricher-xml08">
<para>
The result type expected from the XPath evaluation. This will be the type of the header value.
The result type expected from the XPath evaluation. This will be the type of the header value, if there is no
<code>header-type</code> attribute provided.
The following values are allowed: BOOLEAN_RESULT, STRING_RESULT, NUMBER_RESULT, NODE_RESULT and NODE_LIST_RESULT.
Defaults internally to <code>XPathEvaluationType.STRING_RESULT</code> if not set. <emphasis>Optional</emphasis>.
</para>
</callout>
<callout arearefs="xpath-header-enricher-xml09-co" id="xpath-header-enricher-xml09">
<para>
The fully qualified class name for the header value type. The result of XPath evaluation will be
converted to this type using the <interfacename>ConversionService</interfacename>.
This allows, for example, a <code>NUMBER_RESULT</code> (a double) to be converted to an
<code>Integer</code>. The type can be declared as a primitive (e.g. <code>int</code>) but
the result will always be the equivalent wrapper class (e.g. <code>Integer</code>).
The same integration <interfacename>ConversionService</interfacename> discussed in
<xref linkend="payload-type-conversion"/> is used for the conversion, so conversion to custom
types is supported, by adding a custom converter to the service.
<emphasis>Optional</emphasis>.
</para>
</callout>
<callout arearefs="xpath-header-enricher-xml10-co" id="xpath-header-enricher-xml10">
<para>
Boolean value to indicate whether this header value should overwrite an existing header value for
the same name if already present on the input Message.
</para>
</callout>
<callout arearefs="xpath-header-enricher-xml10-co" id="xpath-header-enricher-xml10">
<callout arearefs="xpath-header-enricher-xml11-co" id="xpath-header-enricher-xml11">
<para>
The XPath Expression as a String. Either this attribute or
<code>xpath-expression-ref</code> must be provided, but not both.
</para>
</callout>
<callout arearefs="xpath-header-enricher-xml11-co" id="xpath-header-enricher-xml11">
<callout arearefs="xpath-header-enricher-xml12-co" id="xpath-header-enricher-xml12">
<para>
The XPath Expression reference. Either this attribute or
<code>xpath-expression</code> must be provided, but not both.