在 java-8“安全处理 org.xml.sax.SAXNotRecognizedException 导致 java.lang.IllegalStateException”中解组 xml 时出错

Posted

技术标签:

【中文标题】在 java-8“安全处理 org.xml.sax.SAXNotRecognizedException 导致 java.lang.IllegalStateException”中解组 xml 时出错【英文标题】:Error unmarshalling xml in java-8 "secure-processing org.xml.sax.SAXNotRecognizedException causing java.lang.IllegalStateException" 【发布时间】:2014-10-27 22:28:45 【问题描述】:

以下代码在 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)

我知道有一个question 针对类似的问题,但退回到 java 7 对我来说不是解决方案。

我尝试添加以下maven依赖

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

但这并没有改变结果,所以我删除了它(感谢@BlaiseDoughan 提供的信息,它包含在 Java 6 中)

欢迎任何提示,非常感谢。

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,并通过将 JVM 争论设置为 -Djavax.xml.accessExternalDTD=all -Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl

【讨论】:

【参考方案2】:

我在尝试解决声纳漏洞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>

【讨论】:

【参考方案3】:

我遇到过类似的问题,当 xerces jar 和 xercesImpl jar 的版本存在很大差异时会出现此问题。为了解决这个问题,我使用了 xerces-2.9.0 和 xercesImpl-2.9.1,问题就消失了。

【讨论】:

【参考方案4】:

我在我的项目中使用第二个 Mitch 解决方案解决了这个问题,但只是使用了

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

【讨论】:

它解决了我的问题,我们使用jdk6编译和运行tomcat6 & jdk8。不需要任何与代码相关的更改,真是太好了。【参考方案5】:

我们也遇到了这个问题,注意到需要保持jdk版本和jre版本一致,否则会存在版本不匹配导致的问题。

遇到问题的人用的是jdk1.6和jre 1.8,改成jdk1.6后问题就解决了。

【讨论】:

【参考方案6】:

另一种可能的解决方案是添加系统变量:

我在对我有用的 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");

【讨论】:

这对我有用。你能解释一下它到底是做什么的吗? 如果你不能重建 java.lang.在 jruby 中使用 java.lang.System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser"); 等。 系统属性“jdk.xml.entityExpansionLimit”被我忽略了,直到我在底部设置了这三个属性。谢谢,你救了我的包子......但是为什么我必须设置解析器属性才能让“jdk.xml.entityExpansionLimit”等其他属性生效?【参考方案7】:

Xerces impl 是这里的罪魁祸首。去掉它。 jdk内置了jaxb解析器,你不需要这个。

所以,如果该依赖项来自父项目(在 maven 的情况下) 使用排除选项卡以防您无法直接删除它。

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

这个问题很难被发现的原因是,当你通常编写一个 jaxb 解组代码时

您将对 try 块进行解组,然后捕获 jaxb 异常,然后对错误执行任何操作。

但是这个 jar (xercesimpl) 的罪魁祸首解析器在中间抛出了一个运行时异常,导致错误不会 被记录下来,只有在仔细调试后才会被检测到。看下面的代码sn-p

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 导致解组器使用其他一些 sax 解析器(而不是常规的 jaxb 解析器) 导致它抛出不同的异常 不会被我们的 catch 块捕获,该块期待 jaxbexception 或其子类之一。

【讨论】:

对于未来的访问者:mvn dependency:tree -Dverbose -Dincludes=xerces。现在阅读树以找出正在加载它的依赖项。 在我们的例子中,排除 xercesImpl 像上面的依赖 jaxen:jaxen 修复了构建。 对我来说它来自junit-addons:junit-addons【参考方案8】:

尝试创建一个 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 );

【讨论】:

如下所述,它是/是一个依赖问题,在我的情况下是 jcs。如此普通的代码总是运行良好。【参考方案9】:

Bernard 和 Blaise 的回答都非常有帮助。就我而言,由于我使用的是 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>

【讨论】:

【参考方案10】:

我们遇到了类似的问题 - 我们的首席开发人员找到了适合我们的解决方案。

我们将此依赖项添加到几个 pom.xml 文件中

对于那些关心的人来说,Sonar 中失败的单元测试显然失败了,因为 Cobatura 默认情况下会引入旧版本的 xerces。它引入的版本与 Java 8 中的 JAX-B 不兼容。该库不用于生产代码——只是 Cobatura。因此,修复是在更新版本的 xerces (2.11.0) 上添加测试依赖项。这是通过将依赖项添加到 pom 文件来完成的:

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

【讨论】:

C:\Java64\jdk1.8.0_60\jre\lib\rt.jar 中的 javax.xml.bind.JAXBContext 无法正常工作。解决方案是在 CLASSPATH 中使用早期版本的 xerces。在 pom.xml 中,将上述 xerces 2.11.0 依赖项插入到所有其他 之上,因此它具有更高的优先级以被 Java 8 获取。 对于 Jdk v1.8.0_181 和 Jaxb v2.2.11 和 xercesIml v2.11.0,此解决方案不起作用 这对我不起作用。我也测试了 2.12.0 版,但不起作用!我的 java 版本是 1.8.0_202【参考方案11】:

这是一个依赖问题。

这是我解决问题的方法:

    创建一个新的 maven 项目,使用我在下面附加的那些简单代码,程序正常崩溃并出现错误,无法解析结构,这没关系。

    将你的依赖项复制到项目 pom.xml 中,现在程序应该崩溃(如上所述)

    不,你在你喜欢的方法(好猜测,Bisection,1-by-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>

希望对您有所帮助。

【讨论】:

这是您描述的一个有用的过程。但是获取有关在您的情况下导致此错误的依赖项的信息也很有用! @Lii 在我的例子中,它是 java 缓存系统 jcsjcs1.3 > “也许有人有更好(更专业)的方法” 那就是使用 Maven 依赖插件并简单地寻找 Xerces。 org.apache.maven.plugins:maven-dependency-plugin:2.10:tree【参考方案12】:

使用 SAXparser 可能是一场噩梦。这是 java 中使用最广泛的 XML 解析器,每个人最终都直接或间接使用。 JDK 8 已经提供了 JAXB。因此,如果您使用的是 JDK 8,那么唯一可能的方法应该是删除 maven 依赖项。 我也遇到了这个问题,所以我尝试删除 maven 依赖项,但没有发生。然后我想如果 java 和 VOILLA 我成功了,为什么不恢复到旧版本。我目前正在使用 jdk 7,并且我的测试运行顺利。我想这是唯一的解决方案。

【讨论】:

降级是/不是一种选择。但我发现了导致问题的依赖性。 如果不深入调查原因,我认为建议使用旧版本的 java 是不好的。【参考方案13】:

Java SE 自版本 6 起就包含了 JAXB 的实现。如果您删除 Maven 依赖项(这可能会导致版本冲突),一切都应该正常工作。

【讨论】:

Mhhh ...谢谢,因为我很绝望,我添加了依赖项来解决问题,但没有任何改变。我删除了它,但结果仍然相同。我编辑了我的问题。 @mmx73 - 在没有 Maven 的情况下运行示例时,您是否看到同样的问题? 你认为这是一个依赖问题吗?也许我可以设置一个简单的项目,只运行一个小型 XML 解析器程序。我会在周末试试这个然后回来。 @mmx73 - 是的,我认为这是一个依赖问题。 @blaise_doughan :你是对的,这是一个依赖问题。我将用我发现的解决方案自己回答我的问题。感谢您的帮助。

以上是关于在 java-8“安全处理 org.xml.sax.SAXNotRecognizedException 导致 java.lang.IllegalStateException”中解组 xml 时出错的主要内容,如果未能解决你的问题,请参考以下文章

java 在java 8中排序比较器

在 java-8 中处理或避免 NPE 的最佳方法是啥?

《Java 8 in Action》Chapter 1:为什么要关心Java 8

在Windows中安装和切换java 7和java 8

Java 8 https 连接在某些站点上失败

将 java 从版本 8 降级到 7