diff --git a/build.gradle b/build.gradle index 7375c809d9..a3b3de5498 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,7 @@ subprojects { subproject -> springSocialTwitterVersion = '1.1.2.RELEASE' springRetryVersion = '1.1.3.RELEASE' springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.3.22.RELEASE' - springWsVersion = '2.3.0.RELEASE' + springWsVersion = '2.4.4.RELEASE' xmlUnitVersion = '1.6' xstreamVersion = '1.4.7' } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java index 877e45af26..6ab1af064b 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -33,6 +33,8 @@ import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.springframework.messaging.MessagingException; +import org.springframework.util.Assert; +import org.springframework.xml.DocumentBuilderFactoryUtils; import org.springframework.xml.transform.StringSource; /** @@ -49,11 +51,12 @@ public class DefaultXmlPayloadConverter implements XmlPayloadConverter { public DefaultXmlPayloadConverter() { - this.documentBuilderFactory = DocumentBuilderFactory.newInstance(); + this(DocumentBuilderFactoryUtils.newInstance()); this.documentBuilderFactory.setNamespaceAware(true); } public DefaultXmlPayloadConverter(DocumentBuilderFactory documentBuilderFactory) { + Assert.notNull(documentBuilderFactory, "'documentBuilderFactory' must not be null."); this.documentBuilderFactory = documentBuilderFactory; } @@ -116,7 +119,7 @@ public class DefaultXmlPayloadConverter implements XmlPayloadConverter { @Override public Node convertToNode(Object object) { - Node node = null; + Node node; if (object instanceof Node) { node = (Node) object; } @@ -131,7 +134,7 @@ public class DefaultXmlPayloadConverter implements XmlPayloadConverter { @Override public Source convertToSource(Object object) { - Source source = null; + Source source; if (object instanceof Source) { source = (Source) object; } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java index 6c5a3545ca..50c4d0d04f 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2019 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. @@ -34,6 +34,7 @@ import org.springframework.util.StringUtils; * * @author Mark Fisher * @author Artem Bilan + * * @since 2.0 */ public class XPathHeaderEnricherParser extends AbstractTransformerParser { @@ -46,7 +47,7 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser { @Override protected void parseTransformer(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { ManagedMap headers = new ManagedMap(); - this.processHeaders(element, headers, parserContext); + processHeaders(element, headers, parserContext); builder.addConstructorArgValue(headers); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-overwrite"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "should-skip-nulls"); @@ -54,6 +55,7 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser { protected void processHeaders(Element element, ManagedMap headers, ParserContext parserContext) { Object source = parserContext.extractSource(element); + String converter = element.getAttribute("converter"); NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); @@ -62,14 +64,16 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser { String elementName = node.getLocalName(); if ("header".equals(elementName)) { BeanDefinitionBuilder builder = - BeanDefinitionBuilder.genericBeanDefinition(XPathExpressionEvaluatingHeaderValueMessageProcessor.class); + BeanDefinitionBuilder.genericBeanDefinition( + XPathExpressionEvaluatingHeaderValueMessageProcessor.class); String expressionString = headerElement.getAttribute("xpath-expression"); String expressionRef = headerElement.getAttribute("xpath-expression-ref"); boolean isExpressionString = StringUtils.hasText(expressionString); boolean isExpressionRef = StringUtils.hasText(expressionRef); - if (!(isExpressionString ^ isExpressionRef)) { + if (isExpressionString == isExpressionRef) { parserContext.getReaderContext().error( - "Exactly one of the 'xpath-expression' or 'xpath-expression-ref' attributes is required.", source); + "Exactly one of the 'xpath-expression' " + + "or 'xpath-expression-ref' attributes is required.", source); } if (isExpressionString) { builder.addConstructorArgValue(expressionString); @@ -77,6 +81,9 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser { else { builder.addConstructorArgReference(expressionRef); } + if (StringUtils.hasText(converter)) { + builder.addConstructorArgReference(converter); + } IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, headerElement, "evaluation-type"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, headerElement, "overwrite"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, headerElement, "header-type"); diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/result/DomResultFactory.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/result/DomResultFactory.java index 4270bce7d2..ca94bcc66c 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/result/DomResultFactory.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/result/DomResultFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2019 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. @@ -23,23 +23,26 @@ import javax.xml.transform.Result; import javax.xml.transform.dom.DOMResult; import org.springframework.messaging.MessagingException; +import org.springframework.util.Assert; +import org.springframework.xml.DocumentBuilderFactoryUtils; /** * @author Jonas Partner + * @author Artem Bilan */ public class DomResultFactory implements ResultFactory { private final DocumentBuilderFactory documentBuilderFactory; - public DomResultFactory(DocumentBuilderFactory documentBuilderFactory) { - this.documentBuilderFactory = documentBuilderFactory; + public DomResultFactory() { + this(DocumentBuilderFactoryUtils.newInstance()); + this.documentBuilderFactory.setNamespaceAware(true); } - public DomResultFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - this.documentBuilderFactory = factory; + public DomResultFactory(DocumentBuilderFactory documentBuilderFactory) { + Assert.notNull(documentBuilderFactory, "'documentBuilderFactory' must not be null."); + this.documentBuilderFactory = documentBuilderFactory; } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/XmlValidatingMessageSelector.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/XmlValidatingMessageSelector.java index 8c462831f6..efd92da2fa 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/XmlValidatingMessageSelector.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/XmlValidatingMessageSelector.java @@ -21,7 +21,6 @@ import java.util.Arrays; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.xml.sax.SAXParseException; import org.springframework.core.io.Resource; import org.springframework.integration.MessageRejectedException; @@ -41,6 +40,8 @@ import org.springframework.xml.validation.XmlValidatorFactory; * @author Oleg Zhurakousky * @author Gary Russell * @author Liujiong + * @author Artem Bilan + * * @since 2.0 */ public class XmlValidatingMessageSelector implements MessageSelector { @@ -63,19 +64,13 @@ public class XmlValidatingMessageSelector implements MessageSelector { } - private final Log logger = LogFactory.getLog(this.getClass()); + private final Log logger = LogFactory.getLog(getClass()); private final XmlValidator xmlValidator; - private volatile boolean throwExceptionOnRejection; + private boolean throwExceptionOnRejection; - private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); - - - public XmlValidatingMessageSelector(XmlValidator xmlValidator) { - Assert.notNull(xmlValidator, "XmlValidator must not be null"); - this.xmlValidator = xmlValidator; - } + private XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); /** @@ -83,23 +78,28 @@ public class XmlValidatingMessageSelector implements MessageSelector { * the provided 'schema' location {@link Resource} and 'schemaType'. The valid options for schema * type are {@link XmlValidatorFactory#SCHEMA_W3C_XML} or {@link XmlValidatorFactory#SCHEMA_RELAX_NG}. * If no 'schemaType' is provided it will default to {@link XmlValidatorFactory#SCHEMA_W3C_XML}; - * * @param schema The schema. * @param schemaType The schema type. - * * @throws IOException if the XmlValidatorFactory fails to create a validator */ public XmlValidatingMessageSelector(Resource schema, SchemaType schemaType) throws IOException { - Assert.notNull(schema, "You must provide XML schema location to perform validation"); - if (schemaType == null) { - schemaType = SchemaType.XML_SCHEMA; - } - this.xmlValidator = XmlValidatorFactory.createValidator(schema, schemaType.getUrl()); + this(XmlValidatorFactory.createValidator(schema, + schemaType == null + ? SchemaType.XML_SCHEMA.getUrl() + : schemaType.getUrl())); } + public XmlValidatingMessageSelector(XmlValidator xmlValidator) { + Assert.notNull(xmlValidator, "XmlValidator must not be null"); + this.xmlValidator = xmlValidator; + } + + public XmlValidatingMessageSelector(Resource schema, String schemaType) throws IOException { - this(schema, StringUtils.isEmpty(schemaType) ? null : - SchemaType.valueOf(schemaType.toUpperCase().replaceFirst("-", "_"))); + this(schema, + StringUtils.isEmpty(schemaType) + ? null + : SchemaType.valueOf(schemaType.toUpperCase().replaceFirst("-", "_"))); } @@ -119,7 +119,7 @@ public class XmlValidatingMessageSelector implements MessageSelector { @Override public boolean accept(Message message) { - SAXParseException[] validationExceptions = null; + Throwable[] validationExceptions = null; try { validationExceptions = this.xmlValidator.validate(this.converter.convertToSource(message.getPayload())); } @@ -130,10 +130,12 @@ public class XmlValidatingMessageSelector implements MessageSelector { if (!validationSuccess) { if (this.throwExceptionOnRejection) { throw new MessageRejectedException(message, "Message was rejected due to XML Validation errors", - new AggregatedXmlMessageValidationException( - Arrays.asList(validationExceptions))); + new AggregatedXmlMessageValidationException(Arrays.asList(validationExceptions))); + } + else if (this.logger.isInfoEnabled()) { + this.logger.info("Message was rejected due to XML Validation errors", + new AggregatedXmlMessageValidationException(Arrays.asList(validationExceptions))); } - this.logger.debug("Message was rejected due to XML Validation errors"); } return validationSuccess; } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/DomSourceFactory.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/DomSourceFactory.java index dc9ecc8ab6..f83890f8ba 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/DomSourceFactory.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/DomSourceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -29,6 +29,8 @@ import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.springframework.messaging.MessagingException; +import org.springframework.util.Assert; +import org.springframework.xml.DocumentBuilderFactoryUtils; /** * {@link SourceFactory} implementation which supports creation of a {@link DOMSource} @@ -36,6 +38,7 @@ import org.springframework.messaging.MessagingException; * * @author Jonas Partner * @author Mark Fisher + * @author Artem Bilan */ public class DomSourceFactory implements SourceFactory { @@ -43,12 +46,12 @@ public class DomSourceFactory implements SourceFactory { public DomSourceFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - this.documentBuilderFactory = factory; + this(DocumentBuilderFactoryUtils.newInstance()); + this.documentBuilderFactory.setNamespaceAware(true); } public DomSourceFactory(DocumentBuilderFactory documentBuilderFactory) { + Assert.notNull(documentBuilderFactory, "'documentBuilderFactory' must not be null."); this.documentBuilderFactory = documentBuilderFactory; } @@ -87,7 +90,7 @@ public class DomSourceFactory implements SourceFactory { private DOMSource createDomSourceForFile(File file) { try { - Document document = this.getNewDocumentBuilder().parse(file); + Document document = getNewDocumentBuilder().parse(file); return new DOMSource(document.getDocumentElement()); } catch (Exception e) { diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/StringSourceFactory.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/StringSourceFactory.java index 2b2afd7b26..d4f279ad14 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/StringSourceFactory.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/source/StringSourceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -27,9 +27,11 @@ import javax.xml.transform.dom.DOMSource; import org.w3c.dom.Document; import org.springframework.messaging.MessagingException; +import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; import org.springframework.xml.transform.StringResult; import org.springframework.xml.transform.StringSource; +import org.springframework.xml.transform.TransformerFactoryUtils; /** * {@link SourceFactory} implementation which supports creation of a {@link StringSource} @@ -37,6 +39,7 @@ import org.springframework.xml.transform.StringSource; * * @author Jonas Partner * @author Mark Fisher + * @author Artem Bilan */ public class StringSourceFactory implements SourceFactory { @@ -44,10 +47,11 @@ public class StringSourceFactory implements SourceFactory { public StringSourceFactory() { - this(TransformerFactory.newInstance()); + this(TransformerFactoryUtils.newInstance()); } public StringSourceFactory(TransformerFactory transformerFactory) { + Assert.notNull(transformerFactory, "'transformerFactory' must not be null."); this.transformerFactory = transformerFactory; } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/splitter/XPathMessageSplitter.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/splitter/XPathMessageSplitter.java index e3922aa160..30392a7ad4 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/splitter/XPathMessageSplitter.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/splitter/XPathMessageSplitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -49,8 +49,10 @@ import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.converter.MessageConversionException; import org.springframework.util.Assert; +import org.springframework.xml.DocumentBuilderFactoryUtils; import org.springframework.xml.namespace.SimpleNamespaceContext; import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.TransformerFactoryUtils; import org.springframework.xml.xpath.XPathException; import org.springframework.xml.xpath.XPathExpression; import org.springframework.xml.xpath.XPathExpressionFactory; @@ -69,7 +71,7 @@ import org.springframework.xml.xpath.XPathExpressionFactory; */ public class XPathMessageSplitter extends AbstractMessageSplitter { - private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); + private final TransformerFactory transformerFactory; private final Object documentBuilderFactoryMonitor = new Object(); @@ -77,22 +79,49 @@ public class XPathMessageSplitter extends AbstractMessageSplitter { private javax.xml.xpath.XPathExpression jaxpExpression; - private volatile boolean createDocuments; + private boolean createDocuments; - private volatile DocumentBuilderFactory documentBuilderFactory; + private DocumentBuilderFactory documentBuilderFactory; - private volatile XmlPayloadConverter xmlPayloadConverter = new DefaultXmlPayloadConverter(); + private XmlPayloadConverter xmlPayloadConverter = new DefaultXmlPayloadConverter(); - private volatile Properties outputProperties; + private Properties outputProperties; - private volatile boolean iterator = true; + private boolean iterator = true; public XPathMessageSplitter(String expression) { this(expression, new HashMap()); } + /** + * Construct an instance based on the provided xpath expression and + * {@link TransformerFactory}. + * @param expression the xpath expression for splitting. + * @param transformerFactory the {@link TransformerFactory} + * for parsing and building documents. + * @since 4.3.19 + */ + public XPathMessageSplitter(String expression, TransformerFactory transformerFactory) { + this(expression, new HashMap(), transformerFactory); + } + public XPathMessageSplitter(String expression, Map namespaces) { - this(XPathExpressionFactory.createXPathExpression(expression, namespaces)); + this(expression, namespaces, TransformerFactoryUtils.newInstance()); + } + + /** + * Construct an instance based on the provided xpath expression, namespaces and + * {@link TransformerFactory}. + * @param expression the xpath expression for splitting. + * @param namespaces the XML namespace for parsing. + * @param transformerFactory the {@link TransformerFactory} + * for parsing and building documents. + * @since 4.3.19 + */ + public XPathMessageSplitter(String expression, Map namespaces, + TransformerFactory transformerFactory) { + + this(XPathExpressionFactory.createXPathExpression(expression, namespaces), transformerFactory); XPath xpath = XPathFactory.newInstance().newXPath(); SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext(); @@ -108,12 +137,25 @@ public class XPathMessageSplitter extends AbstractMessageSplitter { } public XPathMessageSplitter(XPathExpression xpathExpression) { - Assert.notNull(xpathExpression, "'xpathExpression' must not be null."); - this.xpathExpression = xpathExpression; - this.documentBuilderFactory = DocumentBuilderFactory.newInstance(); - this.documentBuilderFactory.setNamespaceAware(true); + this(xpathExpression, TransformerFactoryUtils.newInstance()); } + /** + * Construct an instance based on the provided xpath expression and + * {@link TransformerFactory}. + * @param xpathExpression the xpath expression for splitting. + * @param transformerFactory the {@link TransformerFactory} + * for parsing and building documents. + * @since 4.3.19 + */ + public XPathMessageSplitter(XPathExpression xpathExpression, TransformerFactory transformerFactory) { + Assert.notNull(xpathExpression, "'xpathExpression' must not be null."); + Assert.notNull(transformerFactory, "'transformerFactory' must not be null."); + this.xpathExpression = xpathExpression; + this.transformerFactory = transformerFactory; + this.documentBuilderFactory = DocumentBuilderFactoryUtils.newInstance(); + this.documentBuilderFactory.setNamespaceAware(true); + } public void setCreateDocuments(boolean createDocuments) { this.createDocuments = createDocuments; @@ -277,7 +319,7 @@ public class XPathMessageSplitter extends AbstractMessageSplitter { private int index; - private NodeListIterator(NodeList nodeList) throws ParserConfigurationException { + NodeListIterator(NodeList nodeList) throws ParserConfigurationException { this.nodeList = nodeList; if (XPathMessageSplitter.this.createDocuments) { this.documentBuilder = getNewDocumentBuilder(); diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToDocumentTransformer.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToDocumentTransformer.java index 038b9cf983..53eb0d7643 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToDocumentTransformer.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToDocumentTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2019 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,6 +28,8 @@ import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.springframework.messaging.MessagingException; +import org.springframework.util.Assert; +import org.springframework.xml.DocumentBuilderFactoryUtils; import org.springframework.xml.transform.StringResult; /** @@ -35,6 +37,7 @@ import org.springframework.xml.transform.StringResult; * {@link DOMResult} and {@link StringResult} implementations. * * @author Jonas Partner + * @author Artem Bilan */ public class ResultToDocumentTransformer implements ResultTransformer { @@ -42,18 +45,19 @@ public class ResultToDocumentTransformer implements ResultTransformer { private final DocumentBuilderFactory documentBuilderFactory; - public ResultToDocumentTransformer(DocumentBuilderFactory documentBuilderFactory) { - this.documentBuilderFactory = documentBuilderFactory; + public ResultToDocumentTransformer() { + this(DocumentBuilderFactoryUtils.newInstance()); + this.documentBuilderFactory.setNamespaceAware(true); } - public ResultToDocumentTransformer() { - this.documentBuilderFactory = DocumentBuilderFactory.newInstance(); - this.documentBuilderFactory.setNamespaceAware(true); + public ResultToDocumentTransformer(DocumentBuilderFactory documentBuilderFactory) { + Assert.notNull(documentBuilderFactory, "'documentBuilderFactory' must not be null."); + this.documentBuilderFactory = documentBuilderFactory; } public Object transformResult(Result result) { - Document document = null; + Document document; if (DOMResult.class.isAssignableFrom(result.getClass())) { document = createDocumentFromDomResult((DOMResult) result); } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToStringTransformer.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToStringTransformer.java index f22d1c9f14..675f86990a 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToStringTransformer.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/ResultToStringTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2019 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. @@ -27,7 +27,9 @@ import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import org.springframework.messaging.MessagingException; +import org.springframework.util.Assert; import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.TransformerFactoryUtils; /** * Converts the passed {@link Result} to an instance of {@link String}. @@ -35,16 +37,27 @@ import org.springframework.xml.transform.StringResult; * * @author Jonas Partner * @author Mark Fisher + * @author Artem Bilan */ public class ResultToStringTransformer implements ResultTransformer { - private volatile Properties outputProperties; - private final TransformerFactory transformerFactory; + private Properties outputProperties; + public ResultToStringTransformer() { - this.transformerFactory = TransformerFactory.newInstance(); + this.transformerFactory = TransformerFactoryUtils.newInstance(); + } + + /** + * Construct an instance based on the provided {@link TransformerFactory}. + * @param transformerFactory the {@link TransformerFactory} to use. + * @since 4.3.19 + */ + public ResultToStringTransformer(TransformerFactory transformerFactory) { + Assert.notNull(transformerFactory, "'transformerFactory' must not be null."); + this.transformerFactory = transformerFactory; } @@ -55,12 +68,12 @@ public class ResultToStringTransformer implements ResultTransformer { public Object transformResult(Result result) { String returnString = null; if (result instanceof StringResult) { - returnString = ((StringResult) result).toString(); + returnString = result.toString(); } else if (result instanceof DOMResult) { try { StringResult stringResult = new StringResult(); - this.getNewTransformer().transform( + getNewTransformer().transform( new DOMSource(((DOMResult) result).getNode()), stringResult); returnString = stringResult.toString(); } @@ -76,7 +89,7 @@ public class ResultToStringTransformer implements ResultTransformer { } private Transformer getNewTransformer() throws TransformerConfigurationException { - Transformer transformer = null; + Transformer transformer; synchronized (this.transformerFactory) { transformer = this.transformerFactory.newTransformer(); } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java index ac5ee40e8a..741858fc74 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XsltPayloadTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -21,10 +21,12 @@ import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; +import javax.xml.XMLConstants; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; @@ -34,7 +36,10 @@ import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; +import org.springframework.core.io.VfsResource; import org.springframework.expression.Expression; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.integration.expression.ExpressionUtils; @@ -45,11 +50,13 @@ import org.springframework.integration.xml.source.SourceFactory; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.PatternMatchUtils; import org.springframework.util.StringUtils; import org.springframework.xml.transform.StringResult; import org.springframework.xml.transform.StringSource; +import org.springframework.xml.transform.TransformerFactoryUtils; /** * Thread safe XSLT transformer implementation which returns a transformed @@ -80,11 +87,24 @@ import org.springframework.xml.transform.StringSource; */ public class XsltPayloadTransformer extends AbstractXmlTransformer implements BeanClassLoaderAware { + private static final Class SERVLET_CONTEXT_RESOURCE_CLASS; + + static { + Class theClass = null; + try { + theClass = ClassUtils.forName("org.springframework.web.context.support.ServletContextResource", null); + } + catch (ClassNotFoundException e) { + // + } + SERVLET_CONTEXT_RESOURCE_CLASS = theClass; + } + private final ResultTransformer resultTransformer; - private volatile Resource xslResource; + private final Resource xslResource; - private volatile Templates templates; + private Templates templates; private String transformerFactoryClassName; @@ -92,15 +112,15 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be private Map xslParameterMappings; - private volatile SourceFactory sourceFactory = new DomSourceFactory(); + private SourceFactory sourceFactory = new DomSourceFactory(); - private volatile boolean resultFactoryExplicitlySet; + private boolean resultFactoryExplicitlySet; - private volatile boolean alwaysUseSourceFactory = false; + private boolean alwaysUseSourceFactory = false; - private volatile boolean alwaysUseResultFactory = false; + private boolean alwaysUseResultFactory = false; - private volatile String[] xsltParamHeaders; + private String[] xsltParamHeaders; private ClassLoader classLoader; @@ -109,6 +129,13 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be this(templates, null); } + public XsltPayloadTransformer(Templates templates, ResultTransformer resultTransformer) { + Assert.notNull(templates, "'templates' must not be null."); + this.templates = templates; + this.resultTransformer = resultTransformer; + this.xslResource = null; + } + public XsltPayloadTransformer(Resource xslResource) { this(xslResource, null, null); } @@ -118,29 +145,27 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be } public XsltPayloadTransformer(Resource xslResource, String transformerFactoryClassName) { - Assert.notNull(xslResource, "'xslResource' must not be null."); - Assert.hasText(transformerFactoryClassName, "'transformerFactoryClassName' must not be empty String."); - this.xslResource = xslResource; - this.transformerFactoryClassName = transformerFactoryClassName; - this.resultTransformer = null; + this(xslResource, null, transformerFactoryClassName); } - public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer, String transformerFactoryClassName) { + public XsltPayloadTransformer(Resource xslResource, ResultTransformer resultTransformer, + String transformerFactoryClassName) { + Assert.notNull(xslResource, "'xslResource' must not be null."); + Assert.isTrue(xslResource instanceof ClassPathResource || xslResource instanceof FileSystemResource || + xslResource instanceof VfsResource || + (SERVLET_CONTEXT_RESOURCE_CLASS != null + && SERVLET_CONTEXT_RESOURCE_CLASS.isAssignableFrom(xslResource.getClass())), + "Only 'ClassPathResource', 'FileSystemResource', 'ServletContextResource' or 'VfsResource'" + + " are supported directly in this transformer. For any other 'Resource' implementations" + + " consider to use a 'Templates'-based constructor instantiation."); this.xslResource = xslResource; this.resultTransformer = resultTransformer; this.transformerFactoryClassName = transformerFactoryClassName; } - public XsltPayloadTransformer(Templates templates, ResultTransformer resultTransformer) { - Assert.notNull(templates, "'templates' must not be null."); - this.templates = templates; - this.resultTransformer = resultTransformer; - } - /** * Sets the SourceFactory. - * * @param sourceFactory The source factory. */ public void setSourceFactory(SourceFactory sourceFactory) { @@ -150,7 +175,6 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be /** * Sets the ResultFactory. - * * @param resultFactory The result factory. */ @Override @@ -161,7 +185,6 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be /** * Specify whether to always use source factory even for directly supported payload types. - * * @param alwaysUseSourceFactory true to always use the source factory. */ public void setAlwaysUseSourceFactory(boolean alwaysUseSourceFactory) { @@ -170,7 +193,6 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be /** * Specify whether to always use result factory even for directly supported payload types - * * @param alwaysUseResultFactory true to always use the result factory. */ public void setAlwaysUseResultFactory(boolean alwaysUseResultFactory) { @@ -181,7 +203,8 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be this.xslParameterMappings = xslParameterMappings; } - public void setXsltParamHeaders(String[] xsltParamHeaders) { + public void setXsltParamHeaders(String... xsltParamHeaders) { + Assert.notNull(xsltParamHeaders, "'xsltParamHeaders' must not be null."); this.xsltParamHeaders = Arrays.copyOf(xsltParamHeaders, xsltParamHeaders.length); } @@ -215,16 +238,27 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be @Override protected void onInit() throws Exception { super.onInit(); - this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); + this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); if (this.templates == null) { TransformerFactory transformerFactory; if (this.transformerFactoryClassName != null) { - transformerFactory = TransformerFactory.newInstance(this.transformerFactoryClassName, this.classLoader); + transformerFactory = TransformerFactory.newInstance(this.transformerFactoryClassName, + this.classLoader); } else { - transformerFactory = TransformerFactory.newInstance(); + transformerFactory = TransformerFactoryUtils.newInstance(); + } + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "file,jar:file"); + try { + this.templates = transformerFactory.newTemplates(createStreamSourceOnResource(this.xslResource)); + } + catch (TransformerConfigurationException e) { + throw new IllegalStateException(e); + } + catch (IOException e) { + throw new IllegalStateException(e); } - this.templates = transformerFactory.newTemplates(createStreamSourceOnResource(this.xslResource)); } } @@ -278,13 +312,16 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be return transformSource(source, payload, transformer); } - private Object transformSource(Source source, Object payload, Transformer transformer) throws TransformerException { + private Object transformSource(Source source, Object payload, Transformer transformer) + throws TransformerException { + Result result; - if (!this.resultFactoryExplicitlySet && "text".equals(transformer.getOutputProperties().getProperty("method"))) { + if (!this.resultFactoryExplicitlySet && + "text".equals(transformer.getOutputProperties().getProperty("method"))) { result = new StringResult(); } else { - result = this.getResultFactory().createResult(payload); + result = getResultFactory().createResult(payload); } transformer.transform(source, result); if (this.resultTransformer != null) { @@ -314,7 +351,7 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be else { source = new DOMSource(documentPayload); } - Result result = this.getResultFactory().createResult(documentPayload); + Result result = getResultFactory().createResult(documentPayload); if (!DOMResult.class.isAssignableFrom(result.getClass())) { throw new MessagingException( "Document to Document conversion requires a DOMResult-producing ResultFactory implementation."); diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java index 7fd45dc301..6b83ee195e 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2019 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. @@ -38,31 +38,55 @@ import org.springframework.xml.xpath.XPathExpressionFactory; * @author Jonas Partner * @author Mark Fisher * @author Artem Bilan + * * @since 2.0 */ public class XPathExpressionEvaluatingHeaderValueMessageProcessor implements HeaderValueMessageProcessor, BeanFactoryAware { - private static final XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); - private final BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(); private final XPathExpression expression; - private volatile XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT; + private final XmlPayloadConverter converter; - private volatile TypeDescriptor headerTypeDescriptor; + private XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT; - private volatile Boolean overwrite = null; + private TypeDescriptor headerTypeDescriptor; + + private Boolean overwrite; public XPathExpressionEvaluatingHeaderValueMessageProcessor(String expression) { - Assert.hasText(expression, "expression must have text"); - this.expression = XPathExpressionFactory.createXPathExpression(expression); + this(expression, new DefaultXmlPayloadConverter()); + } + + /** + * Construct an instance based on the provided xpath expression and {@link XmlPayloadConverter}. + * @param expression the xpath expression to evaluate. + * @param converter the {@link XmlPayloadConverter} to use for document conversion. + * @since 4.3.19 + */ + public XPathExpressionEvaluatingHeaderValueMessageProcessor(String expression, XmlPayloadConverter converter) { + this(XPathExpressionFactory.createXPathExpression(expression), converter); } public XPathExpressionEvaluatingHeaderValueMessageProcessor(XPathExpression expression) { - Assert.notNull(expression, "expression must not be null"); + this(expression, new DefaultXmlPayloadConverter()); + } + + /** + * Construct an instance based on the provided xpath expression and {@link XmlPayloadConverter}. + * @param expression the xpath expression to evaluate. + * @param converter the {@link XmlPayloadConverter} to use for document conversion. + * @since 4.3.19 + */ + public XPathExpressionEvaluatingHeaderValueMessageProcessor(XPathExpression expression, + XmlPayloadConverter converter) { + + Assert.notNull(expression, "'expression' must not be null."); + Assert.notNull(converter, "'converter' must not be null."); this.expression = expression; + this.converter = converter; } public void setEvaluationType(XPathEvaluationType evaluationType) { @@ -94,7 +118,7 @@ public class XPathExpressionEvaluatingHeaderValueMessageProcessor implements Hea @Override public Object processMessage(Message message) { - Node node = converter.convertToNode(message.getPayload()); + Node node = this.converter.convertToNode(message.getPayload()); Object result = this.evaluationType.evaluateXPath(this.expression, node); if (result instanceof String && ((String) result).length() == 0) { result = null; @@ -106,4 +130,5 @@ public class XPathExpressionEvaluatingHeaderValueMessageProcessor implements Hea return result; } } + } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/xpath/XPathUtils.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/xpath/XPathUtils.java index 4a305ab50f..f566b18d6a 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/xpath/XPathUtils.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/xpath/XPathUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2019 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. @@ -30,8 +30,8 @@ import org.w3c.dom.Node; import org.springframework.integration.xml.DefaultXmlPayloadConverter; import org.springframework.integration.xml.XmlPayloadConverter; -import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; +import org.springframework.xml.DocumentBuilderFactoryUtils; import org.springframework.xml.xpath.NodeMapper; import org.springframework.xml.xpath.XPathException; import org.springframework.xml.xpath.XPathExpression; @@ -41,6 +41,7 @@ import org.springframework.xml.xpath.XPathExpressionFactory; * Utility class for 'xpath' support. * * @author Artem Bilan + * * @since 3.0 */ public final class XPathUtils { @@ -57,31 +58,36 @@ public final class XPathUtils { public static final String DOCUMENT_LIST = "document_list"; - private static List RESULT_TYPES = Arrays.asList(STRING, BOOLEAN, NUMBER, NODE, NODE_LIST, DOCUMENT_LIST); + private static final List RESULT_TYPES = + Arrays.asList(STRING, BOOLEAN, NUMBER, NODE, NODE_LIST, DOCUMENT_LIST); - private static XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); + private static final XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); - private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactoryUtils.newInstance(); + + static { + documentBuilderFactory.setNamespaceAware(true); + } /** * Utility method to evaluate an xpath on the provided object. * Delegates evaluation to an {@link XPathExpression}. * Note this method provides the {@code #xpath()} SpEL function. - * - * - * @param o the xml Object for evaluaton. - * @param xpath an 'xpath' expression String. + * @param object the xml Object for evaluation. + * @param xpath an 'xpath' expression String. * @param resultArg an optional parameter to represent the result type of the xpath evaluation. - * Only one argument is allowed, which can be an instance of {@link org.springframework.xml.xpath.NodeMapper} or - * one of these String constants: "string", "boolean", "number", "node" or "node_list". - * @param The required return type. + * Only one argument is allowed, which can be an instance of + * {@link org.springframework.xml.xpath.NodeMapper} or + * one of these String constants: "string", "boolean", "number", "node" or "node_list". + * @param The required return type. * @return the result of the xpath expression evaluation. * @throws IllegalArgumentException - if the provided arguments aren't appropriate types or values; - * @throws MessagingException - if the provided object can't be converted to a {@link Node}; + * @throws org.springframework.messaging.MessagingException - if the provided + * object can't be converted to a {@link Node}; * @throws XPathException - if the xpath expression can't be evaluated. */ - @SuppressWarnings({"unchecked"}) - public static T evaluate(Object o, String xpath, Object... resultArg) { + @SuppressWarnings({ "unchecked" }) + public static T evaluate(Object object, String xpath, Object... resultArg) { Object resultType = null; if (resultArg != null && resultArg.length > 0) { Assert.isTrue(resultArg.length == 1, "'resultArg' can contains only one element."); @@ -90,7 +96,7 @@ public final class XPathUtils { } XPathExpression expression = XPathExpressionFactory.createXPathExpression(xpath); - Node node = converter.convertToNode(o); + Node node = converter.convertToNode(object); if (resultType == null) { return (T) expression.evaluateAsString(node); @@ -101,7 +107,8 @@ public final class XPathUtils { else if (resultType instanceof String && RESULT_TYPES.contains(resultType)) { String resType = (String) resultType; if (DOCUMENT_LIST.equals(resType)) { - List nodeList = (List) XPathEvaluationType.NODE_LIST_RESULT.evaluateXPath(expression, node); + List nodeList = (List) XPathEvaluationType.NODE_LIST_RESULT.evaluateXPath(expression, + node); try { DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); List documents = new ArrayList(nodeList.size()); diff --git a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-4.3.xsd b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-4.3.xsd index f32604c86c..e6927d9afa 100644 --- a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-4.3.xsd +++ b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-4.3.xsd @@ -367,6 +367,22 @@ + + + + Specify the XmlPayloadConverter to use when converting a Message payload prior + to XPath evaluation. + The DefaultXmlPayloadConverter is used if this reference is not provided, and it + should be sufficient in most cases since it can convert from Node, Document, Source, + File, and String typed payloads. + + + + + + + + diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests-context.xml b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests-context.xml index 7b944e10fc..c3819a73d1 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests-context.xml +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests-context.xml @@ -53,8 +53,14 @@
- +
+ + diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests.java index 8135617d76..ad6e8aea05 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XPathHeaderEnricherParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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,12 +17,16 @@ package org.springframework.integration.xml.config; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.List; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,12 +41,13 @@ import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.support.SmartLifecycleRoleController; import org.springframework.integration.test.util.TestUtils; +import org.springframework.integration.transformer.support.HeaderValueMessageProcessor; +import org.springframework.integration.xml.transformer.support.XPathExpressionEvaluatingHeaderValueMessageProcessor; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.PollableChannel; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.MultiValueMap; /** @@ -52,8 +57,7 @@ import org.springframework.util.MultiValueMap; * * @since 2.0 */ -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @DirtiesContext public class XPathHeaderEnricherParserTests { @@ -66,11 +70,12 @@ public class XPathHeaderEnricherParserTests { @Autowired private ApplicationContext context; - private final Message message = MessageBuilder.withPayload("").build(); + private final Message message = + MessageBuilder.withPayload("").build(); @Test - public void testParse() throws Exception { + public void testParse() { EventDrivenConsumer consumer = (EventDrivenConsumer) context.getBean("parseOnly"); assertEquals(2, TestUtils.getPropertyValue(consumer, "handler.order")); assertEquals(123L, TestUtils.getPropertyValue(consumer, "handler.messagingTemplate.sendTimeout")); @@ -115,35 +120,36 @@ public class XPathHeaderEnricherParserTests { public void nodeListResult() { Message result = this.getResultMessage(); Object header = result.getHeaders().get("node-list-test"); - assertTrue(List.class.isAssignableFrom(header.getClass())); + assertThat(header, instanceOf(List.class)); List nodeList = (List) header; + assertNotNull(nodeList); assertEquals(3, nodeList.size()); } @Test public void expressionRef() { - Message result = this.getResultMessage(); - assertEquals(new Double(84), result.getHeaders().get("ref-test")); + Message result = getResultMessage(); + assertEquals(84d, result.getHeaders().get("ref-test")); } @Test - public void defaultOverwrite() { - assertEquals(false, this.getEnricherProperty("defaultHeaderEnricher", "defaultOverwrite")); + public void testDefaultHeaderEnricher() { + assertFalse(getEnricherProperty("defaultHeaderEnricher", "defaultOverwrite")); + assertTrue(getEnricherProperty("defaultHeaderEnricher", "shouldSkipNulls")); } @Test - public void defaultShouldSkipNulls() { - assertEquals(true, this.getEnricherProperty("defaultHeaderEnricher", "shouldSkipNulls")); - } - - @Test - public void customOverwrite() { - assertEquals(true, this.getEnricherProperty("customHeaderEnricher", "defaultOverwrite")); - } - - @Test - public void customShouldSkipNulls() { - assertEquals(false, this.getEnricherProperty("customHeaderEnricher", "shouldSkipNulls")); + @SuppressWarnings("unchecked") + public void testCustomHeaderEnricher() { + assertTrue(getEnricherProperty("customHeaderEnricher", "defaultOverwrite")); + assertFalse(getEnricherProperty("customHeaderEnricher", "shouldSkipNulls")); + Map> headersToAdd = + TestUtils.getPropertyValue(this.context.getBean("customHeaderEnricher"), + "handler.transformer.headersToAdd", Map.class); + HeaderValueMessageProcessor headerValueMessageProcessor = headersToAdd.get("foo"); + assertThat(headerValueMessageProcessor, instanceOf(XPathExpressionEvaluatingHeaderValueMessageProcessor.class)); + assertSame(this.context.getBean("xmlPayloadConverter"), + TestUtils.getPropertyValue(headerValueMessageProcessor, "converter")); } @Test @@ -155,6 +161,7 @@ public class XPathHeaderEnricherParserTests { .build(); this.context.getBean("defaultInput", MessageChannel.class).send(request); Message reply = replyChannel.receive(); + assertNotNull(reply); assertEquals("John Doe", reply.getHeaders().get("foo")); } @@ -167,6 +174,7 @@ public class XPathHeaderEnricherParserTests { .build(); this.context.getBean("customInput", MessageChannel.class).send(request); Message reply = replyChannel.receive(); + assertNotNull(reply); assertEquals("bar", reply.getHeaders().get("foo")); } @@ -180,7 +188,7 @@ public class XPathHeaderEnricherParserTests { Object endpoint = this.context.getBean(beanName); Object handler = new DirectFieldAccessor(endpoint).getPropertyValue("handler"); Object enricher = new DirectFieldAccessor(handler).getPropertyValue("transformer"); - return ((Boolean) new DirectFieldAccessor(enricher).getPropertyValue(propertyName)).booleanValue(); + return (boolean) new DirectFieldAccessor(enricher).getPropertyValue(propertyName); } } diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java index e799a06f25..704f554f75 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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,25 +20,32 @@ import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.io.IOException; + import javax.xml.transform.Result; +import javax.xml.transform.Templates; import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.mockito.Mockito; import org.w3c.dom.Document; import org.springframework.beans.factory.BeanFactory; -import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessagingException; -import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.xml.result.StringResultFactory; import org.springframework.integration.xml.util.XmlTestUtil; +import org.springframework.messaging.MessagingException; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.util.FileCopyUtils; import org.springframework.xml.transform.StringResult; import org.springframework.xml.transform.StringSource; @@ -53,21 +60,26 @@ public class XsltPayloadTransformerTests { private XsltPayloadTransformer transformer; - private final String docAsString = "test"; + private final String docAsString = "test" + + ""; private final String outputAsString = "test"; + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Before public void setUp() throws Exception { - transformer = new XsltPayloadTransformer(getXslResource()); - transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); - transformer.afterPropertiesSet(); + this.transformer = new XsltPayloadTransformer(getXslTemplates()); + this.transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); + this.transformer.setAlwaysUseResultFactory(false); + this.transformer.afterPropertiesSet(); } @Test public void testDocumentAsPayload() throws Exception { - Object transformed = transformer.doTransform(buildMessage(XmlTestUtil - .getDocumentForString(docAsString))); + Object transformed = + transformer.doTransform(new GenericMessage<>(XmlTestUtil.getDocumentForString(docAsString))); assertTrue("Wrong return type for document payload", Document.class .isAssignableFrom(transformed.getClass())); Document transformedDocument = (Document) transformed; @@ -78,7 +90,7 @@ public class XsltPayloadTransformerTests { @Test public void testSourceAsPayload() throws Exception { Object transformed = transformer - .doTransform(buildMessage(new StringSource(docAsString))); + .doTransform(new GenericMessage<>(new StringSource(docAsString))); assertEquals("Wrong return type for source payload", DOMResult.class, transformed.getClass()); DOMResult result = (DOMResult) transformed; @@ -89,7 +101,7 @@ public class XsltPayloadTransformerTests { @Test public void testStringAsPayload() throws Exception { - Object transformed = transformer.doTransform(buildMessage(docAsString)); + Object transformed = transformer.doTransform(new GenericMessage<>(docAsString)); assertEquals("Wrong return type for string payload", String.class, transformed.getClass()); String transformedString = (String) transformed; @@ -100,7 +112,7 @@ public class XsltPayloadTransformerTests { @Test public void testStringAsPayloadUseResultFactoryTrue() throws Exception { transformer.setAlwaysUseResultFactory(true); - Object transformed = transformer.doTransform(buildMessage(docAsString)); + Object transformed = transformer.doTransform(new GenericMessage<>(docAsString)); assertEquals("Wrong return type for useFactories true", DOMResult.class, transformed.getClass()); DOMResult result = (DOMResult) transformed; @@ -111,46 +123,46 @@ public class XsltPayloadTransformerTests { @Test public void testSourceWithResultTransformer() throws Exception { - Integer returnValue = new Integer(13); - transformer = new XsltPayloadTransformer(getXslResource(), - new StubResultTransformer(returnValue)); + Integer returnValue = 13; + XsltPayloadTransformer transformer = + new XsltPayloadTransformer(getXslTemplates(), new StubResultTransformer(returnValue)); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object transformed = transformer - .doTransform(buildMessage(new StringSource(docAsString))); + .doTransform(new GenericMessage<>(new StringSource(docAsString))); assertEquals("Wrong value from result conversion", returnValue, transformed); } @Test - public void testXsltPayloadWithTransformerFactoryClassname() throws Exception { - Integer returnValue = new Integer(13); - transformer = new XsltPayloadTransformer(getXslResource(), new StubResultTransformer(returnValue), - "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); + public void testXsltPayloadWithTransformerFactoryClassName() throws Exception { + Integer returnValue = 13; + XsltPayloadTransformer transformer = + new XsltPayloadTransformer(getXslResourceThatOutputsText(), new StubResultTransformer(returnValue), + "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object transformed = transformer - .doTransform(buildMessage(new StringSource(docAsString))); + .doTransform(new GenericMessage<>(new StringSource(docAsString))); assertEquals("Wrong value from result conversion", returnValue, transformed); } @Test(expected = TransformerFactoryConfigurationError.class) public void testXsltPayloadWithBadTransformerFactoryClassname() throws Exception { - transformer = new XsltPayloadTransformer(getXslResource(), "foo.bar.Baz"); + transformer = new XsltPayloadTransformer(getXslResourceThatOutputsText(), "foo.bar.Baz"); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); - transformer.doTransform(buildMessage(new StringSource(docAsString))); } @Test(expected = TransformerException.class) public void testNonXmlString() throws Exception { - transformer.doTransform(buildMessage("test")); + transformer.doTransform(new GenericMessage<>("test")); } @Test(expected = MessagingException.class) public void testUnsupportedPayloadType() throws Exception { - transformer.doTransform(buildMessage(new Long(12))); + transformer.doTransform(new GenericMessage<>(12L)); } @Test @@ -160,7 +172,7 @@ public class XsltPayloadTransformerTests { transformer = new XsltPayloadTransformer(resource); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); - assertEquals(transformer.doTransform(buildMessage(docAsString)), + assertEquals(transformer.doTransform(new GenericMessage<>(docAsString)), outputAsString); } @@ -174,7 +186,7 @@ public class XsltPayloadTransformerTests { transformer.setAlwaysUseResultFactory(true); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); - Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); + Object returned = transformer.doTransform(new GenericMessage<>(XmlTestUtil.getDocumentForString(docAsString))); assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); } @@ -188,7 +200,7 @@ public class XsltPayloadTransformerTests { transformer.setAlwaysUseResultFactory(true); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); - Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); + Object returned = transformer.doTransform(new GenericMessage<>(XmlTestUtil.getDocumentForString(docAsString))); assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); } @@ -199,32 +211,34 @@ public class XsltPayloadTransformerTests { transformer.setAlwaysUseResultFactory(true); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); - Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); + Object returned = transformer.doTransform(new GenericMessage<>(XmlTestUtil.getDocumentForString(docAsString))); assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); assertEquals("Wrong content in string", "hello world", returned.toString()); } - protected Message buildMessage(Object payload) { - return MessageBuilder.withPayload(payload).build(); - } + private Templates getXslTemplates() throws Exception { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); - private Resource getXslResource() throws Exception { String xsl = "" + "" + " " + " test" + " " + ""; - return new ByteArrayResource(xsl.getBytes("UTF-8")); + + return transformerFactory.newTemplates(new StringSource(xsl)); } - private Resource getXslResourceThatOutputsText() throws Exception { + private Resource getXslResourceThatOutputsText() throws IOException { String xsl = "" + "" + " " + " hello world" + ""; - return new ByteArrayResource(xsl.getBytes("UTF-8")); + + File xsltFile = this.temporaryFolder.newFile(); + FileCopyUtils.copy(xsl.getBytes(), xsltFile); + return new FileSystemResource(xsltFile); } public static class StubResultTransformer implements ResultTransformer { @@ -238,6 +252,7 @@ public class XsltPayloadTransformerTests { public Object transformResult(Result result) { return objectToReturn; } + } }