Ошибка unmarshalling xml в java-8 "безопасная обработка org.xml.sax.SAXNotRecognizedException, вызывающая java.lang.IllegalStateException"

Следующий код прекрасно работал в Java 7

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

String xmlString = '<xml ..... ';

StringReader reader = new StringReader(xmlString);

JAXBContext jc = JAXBContext.newInstance(MyClass.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
MyClass myClass = (MyClass) unmarshaller.unmarshal(reader);
....

Теперь нам пришлось обновиться до Java 8, и теперь я получаю это исключение при выполнении кода:

Sep 03, 2014 1:42:47 PM com.sun.xml.internal.bind.v2.util.XmlFactory createParserFactory
SCHWERWIEGEND: null
org.xml.sax.SAXNotRecognizedException: Feature: http://javax.xml.XMLConstants/feature/secure-processing
    at org.apache.xerces.jaxp.SAXParserFactoryImpl.setFeature(SAXParserFactoryImpl.java:100)
    at com.sun.xml.internal.bind.v2.util.XmlFactory.createParserFactory(XmlFactory.java:114)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.getXMLReader(UnmarshallerImpl.java:139)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:214)

Я знаю, что есть вопрос, нацеленный на подобную проблему, но возвращение к Java 7 не является решением для меня.

Я попытался добавить следующую зависимость Maven

<dependency>
    <groupId>javax.xml</groupId>
    <artifactId>jaxp-api</artifactId>
    <version>1.4</version>
</dependency>

но это не изменило результат, поэтому я удалил его (спасибо @BlaiseDoughan за информацию, что это включено в Java 6)

Любые советы приветствуются, большое спасибо.

14 ответов

Решение

Это была проблема зависимости.

Вот мой способ, как я решил проблему:

  1. Создайте новый проект maven, с этими простыми кусочками кода, которые я прикрепил ниже, программа нормально рухнула с ошибкой, что структура не может быть проанализирована, что нормально.
  2. Скопируйте ваши зависимости в проект pom.xml, теперь программа должна аварийно завершить работу (как описано выше)

  3. Нет, вы удаляете зависимости после предпочитаемого вами метода (хорошее предположение, деление на части, 1 на 1 ...), чтобы найти "плохую" зависимость. Может быть, у кого-то есть лучший (более профессиональный) метод, этот работал для меня.

теперь вы можете решить, что делать, возможно, доступна новая версия, в нашем случае это был собственный пакет колледжа, в который он включил пакет колледжа, который я могу исключить.

public class Test {
    public Test() {
    }
    public static void main(String[] args) {
        try {
            StringReader reader = new StringReader("<xml></xml>");
            JAXBContext jc = JAXBContext.newInstance(TestXML.class);
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            TestXML testXMLs = (TestXML) unmarshaller.unmarshal(reader);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

и класс testXML

@XmlRootElement(name="rss")
@XmlAccessorType(XmlAccessType.FIELD)
public class TestXML {   
    public TestXML() {
    }

    @XmlElementWrapper(name="channel")
    @XmlElement(name="item")
    private int i ;

    public int getI() {
        return i;
    }    
    public void setI(int i) {
        this.i = i;
    }
}

Кстати: в моем случае это было

<dependency>
    <groupId>jcs</groupId>
    <artifactId>jcs</artifactId>
    <version>1.3</version>
</dependency>

Надеюсь, это поможет.

У нас была похожая проблема - наш главный разработчик нашел решение, которое работает для нас.

Мы добавили эту зависимость в пару наших файлов pom.xml

Для тех, кто заботится, провальные модульные тесты в Sonar, по-видимому, терпели неудачу, потому что Cobatura по умолчанию использует старую версию xerces. Версия, которую он загружает, несовместима с JAX-B в Java 8. Библиотека не используется в производственном коде - только Cobatura. Поэтому исправлением было добавление тестовой зависимости к более поздней версии xerces (2.11.0). Это делается путем добавления зависимости в файл pom:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
    <scope>test</scope>
</dependency>

Xerces Impl является основным виновником здесь. Убери это. JDK имеет встроенный Jaxb парсер, вам это не нужно.

Итак, если эта зависимость исходит от родительского проекта в случае maven, используйте вкладку исключения, если вы не можете удалить ее напрямую.

<exclusion>
                 <groupId>xerces</groupId>  
            <artifactId>xercesImpl</artifactId> 
                </exclusion>

Причина, по которой эту проблему так трудно обнаружить, заключается в том, что, когда вы обычно пишете код jaxb с демаршалингом

вы сделаете unmarshalling в блоке try, а затем поймаете исключение jaxb и затем сделаете все с ошибкой.

Но этот синтаксический анализатор jar (xercesimpl) выбрасывает исключение времени выполнения в середине, вызывая ошибку, чтобы не регистрироваться и будет обнаружен только после тщательной отладки. Посмотрите на фрагмент кода ниже

try {
JAXBContext context = JAXBContext.newInstance(YourClass.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            YourClass object = (YourClass)unmarshaller.unmarshal(new StringReader("SomeXmlInString"));


}

catch (JAXBException e){
e.printStackTrace();

}

Здесь xercesImpl заставляет unmarshaller использовать какой-то другой синтаксический анализатор sax (вместо обычного синтаксического анализатора jaxb), заставляя его генерировать другое исключение, которое не будет поймано в нашем блоке catch, который ожидает jaxbexception или один из его подклассов.

Другое возможное решение для этого - добавить системные переменные:

Я использовал их в плагине Maven Tomcat, который работал для меня:

<javax.xml.parsers.DocumentBuilderFactory>com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl</javax.xml.parsers.DocumentBuilderFactory>
<org.xml.sax.parser>com.sun.org.apache.xerces.internal.parsers.SAXParser</org.xml.sax.parser>
<javax.xml.parsers.SAXParserFactory>com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl</javax.xml.parsers.SAXParserFactory>

Но вы также должны быть в состоянии установить следующее:

java -Dorg.xml.sax.parser="com.sun.org.apache.xerces.internal.parsers.SAXParser" \
-Djavax.xml.parsers.DocumentBuilderFactory="com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl" \
-Djavax.xml.parsers.SAXParserFactory="com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"

или даже использовать System.setProperty:

System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser");
System.setProperty("javax.xml.parsers.DocumentBuilderFactory","com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
System.setProperty("javax.xml.parsers.SAXParserFactory","com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");

Реализация JAXB была включена в Java SE начиная с версии 6. Если вы удалите зависимость Maven (которая, вероятно, вызывает конфликт версий), все должно работать.

Ответы Бернарда и Блейза были очень полезны. В моем случае, поскольку я использую JDK 7, решением было исключить субзависимость xerces, которая была включена в одну из моих зависимостей:

<dependency>
  <groupId>org.apache.axis</groupId>
  <artifactId>axis</artifactId>
  <version>1.4.1-SNAPSHOT</version>
  <exclusions>
    <exclusion>
      <groupId>xerces</groupId>
      <artifactId>xercesImpl</artifactId>
    </exclusion>
    <exclusion>
      <groupId>xerces</groupId>
      <artifactId>xmlParserAPIs</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Я решил эту проблему в своем проекте с помощью второго решения Митча, но только с

java -Djavax.xml.parsers.SAXParserFactory="com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"

Попробуйте создать XML-документ и распаковать его. Это сработало для меня. JAXBContext jc = JAXBContext.newInstance( Message.class);

        InputStream stream = new ByteArrayInputStream( string.getBytes( StandardCharsets.UTF_8 ) );
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse( stream );

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Message msg = ( Message ) unmarshaller.unmarshal( doc );

Использование SAXparser может быть кошмаром. Это наиболее широко используемый синтаксический анализатор XML в Java, и каждый из них в конечном итоге использует его прямо или косвенно. JDK 8 уже имеет JAXB. Так что, если вы используете JDK 8, то единственным возможным способом должно быть удаление зависимости maven. У меня тоже была эта проблема, поэтому я попытался удалить зависимость maven, но не получилось. Тогда я подумал, почему бы не вернуться к более старой версии, если Java и VOILLA я добился успеха. Я использую JDK 7 в настоящее время, и мои тесты проходят гладко. Я думаю, что это единственное решение.

У меня была аналогичная проблема при попытке устранить уязвимость сонара. java:S2755.

      SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // added (for sonar)
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // added (for sonar)

После добавления этих двух строк первая setProperty() звонок бросил SAXNotRecognizedException.

Я предполагаю, что это произошло потому, что было доступно несколько реализаций XMLSchemaFactory, один из которых включен в JDK.

Моим решением было бежать mvn dependency:treeна проекте и ищите вхождения "xerces". Я обнаружил две зависимости, которые я исключил из всех зависимостей, которые их использовали:

      <dependency>
    <!-- ... -->
    <exclusions>
        <exclusion>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
        </exclusion>
    </exclusions>
</dependency>
      <dependency>
    <!-- ... -->
    <exclusions>
        <exclusion>
            <groupId>com.rackspace.apache</groupId>
            <artifactId>xerces2-xsd11</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Я сталкивался с подобной проблемой, эта проблема возникает, когда существует большая разница в версиях xerces jar и xercesImpl jar. Чтобы решить эту проблему, я использовал xerces-2.9.0 и xercesImpl-2.9.1, и проблема исчезла.

Мы также столкнулись с этой проблемой и заметили, что необходимо сохранить одинаковые версию jdk и версию jre, иначе будет существовать несовпадение версий, вызвавшее проблему.

Ребята, которые столкнулись с проблемой, используют jdk1.6 и jre 1.8, когда меняли обе версии на jdk1.6, проблема исчезла.

У меня была такая же проблема, и она была исправлена ​​путем установки аргументов JVM как -Djavax.xml.accessExternalDTD=all -Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl

Наши симптомы были

      java.lang.SecurityException: AuthConfigFactory error: java.lang.reflect.InvocationTargetException <SNIP>
java.lang.reflect.InvocationTargetException <SNIP>
java.lang.SecurityException: org.xml.sax.SAXNotRecognizedException: http://apache.org/xml/features/allow-java-encodings <SNIP>
org.xml.sax.SAXNotRecognizedException: http://apache.org/xml/features/allow-java-encodings

Как предложил @foxpas, я добавил следующее в setenv.sh для нашего экземпляра tomcat 8.5.34, работающего с OpenJDK 1.8.0_292-b10.

      -Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
Другие вопросы по тегам