36

我想提供有关正在使用的 JAXP 实现以及从哪个 JAR 文件加载它的诊断信息。

实现此目的的一种方法是在例如 a 的实例中创建,DocumentBuilderFactory然后检查该类的属性:

private static String GetJaxpImplementation() {
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    Class<? extends DocumentBuilderFactory> c = documentBuilderFactory.getClass();
    Package p = c.getPackage();
    CodeSource source = c.getProtectionDomain().getCodeSource();
    return MessageFormat.format(
            "Using JAXP implementation ''{0}'' ({1}) version {2} ({3}){4}",
            p.getName(),
            p.getImplementationVendor(),
            p.getSpecificationVersion(),
            p.getImplementationVersion(),
            source == null ? "." : " loaded from: " + source.getLocation());
}

有没有更好的方法来实现这一点,也许不必创建一个DocumentBuilderFactory

4

5 回答 5

62

在没有实际创建实例的情况下,很难预测将加载哪些具体的 JAXP 工厂实现,因为选择实现的过程。

来自官方 JAXP 常见问题解答(问题 14):

当应用程序想要创建一个新的 JAXPDocumentBuilderFactory 实例时,它会调用 staic 方法 DocumentBuilderFactory.newInstance()。这将导致 DocumentBuilderFactory使用以下顺序搜索具体子类的名称:

  1. 系统属性的值,例如javax.xml.parsers.DocumentBuilderFactory它是否存在且可访问。
  2. 文件的内容($JAVA_HOME/jre/lib/jaxp.properties如果存在)。
  3. Jar 文件规范中指定的 Jar 服务提供者发现机制。jar 文件可以有一个资源(即嵌入文件),例如META-INF/services/javax.xml.parsers.DocumentBuilderFactory包含要实例化的具体类的名称。
  4. 后备平台默认实现。

除了这种复杂性之外,每个单独的 JAXP 工厂都可以指定一个独立的实现。使用一个解析器实现和另一个 XSLT 实现是很常见的,但是上面选择机制的粒度允许您在更大程度上混合和匹配。

以下代码将输出有关四个主要 JAXP 工厂的信息:

private static void OutputJaxpImplementationInfo() {
    System.out.println(getJaxpImplementationInfo("DocumentBuilderFactory", DocumentBuilderFactory.newInstance().getClass()));
    System.out.println(getJaxpImplementationInfo("XPathFactory", XPathFactory.newInstance().getClass()));
    System.out.println(getJaxpImplementationInfo("TransformerFactory", TransformerFactory.newInstance().getClass()));
    System.out.println(getJaxpImplementationInfo("SAXParserFactory", SAXParserFactory.newInstance().getClass()));
}

private static String getJaxpImplementationInfo(String componentName, Class componentClass) {
    CodeSource source = componentClass.getProtectionDomain().getCodeSource();
    return MessageFormat.format(
            "{0} implementation: {1} loaded from: {2}",
            componentName,
            componentClass.getName(),
            source == null ? "Java Runtime" : source.getLocation());
}

以下示例输出说明了三种不同 JAXP 实现(内置 Xerces 和 Xerces 2.8 和 Xalan 的外部 JAR)的混合搭配:

DocumentBuilderFactory implementation: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xerces-2.8.0.jar
XPathFactory implementation: com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl loaded from: Java Runtime
TransformerFactory implementation: org.apache.xalan.processor.TransformerFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xalan.jar
SAXParserFactory implementation: org.apache.xerces.jaxp.SAXParserFactoryImpl loaded from: file:/C:/Projects/Scratch/lib/xerces-2.8.0.jar
于 2009-11-26T15:22:27.777 回答
13

只需添加

-Djaxp.debug=1

JAVA_OPTS,你会看到这样的信息。

更多详情:https ://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html

于 2014-12-15T02:56:46.820 回答
4

这很简单,你只需设置

System.setProperty("jaxp.debug", "1");

曲目会告诉你 whick impl 和 jaxp 的使用方式。

于 2012-12-11T03:10:06.097 回答
2

在“回退平台默认实现”之前搜索了另一个位置,即Java 认可的标准覆盖机制java.endorsed.dirs中记录的目录

认可的标准覆盖机制提供了一种方法,可以将实现认可标准或独立技术的类和接口的更高版本合并到 Java 平台中。

于 2012-04-20T01:59:58.580 回答
1

这取决于,但通常不会。

DocumentBuilderFactory.newInstance()DocumentBuilderFactory如果未设置系统属性,则将返回在系统属性“javax.xml.parsers.DocumentBuilderFactory”中配置的实现或 JRE 的默认工厂。默认工厂很可能在 newInstance 方法的实现中被硬编码,并且无法以其他方式访问。

如果设置了系统属性,你至少可以使用相关类加载器上的getResource方法来获取URL,类加载器将从该URL加载相应的类文件。如果它来自 jar 文件,您应该能够从 jar: URL 中提取文件名(或源 URL)。如果您从类路径手动读取元数据文件,还应该提供详细的包信息。

如果未设置系统属性,我很确定如果没有像您已经在做的那样实际创建新工厂,您将无法获得您正在寻找的信息。

于 2009-11-25T18:12:40.487 回答