DocumentBuilderFactory

DocumentBuilderFactory

如果Spring Integration的传入XML中存在XmlValidatingMessageSelector部分,如何防止!DOCTYPE中的DTD加载(和验证)?

更新

实际上,在我们的SI配置中,我们有此过滤器配置

@Bean
public MessageSelector cageXmlValidator() {
    XmlValidatingMessageSelector selector = new XmlValidatingMessageSelector(
            new ClassPathResource("/CageMessage.xsd"),
            XmlValidatingMessageSelector.SchemaType.XML_SCHEMA);
    selector.setThrowExceptionOnRejection(true);
    return selector;
}


并以这种方式在我们的流程中使用它

@Bean
public IntegrationFlow processorFlow(
        ...
        MessageSelector cageXmlValidator,
        Unmarshaller cageXmlUnmarshaller,
        ...) {
    return IntegrationFlows
            .from(cageInputChannel())
            ...
            .filter(cageXmlValidator)
            .transform(new UnmarshallingTransformer(cageXmlUnmarshaller))
            ...
            .channel(cageOutputChannel())
            .get();
}


我也尝试过此XmlValidatingMessageSelector定义,但它不起作用

@Bean
public MessageSelector cageXmlValidator() throws Exception {
    XmlValidatingMessageSelector selector = new XmlValidatingMessageSelector(
            new ClassPathResource("/CageMessage.xsd"),
            XmlValidatingMessageSelector.SchemaType.XML_SCHEMA);

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
    factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    selector.setConverter(new DefaultXmlPayloadConverter(factory));

    selector.setThrowExceptionOnRejection(true);
    return selector;
}

最佳答案

我有一个测试用例,如:

@Test
public void testValidMessage() throws Exception {
    Document doc = XmlTestUtil.getDocumentForString("<!DOCTYPE greeting SYSTEM \"greeting.dtd\"><greeting>hello</greeting>");
    GenericMessage<Document> docMessage = new GenericMessage<Document>(doc);
    PollableChannel validChannel = ac.getBean("validOutputChannel", PollableChannel.class);
    MessageChannel inputChannel = ac.getBean("inputChannelA", MessageChannel.class);
    inputChannel.send(docMessage);
    assertNotNull(validChannel.receive(100));
}


请注意MXL代码段中的!DOCTYPE声明。

XmlTestUtil.getDocumentForString()具有以下代码:

DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
builder.setNamespaceAware(true);
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);


return builder.newDocumentBuilder().parse(
        new InputSource(new StringReader(strDoc)));


最新的load-external-dtd功能完全可以满足我的需求。

因此,您的应用程序需要考虑的是在验证之前预先为XML构建Document并将这些功能用于DocumentBuilderFactory

更新

插入带有适当DefaultXmlPayloadConverter的自定义DocumentBuilderFactory对我们的有效负载无效:

validationExceptions = this.xmlValidator.validate(this.converter.convertToSource(message.getPayload()));


convertToSource()如下所示:

public Source convertToSource(Object object) {
    Source source = null;
    if (object instanceof Source) {
        source = (Source) object;
    }
    else if (object instanceof Document) {
        source = new DOMSource((Document) object);
    }
    else if (object instanceof String) {
        source = new StringSource((String) object);
    }
    else {
        throw new MessagingException("unsupported payload type [" + object.getClass().getName() + "]");
    }
    return source;
}


如您所见,没有人调用该DocumentBuilderFactory

我建议您使用.transform()前期.filter(cageXmlValidator)将您的payload转换为具有自定义DocumentDocumentBuilderFactory对象。

看到我们不能影响javax.xml.validation.Validator内部的事实,我认为从验证器调用convertToDocument()并将其包装到DOMSource中将是一个很好的折衷方案。这样,确实,您的DefaultXmlPayloadConverter将会起作用。

随时提出JIRA甚至考虑捐款。

感谢您指出!

09-04 20:44