我在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)
查找过程的第3点newInstance
javax.xml.xpath.XPathFactory
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
方法的javadoc用于本地化实现:
要求类加载器提供与资源目录META-INF / services中的javax.xml.xpath.XPathFactory匹配的服务提供者提供者配置文件。有关文件格式和解析规则,请参阅JAR文件规范。
JAR文件规范的Service Provider section声明:
该文件应包含以换行符分隔的唯一具体提供者类名称列表。
但是,如果我提取saxon9he.jar文件并查看META-INF目录,我看到:
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
第一行是正确的,但我不明白为什么有两条额外的行,看起来这些行给ServiceLoader造成了麻烦。我看到了一个测试示例的问题,我写了解了用于查找提供程序的机制。我们可以看到saxon9he.jar在CLASSPATH中。
jar:file:/Users/ludo/Library/Java/saxon9he.jar!/META-INF/services/javax.xml.xpath.XPathFactory:2: Illegal configuration-file syntax
感兴趣的是:
XPathFactory xpf = XPathFactory.newInstance(
XPathFactory.DEFAULT_OBJECT_MODEL_URI,
"net.sf.saxon.xpath.XPathFactoryImpl",
ClassLoader.getSystemClassLoader());
它是Saxon的错误还是我的系统不支持的扩展语法?我该怎么做才能解决这个问题?
请注意,如果我明确选择了实现的类,我可以获得一个工厂。但我想使用服务机制。以下代码有效:
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);
}
}
我在下面添加了整个Java测试程序。
{{1}}
答案 0 :(得分:12)
Michael Kay answered the question在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());
答案 1 :(得分:1)
我知道这是一个较旧的主题,但是this post of mine可能会对这个问题有所了解。它使用我从未见过的-D参数找到XPathFactory。