我有以下代码:
final TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
第二行在现代JDK(我试过1.8)中使用默认TransformerFactory
。但是当我将xalan
(版本2.7.2,最新的版本)添加到类路径时,我在第二行上得到以下内容:
Exception in thread "main" java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD
at org.apache.xalan.processor.TransformerFactoryImpl.setAttribute(TransformerFactoryImpl.java:571)
at Main.main(Main.java:11)
我想这是因为xalan的TransformerFactory
不支持此属性。 Xalan的实现通过ServiceLoader
机制获得:它在xalan jar中的services/javax.xml.transform.TransfomerFactory
中指定。
可以使用TransformerFactory
系统属性或javax.xml.transform.TransformerFactory
文件覆盖$JRE/lib/jaxp.properties
实现,或直接在代码中传递类名。但要做到这一点,我必须提供一个具体的类名。现在,它是com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
,但在系统属性中对它进行硬编码有点可怕,因为在JDK升级时,它们可以轻松更改类名,我们只会遇到运行时错误。
有没有办法指示TransformerFactory.newInstance()
忽略xalan提供的实现?或者告诉它“只使用系统默认值”。
P.S。我不能只从类路径中删除xalan
,因为我们使用的一堆其他库依赖于它。
答案 0 :(得分:1)
我在这里唯一可以实现的是硬编码JDK默认工厂并使用正常的发现过程作为后备:
TransformerFactory factory;
try {
factory = TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", SecureXmlFactories.class.getClassLoader());
} catch (Exception | TransformerFactoryConfigurationError e) {
LOGGER.error("Cannot load default TransformerFactory, let's try the usual way", e);
factory = TransformerFactory.newInstance();
}
然后在try/catch
// this works everywhere, but it does not disable accessing
// external DTDs... still enabling it just in case
try {
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
} catch (TransformerConfigurationException e) {
LOGGER.error("Cannot enable secure processing", e);
}
// this does not work in Xalan 2.7.2
try {
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
} catch (Exception e) {
LOGGER.error("Cannot disable external DTD access", e);
}
// this does not work in Xalan 2.7.2
try {
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
} catch (Exception e) {
LOGGER.error("Cannot disable external stylesheet access", e);
}
监视日志以查看默认JDK工厂类名称是否/何时更改。
答案 1 :(得分:0)
定义要加载哪个TransformerFactory实现的另一种方法是设置javax.xml.transform.TransformerFactory
系统属性(docs)。
在Ant中,您将在目标内执行以下操作:
<jvmarg value="-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"/>
在上面的示例中,我将OpenJDK8中的一个设置为默认值