Saxon-HE 9.3 的 javax.xml.xpath.XPathFactory 提供程序配置文件中的语法错误

发布于 2024-12-12 07:56:47 字数 3964 浏览 0 评论 0原文

我在 Mac OS X 和 Saxon-HE 9.3.0.5 上使用 Java SE 6。 ServiceLoader 无法找到 javax.xml.xpath.XPathFactory 的 Saxon 实现。

mac:test2 ludo$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode)

javax.xml.xpath.XPathFactorynewInstance 方法的 javadoc 在查找过程的第 3 点中声明了本地化实现:

类加载器被要求提供与资源目录 META-INF/services 中的 javax.xml.xpath.XPathFactory 匹配的服务提供者提供者配置文件。有关文件格式和解析规则,请参阅 JAR 文件规范。

服务提供商部分 JAR 文件规范指出:

该文件应包含一个以换行符分隔的唯一具体提供程序类名称列表。

但是,如果我提取 saxon9he.jar 文件并查看 META-INF 目录,我会看到:

mac:Java ludo$ mkdir test
mac:Java ludo$ cd test
mac:test ludo$ jar fx ../saxon9he.jar 
mac:test ludo$ cat META-INF/services/javax.xml.xpath.XPathFactory 
net.sf.saxon.xpath.XPathFactoryImpl
http\://java.sun.com/jaxp/xpath/dom:    net.sf.saxon.xpath.XPathFactoryImpl
http\://saxon.sf.net/jaxp/xpath/om:     net.sf.saxon.xpath.XPathFactoryImpl

第一行是正确的,但我不明白为什么有两行,而且看起来这些行给 ServiceLoader 带来了麻烦。我在我编写的测试示例中看到了这个问题,以了解用于查找提供者的机制。我们可以看到 saxon9he.jar 在 CLASSPATH 中。

mac:services ludo$ java ServicesTest
CLASSPATH = ..., /Users/ludo/Library/Java/saxon9he.jar, ...
Service XPathFactory: java.util.ServiceLoader[javax.xml.xpath.XPathFactory]
ServiceConfigurationError: javax.xml.xpath.XPathFactory: jar:file:/Users/ludo/Library/Java/saxon9he.jar!/META-INF/services/javax.xml.xpath.XPathFactory:2: Illegal configuration-file syntax

感兴趣的是:

jar:file:/Users/ludo/Library/Java/saxon9he.jar!/META-INF/services/javax.xml.xpath.XPathFactory:2: Illegal configuration-file syntax

它是 Saxon 的错误还是我的系统不支持的扩展语法?我可以做什么来解决这个问题?

请注意,如果我明确选择实现的类,我可以获得一个工厂。但我想使用Services机制。以下代码有效:

XPathFactory xpf = XPathFactory.newInstance(
  XPathFactory.DEFAULT_OBJECT_MODEL_URI,
  "net.sf.saxon.xpath.XPathFactoryImpl",
  ClassLoader.getSystemClassLoader());

我在下面添加了整个 Java 测试程序。

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import javax.xml.xpath.XPathFactory;

public class ServicesTest {
    public static String getClasspathString() {
        StringBuilder classpath = new StringBuilder();
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        URL[] urls = ((URLClassLoader) classLoader).getURLs();
        for (int i = 0; i < urls.length - 1; i++) {
            classpath.append(urls[i].getFile()).append(", ");
        }
        if (urls.length > 0) {
            classpath.append(urls[urls.length - 1].getFile());
        }

        return classpath.toString();
    }

    public static void availableProviders(ServiceLoader sl) {
        Iterator it = sl.iterator();
        int index = 0;
        for (;;) {
            try {
                if (!it.hasNext()) {
                    break;
                }
                index++;
                Object o = it.next();
                System.out.printf("%03d Concrete class name: %s\n", index, o.getClass().getName());
            } catch (ServiceConfigurationError e) {
                System.err.printf("ServiceConfigurationError: %s\n", e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        System.out.printf("CLASSPATH = %s\n", getClasspathString());
        System.out.println();

        ServiceLoader<XPathFactory> slXPathFactory = ServiceLoader.load(XPathFactory.class);
        System.out.printf("Service XPathFactory: %s\n", slXPathFactory.toString());
        availableProviders(slXPathFactory);
    }
}

I am using Java SE 6 on Mac OS X and Saxon-HE 9.3.0.5. The ServiceLoader is not able to find the Saxon implementation of javax.xml.xpath.XPathFactory.

mac:test2 ludo$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode)

The javadoc of the newInstance method of javax.xml.xpath.XPathFactory states in point 3 of the lookup procedure to localize an implementation that:

The class loader is asked for service provider provider-configuration files matching javax.xml.xpath.XPathFactory in the resource directory META-INF/services. See the JAR File Specification for file format and parsing rules.

The Service Provider section of the JAR File Specification states that:

The file should contain a newline-separated list of unique concrete provider-class names.

But if I extract the saxon9he.jar file and look into the META-INF directory, I see:

mac:Java ludo$ mkdir test
mac:Java ludo$ cd test
mac:test ludo$ jar fx ../saxon9he.jar 
mac:test ludo$ cat META-INF/services/javax.xml.xpath.XPathFactory 
net.sf.saxon.xpath.XPathFactoryImpl
http\://java.sun.com/jaxp/xpath/dom:    net.sf.saxon.xpath.XPathFactoryImpl
http\://saxon.sf.net/jaxp/xpath/om:     net.sf.saxon.xpath.XPathFactoryImpl

The first line is correct but I can't see why there are two extra lines and it looks like those lines are causing trouble to ServiceLoader. I saw the problem with a test example that I wrote the understand the mecanism used to find a provider. We can see that saxon9he.jar is in the CLASSPATH.

mac:services ludo$ java ServicesTest
CLASSPATH = ..., /Users/ludo/Library/Java/saxon9he.jar, ...
Service XPathFactory: java.util.ServiceLoader[javax.xml.xpath.XPathFactory]
ServiceConfigurationError: javax.xml.xpath.XPathFactory: jar:file:/Users/ludo/Library/Java/saxon9he.jar!/META-INF/services/javax.xml.xpath.XPathFactory:2: Illegal configuration-file syntax

The line of interest is:

jar:file:/Users/ludo/Library/Java/saxon9he.jar!/META-INF/services/javax.xml.xpath.XPathFactory:2: Illegal configuration-file syntax

Is it a bug of Saxon or an extended syntax not supported by my system ? What could i do to solve the issue ?

Note that if I explicitly choose the class for the implementation, I can get a factory. But I want to use the Services mechanism. The following code works:

XPathFactory xpf = XPathFactory.newInstance(
  XPathFactory.DEFAULT_OBJECT_MODEL_URI,
  "net.sf.saxon.xpath.XPathFactoryImpl",
  ClassLoader.getSystemClassLoader());

I have added the whole Java test program below.

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import javax.xml.xpath.XPathFactory;

public class ServicesTest {
    public static String getClasspathString() {
        StringBuilder classpath = new StringBuilder();
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        URL[] urls = ((URLClassLoader) classLoader).getURLs();
        for (int i = 0; i < urls.length - 1; i++) {
            classpath.append(urls[i].getFile()).append(", ");
        }
        if (urls.length > 0) {
            classpath.append(urls[urls.length - 1].getFile());
        }

        return classpath.toString();
    }

    public static void availableProviders(ServiceLoader sl) {
        Iterator it = sl.iterator();
        int index = 0;
        for (;;) {
            try {
                if (!it.hasNext()) {
                    break;
                }
                index++;
                Object o = it.next();
                System.out.printf("%03d Concrete class name: %s\n", index, o.getClass().getName());
            } catch (ServiceConfigurationError e) {
                System.err.printf("ServiceConfigurationError: %s\n", e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        System.out.printf("CLASSPATH = %s\n", getClasspathString());
        System.out.println();

        ServiceLoader<XPathFactory> slXPathFactory = ServiceLoader.load(XPathFactory.class);
        System.out.printf("Service XPathFactory: %s\n", slXPathFactory.toString());
        availableProviders(slXPathFactory);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

つ低調成傷 2024-12-19 07:56:47

Michael Kay 在 SourceForge 论坛上回答了该问题。他说:

选择文件格式是为了规避 JDK5 错误。

还有:

实际上,无论如何我都不建议使用 JAXP 搜索机制。它非常慢,并且它提供的 XPath 引擎不一定适用于您的应用程序。您无法知道返回的是 XPath 1.0 还是 2.0 实现,而且 API 的定义非常薄弱,除非您首先使用该提供程序对其进行了测试,否则您的应用程序几乎不可能与特定提供程序一起工作。因此,即使没有这个错误,我也会避开它。

我认为它回答了问题,即使它没有为问题提供明确的解决方案。所以我们可以通过编写来选择实现:

XPathFactory xpf = XPathFactory.newInstance(
  XPathFactory.DEFAULT_OBJECT_MODEL_URI,
  "net.sf.saxon.xpath.XPathFactoryImpl",
  ClassLoader.getSystemClassLoader());

Michael Kay answered the question on a SourceForge forum. He said that:

The format of the file was chosen to circumvent a JDK5 bug.

And also that:

Actually, I wouldn't recommend using the JAXP search mechanism anyway. It's very slow, and it delivers an XPath engine that won't necessarily work with your application. You have no way of knowing whether you get an XPath 1.0 or 2.0 implementation back, and the API is so weakly defined that there's very little chance your application will work with a particular provider unless you have tested it with that provider first. So even without this bug, I would steer clear of it.

I think it answers the question even if it does not provide an explicit fix for the problem. So we could chose the implementation by writing:

XPathFactory xpf = XPathFactory.newInstance(
  XPathFactory.DEFAULT_OBJECT_MODEL_URI,
  "net.sf.saxon.xpath.XPathFactoryImpl",
  ClassLoader.getSystemClassLoader());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文