INT-1167, INT-836 added 'shouldSkipNulls' option to HeaderEnricher and refactored XPathHeaderEnricher to extend from the core HeaderEnricher
This commit is contained in:
@@ -49,12 +49,14 @@ public class HeaderEnricher implements Transformer {
|
||||
private static final Log logger = LogFactory.getLog(HeaderEnricher.class);
|
||||
|
||||
|
||||
private final Map<String, ValueHolder> headersToAdd;
|
||||
private final Map<String, ? extends ValueHolder> headersToAdd;
|
||||
|
||||
private volatile MessageProcessor messageProcessor;
|
||||
|
||||
private volatile boolean defaultOverwrite = false;
|
||||
|
||||
private volatile boolean shouldSkipNulls = true;
|
||||
|
||||
|
||||
public HeaderEnricher() {
|
||||
this(null);
|
||||
@@ -63,7 +65,7 @@ public class HeaderEnricher implements Transformer {
|
||||
/**
|
||||
* Create a HeaderEnricher with the given map of headers.
|
||||
*/
|
||||
public HeaderEnricher(Map<String, ValueHolder> headersToAdd) {
|
||||
public HeaderEnricher(Map<String, ? extends ValueHolder> headersToAdd) {
|
||||
this.headersToAdd = (headersToAdd != null) ? headersToAdd : new HashMap<String, ValueHolder>();
|
||||
}
|
||||
|
||||
@@ -76,19 +78,29 @@ public class HeaderEnricher implements Transformer {
|
||||
this.defaultOverwrite = defaultOverwrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether <code>null</code> values, such as might be returned from an expression evaluation,
|
||||
* should be skipped. The default value is <code>true</code>. Set this to <code>false</false> if a
|
||||
* <code>null</code> value should trigger <i>removal</i> of the corresponding header instead.
|
||||
*/
|
||||
public void setShouldSkipNulls(boolean shouldSkipNulls) {
|
||||
this.shouldSkipNulls = shouldSkipNulls;
|
||||
}
|
||||
|
||||
public Message<?> transform(Message<?> message) {
|
||||
try {
|
||||
Map<String, Object> headerMap = new HashMap<String, Object>(message.getHeaders());
|
||||
this.addHeadersFromMessageProcessor(message, headerMap);
|
||||
for (Map.Entry<String, ValueHolder> entry : this.headersToAdd.entrySet()) {
|
||||
for (Map.Entry<String, ? extends ValueHolder> entry : this.headersToAdd.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
ValueHolder valueHolder = entry.getValue();
|
||||
Boolean shouldOverwrite = valueHolder.isOverwrite();
|
||||
if (shouldOverwrite == null) {
|
||||
shouldOverwrite = this.defaultOverwrite;
|
||||
}
|
||||
if (shouldOverwrite || headerMap.get(key) == null) {
|
||||
headerMap.put(key, valueHolder.evaluate(message));
|
||||
Object value = valueHolder.evaluate(message);
|
||||
if ((value != null && shouldOverwrite) || headerMap.get(key) == null || (value == null && !this.shouldSkipNulls)) {
|
||||
headerMap.put(key, value);
|
||||
}
|
||||
}
|
||||
return MessageBuilder.withPayload(message.getPayload()).copyHeaders(headerMap).build();
|
||||
|
||||
@@ -16,20 +16,18 @@
|
||||
|
||||
package org.springframework.integration.xml.enricher;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.transformer.Transformer;
|
||||
import org.springframework.integration.transformer.HeaderEnricher;
|
||||
import org.springframework.integration.xml.DefaultXmlPayloadConverter;
|
||||
import org.springframework.integration.xml.XmlPayloadConverter;
|
||||
import org.springframework.integration.xml.xpath.XPathEvaluationType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.xml.xpath.XPathExpression;
|
||||
import org.springframework.xml.xpath.XPathExpressionFactory;
|
||||
|
||||
/**
|
||||
* Transformer implementation that evaluates XPath expressions against the
|
||||
@@ -37,71 +35,60 @@ import org.springframework.xml.xpath.XPathExpression;
|
||||
* header. The header names will match the keys in the map of expressions.
|
||||
*
|
||||
* @author Jonas Partner
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class XPathHeaderEnricher implements Transformer {
|
||||
|
||||
private final Map<String, XPathExpression> expressionMap;
|
||||
|
||||
private Map<String, XPathEvaluationType> evaluationTypes;
|
||||
|
||||
private XPathEvaluationType defaultEvaluationType = XPathEvaluationType.STRING_RESULT;
|
||||
|
||||
private volatile boolean skipNullResults = true;
|
||||
|
||||
private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter();
|
||||
|
||||
public class XPathHeaderEnricher extends HeaderEnricher {
|
||||
|
||||
/**
|
||||
* Create an instance of XPathHeaderEnricher using a map with header names as keys
|
||||
* and XPathExpressions to evaluate as the values. All XPathExpressions are evaluated
|
||||
* as String results by default.
|
||||
*
|
||||
* @param expressionMap
|
||||
* and XPathExpressionValueHolders to evaluate the values.
|
||||
*/
|
||||
public XPathHeaderEnricher(Map<String, XPathExpression> expressionMap) {
|
||||
this.expressionMap = Collections.unmodifiableMap(expressionMap);
|
||||
public XPathHeaderEnricher(Map<String, XPathExpressionValueHolder> expressionMap) {
|
||||
super(expressionMap);
|
||||
}
|
||||
|
||||
|
||||
public void setConverter(XmlPayloadConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
public static class XPathExpressionValueHolder implements ValueHolder {
|
||||
|
||||
public void setSkipNullResults(boolean skipNullResults) {
|
||||
this.skipNullResults = skipNullResults;
|
||||
}
|
||||
private final XPathExpression expression;
|
||||
|
||||
public void setEvaluationTypes(Map<String, XPathEvaluationType> evaluationTypes) {
|
||||
this.evaluationTypes = evaluationTypes;
|
||||
}
|
||||
private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter();
|
||||
|
||||
public void setDefaultEvaluationType(XPathEvaluationType defaultEvaluationType) {
|
||||
this.defaultEvaluationType = defaultEvaluationType;
|
||||
}
|
||||
private volatile XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT;
|
||||
|
||||
public final Message<?> transform(Message<?> message) {
|
||||
MessageBuilder<?> builder = MessageBuilder.fromMessage(message);
|
||||
Node node = this.converter.convertToNode(message.getPayload());
|
||||
Set<String> keys = this.expressionMap.keySet();
|
||||
for (String key : keys) {
|
||||
XPathExpression expression = this.expressionMap.get(key);
|
||||
XPathEvaluationType evalType = this.defaultEvaluationType;
|
||||
if (this.evaluationTypes != null && this.evaluationTypes.containsKey(key)) {
|
||||
evalType = this.evaluationTypes.get(key);
|
||||
}
|
||||
setHeader(node, key, expression, evalType, builder);
|
||||
private volatile Boolean overwrite = null;
|
||||
|
||||
|
||||
public XPathExpressionValueHolder(String expression) {
|
||||
Assert.hasText(expression, "expression must have text");
|
||||
this.expression = XPathExpressionFactory.createXPathExpression(expression);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void setHeader(Node node, String headerName, XPathExpression expression,
|
||||
XPathEvaluationType evaluationType, MessageBuilder<?> builder) {
|
||||
Object result = evaluationType.evaluateXPath(expression, node);
|
||||
boolean nullOrEmptyString = (result == null) ||
|
||||
(result instanceof String && !StringUtils.hasLength((String) result));
|
||||
if (!nullOrEmptyString || !this.skipNullResults) {
|
||||
builder.setHeader(headerName, result);
|
||||
public XPathExpressionValueHolder(XPathExpression expression) {
|
||||
Assert.notNull(expression, "expression must not be null");
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public void setEvaluationType(XPathEvaluationType evaluationType) {
|
||||
this.evaluationType = evaluationType;
|
||||
}
|
||||
|
||||
public void setOverwrite(Boolean overwrite) {
|
||||
this.overwrite = overwrite;
|
||||
}
|
||||
|
||||
public Object evaluate(Message<?> message) {
|
||||
Node node = converter.convertToNode(message.getPayload());
|
||||
Object result = this.evaluationType.evaluateXPath(this.expression, node);
|
||||
if (result instanceof String && ((String) result).length() == 0) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Boolean isOverwrite() {
|
||||
return this.overwrite;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.xml.enricher;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -27,9 +28,8 @@ import org.junit.Test;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.core.MessageHeaders;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.xml.enricher.XPathHeaderEnricher.XPathExpressionValueHolder;
|
||||
import org.springframework.integration.xml.xpath.XPathEvaluationType;
|
||||
import org.springframework.xml.xpath.XPathExpression;
|
||||
import org.springframework.xml.xpath.XPathExpressionFactory;
|
||||
|
||||
/**
|
||||
* @author Jonas Partner
|
||||
@@ -39,9 +39,9 @@ public class XPathHeaderEnricherTests {
|
||||
|
||||
@Test
|
||||
public void simpleStringEvaluation() {
|
||||
Map<String, XPathExpression> expressionMap = new HashMap<String, XPathExpression>();
|
||||
expressionMap.put("one", XPathExpressionFactory.createXPathExpression("/root/elementOne"));
|
||||
expressionMap.put("two", XPathExpressionFactory.createXPathExpression("/root/elementTwo"));
|
||||
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
|
||||
expressionMap.put("one", new XPathExpressionValueHolder("/root/elementOne"));
|
||||
expressionMap.put("two", new XPathExpressionValueHolder("/root/elementTwo"));
|
||||
String docAsString = "<root><elementOne>1</elementOne><elementTwo>2</elementTwo></root>";
|
||||
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
|
||||
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).build());
|
||||
@@ -52,8 +52,8 @@ public class XPathHeaderEnricherTests {
|
||||
|
||||
@Test
|
||||
public void nullValuesSkippedByDefault() {
|
||||
Map<String, XPathExpression> expressionMap = new HashMap<String, XPathExpression>();
|
||||
expressionMap.put("two", XPathExpressionFactory.createXPathExpression("/root/elementTwo"));
|
||||
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
|
||||
expressionMap.put("two", new XPathExpressionValueHolder("/root/elementTwo"));
|
||||
String docAsString = "<root><elementOne>1</elementOne></root>";
|
||||
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
|
||||
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).build());
|
||||
@@ -63,27 +63,29 @@ public class XPathHeaderEnricherTests {
|
||||
|
||||
@Test
|
||||
public void notSkippingNullValues() {
|
||||
Map<String, XPathExpression> expressionMap = new HashMap<String, XPathExpression>();
|
||||
expressionMap.put("two", XPathExpressionFactory.createXPathExpression("/root/elementTwo"));
|
||||
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
|
||||
expressionMap.put("two", new XPathExpressionValueHolder("/root/elementTwo"));
|
||||
String docAsString = "<root><elementOne>1</elementOne></root>";
|
||||
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
|
||||
enricher.setSkipNullResults(false);
|
||||
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).build());
|
||||
enricher.setShouldSkipNulls(false);
|
||||
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).setHeader("two", "x").build());
|
||||
MessageHeaders headers = result.getHeaders();
|
||||
assertEquals("no value set for two when result was null and ignore null was false",
|
||||
"", headers.get("two"));
|
||||
assertNull(headers.get("two"));
|
||||
assertFalse(headers.containsKey("two"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void numberEvaluationResult() {
|
||||
Map<String, XPathExpression> expressionMap = new HashMap<String, XPathExpression>();
|
||||
expressionMap.put("one", XPathExpressionFactory.createXPathExpression("/root/elementOne"));
|
||||
expressionMap.put("two", XPathExpressionFactory.createXPathExpression("/root/elementTwo"));
|
||||
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
|
||||
XPathExpressionValueHolder expression1 = new XPathExpressionValueHolder("/root/elementOne");
|
||||
XPathExpressionValueHolder expression2 = new XPathExpressionValueHolder("/root/elementTwo");
|
||||
expression2.setEvaluationType(XPathEvaluationType.NUMBER_RESULT);
|
||||
expressionMap.put("one", expression1);
|
||||
expressionMap.put("two", expression2);
|
||||
Map<String, XPathEvaluationType> evalTypeMap = new HashMap<String, XPathEvaluationType>();
|
||||
evalTypeMap.put("two", XPathEvaluationType.NUMBER_RESULT);
|
||||
String docAsString = "<root><elementOne>1</elementOne><elementTwo>2</elementTwo></root>";
|
||||
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
|
||||
enricher.setEvaluationTypes(evalTypeMap);
|
||||
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).build());
|
||||
MessageHeaders headers = result.getHeaders();
|
||||
assertEquals("Wrong value for element one expression", "1", headers.get("one"));
|
||||
|
||||
Reference in New Issue
Block a user