为什么我的程序的行为仅基于 Maven 依赖性而改变?

Why does the behaviour of my program change just based on maven dependency?

所以这是我的代码:

package biz.tugay.deleteNow;
/* User: koray@tugay.biz Date: 19/12/15 Time: 12:57 */

import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList;
import org.xml.sax.InputSource;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class TestClass {
    public static void main(String[] args) throws XPathExpressionException, FileNotFoundException {
        XPath xpath = XPathFactory.newInstance().newXPath();
        String expression = "/library/catalog/book";
        InputSource inputSource = new InputSource();
        inputSource.setCharacterStream(new FileReader(new File("/Users/koraytugay/Desktop/widgets.xml")));
        Object evaluate = xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
        DTMNodeList dtmNodeList = (DTMNodeList) evaluate;
        System.out.println(dtmNodeList.getLength());
    }
}

这是我的 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>biz.tugay</groupId>
    <artifactId>deleteNow</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>deleteNow</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>


    <build>
        <finalName>deleteNow</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

让我们试一试:

Korays-MacBook-Pro:deleteNow koraytugay$ mvn clean install
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Korays-MacBook-Pro:deleteNow koraytugay$ cd target
Korays-MacBook-Pro:target koraytugay$ java -cp deleteNow-jar-with-dependencies.jar biz.tugay.deleteNow.TestClass
12

好的,一切似乎都很好,现在我将在我的 pom.xml 中添加一个依赖项并重复整个过程..

<dependencies>
    <dependency>
        <groupId>xalan</groupId>
        <artifactId>xalan</artifactId>
        <version>2.7.2</version>
    </dependency>
</dependencies>

构建成功,尝试执行:

Korays-MacBook-Pro:target koraytugay$ java -cp deleteNow-jar-with-dependencies.jar biz.tugay.deleteNow.TestClass
Exception in thread "main" java.lang.ClassCastException: org.apache.xml.dtm.ref.DTMNodeList cannot be cast to com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList
    at biz.tugay.deleteNow.TestClass.main(TestClass.java:22)

为什么会这样?依赖项如何破坏工作软件?

因为您对接口特定实现的依赖性

 import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList;

此行导致错误。通过导入 Xalan,您可以激活一个不同的 XPath 提供程序,它会依次创建 org.apache.xml.dtm.ref.DTMNodeList 而不是 com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList

如果您将代码更改为使用 org.w3c.dom.NodeList,则两种 XPath 实现都可以 :

    Object evaluate = xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
    NodeList dtmNodeList = (NodeList) evaluate;
    System.out.println(dtmNodeList.getLength());