Saxon-HE 9.3 的 javax.xml.xpath.XPathFactory 提供程序配置文件中的语法错误
我在 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.XPathFactory
的 newInstance
方法的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Michael Kay 在 SourceForge 论坛上回答了该问题。他说:
还有:
我认为它回答了问题,即使它没有为问题提供明确的解决方案。所以我们可以通过编写来选择实现:
Michael Kay answered the question on a SourceForge forum. He said that:
And also that:
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: