From 59c69ed40d3755ef59f80872e0ea711adbb13620 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 10 Dec 2018 18:43:15 -0500 Subject: [PATCH] Allow XML components injection **Cherry-pick to 5.0.x & 4.3.x** * Polishing after rebase * Copyright to 2019 * Rebase and update according upstream deps --- build.gradle | 2 +- .../xml/DefaultXmlPayloadConverter.java | 10 ++- .../xml/config/XPathHeaderEnricherParser.java | 19 +++-- .../xml/result/DomResultFactory.java | 17 +++-- .../XmlValidatingMessageSelector.java | 50 +++++++------ .../xml/source/DomSourceFactory.java | 13 ++-- .../xml/source/StringSourceFactory.java | 8 +- .../xml/splitter/XPathMessageSplitter.java | 71 ++++++++++++++---- .../ResultToDocumentTransformer.java | 18 +++-- .../ResultToStringTransformer.java | 27 +++++-- .../transformer/XsltPayloadTransformer.java | 74 +++++++++++-------- ...EvaluatingHeaderValueMessageProcessor.java | 45 ++++++++--- .../integration/xml/xpath/XPathUtils.java | 42 ++++++----- .../xml/config/spring-integration-xml-5.1.xsd | 16 ++++ ...XPathHeaderEnricherParserTests-context.xml | 8 +- .../XPathHeaderEnricherParserTests.java | 58 ++++++++------- .../XsltPayloadTransformerTests.java | 45 +++++++---- 17 files changed, 347 insertions(+), 176 deletions(-) diff --git a/build.gradle b/build.gradle index 218be8bbc6..6158fb3304 100644 --- a/build.gradle +++ b/build.gradle @@ -139,7 +139,7 @@ subprojects { subproject -> springSecurityVersion = '5.1.2.RELEASE' springRetryVersion = '1.2.2.RELEASE' springVersion = project.hasProperty('springVersion') ? project.springVersion : '5.1.4.RELEASE' - springWsVersion = '3.0.4.RELEASE' + springWsVersion = '3.0.5.RELEASE' tomcatVersion = "9.0.12" xstreamVersion = '1.4.11.1' } 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 180062d846..6f3eb05bae 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-2017 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; /** * Default implementation of {@link XmlPayloadConverter}. Supports @@ -48,11 +50,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; } @@ -115,7 +118,7 @@ public class DefaultXmlPayloadConverter implements XmlPayloadConverter { @Override public Node convertToNode(Object object) { - Node node = null; + Node node; if (object instanceof Node) { node = (Node) object; } @@ -130,7 +133,6 @@ public class DefaultXmlPayloadConverter implements XmlPayloadConverter { @Override public Source convertToSource(Object object) { - Source source = null; if (object instanceof Source) { return (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..570925987c 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 { @@ -45,8 +46,8 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser { @Override protected void parseTransformer(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - ManagedMap headers = new ManagedMap(); - this.processHeaders(element, headers, parserContext); + ManagedMap headers = new ManagedMap<>(); + 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 67975e9d75..935df7a948 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 @@ -41,6 +41,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 +65,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,24 +79,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 schemaTypeArg The schema type. - * + * @param schemaType The schema type. * @throws IOException if the XmlValidatorFactory fails to create a validator */ - public XmlValidatingMessageSelector(Resource schema, SchemaType schemaTypeArg) throws IOException { - SchemaType schemaType = schemaTypeArg; - 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()); + public XmlValidatingMessageSelector(Resource schema, SchemaType schemaType) throws IOException { + 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("-", "_"))); } @@ -131,10 +131,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 bdd912f85c..0fed3cadcd 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-2018 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. @@ -48,8 +48,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; @@ -68,7 +70,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(); @@ -76,22 +78,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()); + 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(); @@ -107,12 +136,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; @@ -215,7 +257,7 @@ public class XPathMessageSplitter extends AbstractMessageSplitter { if (nodes instanceof List) { List items = (List) nodes; - List splitStrings = new ArrayList(items.size()); + List splitStrings = new ArrayList<>(items.size()); for (Node nodeFromList : items) { StringResult result = new StringResult(); transformer.transform(new DOMSource(nodeFromList), result); @@ -328,6 +370,7 @@ public class XPathMessageSplitter extends AbstractMessageSplitter { TransformFunctionIterator(Iterator delegate, Function function) { + super(null, delegate, function); this.delegate = delegate; } 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 07dcbbd84a..24e9cb033c 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-2018 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,6 +21,7 @@ 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; @@ -35,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; @@ -48,8 +52,10 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.PatternMatchUtils; import org.springframework.util.StringUtils; +import org.springframework.web.context.support.ServletContextResource; 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 @@ -83,9 +89,9 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be private final ResultTransformer resultTransformer; - private volatile Resource xslResource; + private final Resource xslResource; - private volatile Templates templates; + private Templates templates; private String transformerFactoryClassName; @@ -93,15 +99,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; @@ -110,6 +116,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); } @@ -119,29 +132,25 @@ 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 ServletContextResource || xslResource instanceof VfsResource, + "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) { @@ -151,7 +160,6 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be /** * Sets the ResultFactory. - * * @param resultFactory The result factory. */ @Override @@ -162,7 +170,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) { @@ -171,7 +178,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) { @@ -182,7 +188,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); } @@ -216,15 +223,17 @@ public class XsltPayloadTransformer extends AbstractXmlTransformer implements Be @Override protected void onInit() { 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); } 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)); } @@ -284,13 +293,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) { @@ -320,7 +332,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 6e3653725f..5b8a902b1f 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-2018 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. @@ -31,6 +31,7 @@ import org.w3c.dom.Node; import org.springframework.integration.xml.DefaultXmlPayloadConverter; import org.springframework.integration.xml.XmlPayloadConverter; 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 +42,7 @@ import org.springframework.xml.xpath.XPathExpressionFactory; * * @author Artem Bilan * @author Gary Russell + * * @since 3.0 */ public final class XPathUtils { @@ -57,31 +59,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 org.springframework.messaging.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 +97,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,10 +108,11 @@ 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()); + List documents = new ArrayList<>(nodeList.size()); for (Node n : nodeList) { Document document = documentBuilder.newDocument(); document.appendChild(document.importNode(n, true)); diff --git a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-5.1.xsd b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-5.1.xsd index a2e794f0ef..3ed393f7b5 100644 --- a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-5.1.xsd +++ b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-5.1.xsd @@ -383,6 +383,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 55d66edc83..8983f89378 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-2018 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. @@ -19,21 +19,26 @@ package org.springframework.integration.xml.transformer; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.nio.charset.StandardCharsets; +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.integration.xml.result.DomResultFactory; import org.springframework.integration.xml.result.StringResultFactory; @@ -41,6 +46,7 @@ import org.springframework.integration.xml.util.XmlTestUtil; import org.springframework.messaging.Message; 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; @@ -61,9 +67,12 @@ public class XsltPayloadTransformerTests { private final String outputAsString = "test"; + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Before - public void setUp() { - this.transformer = new XsltPayloadTransformer(getXslResource()); + public void setUp() throws Exception { + this.transformer = new XsltPayloadTransformer(getXslTemplates()); this.transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); this.transformer.setAlwaysUseResultFactory(false); this.transformer.afterPropertiesSet(); @@ -127,8 +136,8 @@ public class XsltPayloadTransformerTests { @Test public void testSourceWithResultTransformer() throws Exception { Integer returnValue = 13; - XsltPayloadTransformer transformer = new XsltPayloadTransformer(getXslResource(), - new StubResultTransformer(returnValue)); + XsltPayloadTransformer transformer = + new XsltPayloadTransformer(getXslTemplates(), new StubResultTransformer(returnValue)); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object transformed = transformer @@ -137,10 +146,10 @@ public class XsltPayloadTransformerTests { } @Test - public void testXsltPayloadWithTransformerFactoryClassname() throws Exception { + public void testXsltPayloadWithTransformerFactoryClassName() throws Exception { Integer returnValue = 13; XsltPayloadTransformer transformer = - new XsltPayloadTransformer(getXslResource(), new StubResultTransformer(returnValue), + new XsltPayloadTransformer(getXslResourceThatOutputsText(), new StubResultTransformer(returnValue), "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); @@ -151,8 +160,8 @@ public class XsltPayloadTransformerTests { } @Test - public void testXsltPayloadWithBadTransformerFactoryClassname() { - XsltPayloadTransformer transformer = new XsltPayloadTransformer(getXslResource(), "foo.bar.Baz"); + public void testXsltPayloadWithBadTransformerFactoryClassName() throws IOException { + XsltPayloadTransformer transformer = new XsltPayloadTransformer(getXslResourceThatOutputsText(), "foo.bar.Baz"); transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); assertThatThrownBy(transformer::afterPropertiesSet) .isExactlyInstanceOf(TransformerFactoryConfigurationError.class); @@ -227,23 +236,29 @@ public class XsltPayloadTransformerTests { assertThat(transformed.toString()).isEqualTo("hello world"); } - private Resource getXslResource() { + private Templates getXslTemplates() throws Exception { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + String xsl = "" + "" + " " + " test" + " " + ""; - return new ByteArrayResource(xsl.getBytes(StandardCharsets.UTF_8)); + + return transformerFactory.newTemplates(new StringSource(xsl)); } - private Resource getXslResourceThatOutputsText() { + private Resource getXslResourceThatOutputsText() throws IOException { String xsl = "" + "" + " " + " hello world" + ""; - return new ByteArrayResource(xsl.getBytes(StandardCharsets.UTF_8)); + + File xsltFile = this.temporaryFolder.newFile(); + FileCopyUtils.copy(xsl.getBytes(), xsltFile); + return new FileSystemResource(xsltFile); } public static class StubResultTransformer implements ResultTransformer {