NodeList.getLength() возвращает 0 в Java 11

Я переношу свое приложение с Java 8 на Java 11. В Java 8 мой входной XML-файл анализировался правильно, но в Java 11 nodeList.getLength() возвращает 0.
Пожалуйста, обратитесь к коду, согласно которому я всегда получаю сообщение об ошибке : Cannot find signature.

Я пробовал использовать document.getElementsByTagName("Signature") вместо getElementsByTagNameNS(), что возвращает правильный length. Однако метод unmarshalXMLSignature() затем выдает ошибку, что реализация документа должна поддерживать DOM уровня 2 и учитывать пространство имен.
Есть ли проблемы с использованием метода getElementsByTagNameNS() в Java 11?

private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
. . .
document = documentBuilderFactory.newDocumentBuilder().parse(input);
final NodeList nodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nodeList.getLength() == 0) {
    throw new SecurityException("Cannot find signature");
}
final XMLValidateContext validateContext = new DOMValidateContext(newX509KeySelector(), nodeList.item(0));
final XMLSignature signature = getXMLSignatureFactory().unmarshalXMLSignature(validateContext);
. . .

Редактировать 1: входной xml

    <?xml version="1.0" encoding="UTF-8" standalone="no"?><License>
        <id>999</id>
        <companyName>TRXX</companyName>
        <creationDate>01-01-2016</creationDate>
        <expirationDate>never</expirationDate>
        <features>
            <feature>
                <name>drwwy</name>
                <value>true</value>
                <description>drwwy module</description>
            </feature>
            <feature>
                <name>pnp</name>
                <value>true</value>
                <description>Index Number Management module</description>
            </feature>
        </features>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="">
<Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>l5Cl4E=</DigestValue></Reference></SignedInfo><SignatureValue>R3zBkE=</SignatureValue>
<KeyInfo><X509Data><X509SubjectName>CN=TRXX Inc,OU=Product Development,O=TRXX Inc,L=Scotle,ST=Atlanta,C=US</X509SubjectName><X509Certificate>MIY</X509Certificate>
</X509Data></KeyInfo></Signature></License>

Редактировать 2: я понял, что ранее я вводил DocumentBuilderFactory, который является частью JDK, но он больше не разрешен в Java 11. Вот почему я создал его с помощью DocumentBuilderFactory.newInstance(), но с этим длина моего списка узлов равна нуль. Можем ли мы использовать какой-либо другой способ создания экземпляра объекта DocumentBuilderFactory?


person Aditya Batra    schedule 03.01.2019    source источник
comment
Пожалуйста, добавьте XML, чтобы воспроизвести проблему.   -  person Karol Dowbecki    schedule 03.01.2019
comment
Спасибо @KarolDowbecki, добавил входной XML   -  person Aditya Batra    schedule 03.01.2019


Ответы (1)


Если вы используете document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");, вы получаете пустой список узлов, а предоставленный исходный код выдает ваш new SecurityException("Cannot find signature").

Если вы document.getElementsByTagName("Signature"), элемент Signature будет найден, но без учета пространства имен, что вызовет это исключение позже:

javax.xml.crypto.MarshalException: Document implementation must support DOM Level 2 and be namespace aware
  at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshal(DOMXMLSignatureFactory.java:189)
  at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshalXMLSignature(DOMXMLSignatureFactory.java:150)

При исследовании термина getElementsByTagNameNS(XMLSignature.XMLNS, "Signature") я нашел примеры кода, в которых они активируют осведомленность о пространстве имен в новом экземпляре DocumentBuilderFactory вручную:

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);

Это должно решить вашу проблему new SecurityException("Cannot find signature").

Что касается вашего предыдущего вопроса, вы не только перенесли Java 8 на 11, но и CDI API, OpenWebBeans, Apache Tomcat и, возможно, другие модули, кто-то еще должен был сделать эту активацию осведомленности о пространстве имен для вас ранее. Или, говоря по-другому, вы @Injected экземпляр DocumentBuilderFactory с учетом пространства имен.

Изменить:

Для ручной настройки и внедрения DocumentBuilderFactory создайте метод, который @Produces создает экземпляр DocumentBuilderFactory и предоставляет этот экземпляр для внедрения в другом месте:

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.xml.parsers.DocumentBuilderFactory;

@Dependent
public class DocumentBuilderFactoryProducer {
    @Produces
    @ApplicationScoped
    public DocumentBuilderFactory createDocumentBuilderFactory() {
        DocumentBuilderFactory result = DocumentBuilderFactory.newInstance();
        result.setNamespaceAware(true);
        // other customizations ...
        return result;
    }
}

Это может быть введено в другие bean-компоненты следующим образом:

@Inject
private DocumentBuilderFactory documentBuilderFactory;
person Selaron    schedule 07.01.2019
comment
Спасибо. Это то, что я использовал в Java 8, но без @ApplicationScoped. Добавил аннотацию на уровне класса, и это решило мою проблему. - person Aditya Batra; 08.01.2019
comment
Эта деталь плюс исходный код могли бы ускорить воспроизведение и ответ на ваш предыдущий вопрос на несколько дней. Даже не знал об аннотации @Produces. Но благодаря этому я многое узнал о CDI :-) - person Selaron; 09.01.2019