当前位置: 首页 > 面试题库 >

如何防止具有META-INF \ services \ javax.xml.transform.TransformerFactory的xalan.jar接管Xalan实现中内置的JDK 1.6?

百里京
2023-03-14
问题内容

考虑以下代码(完全基于飞碟的“入门”代码,保留其权利):

package flyingsaucerpdf;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

import org.xhtmlrenderer.pdf.ITextRenderer;


    public class PDFMaker {
        public static void main(String[] args) throws Exception {
            new PDFMaker().go();
        }

        public void go() throws Exception {
            String inputFile = "sample.html";
            String url = new File(inputFile).toURI().toURL().toString();
            String outputFile = "firstdoc.pdf";
            OutputStream os = new FileOutputStream(outputFile);

            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocument(url);
            renderer.layout();
            renderer.createPDF(os);

            os.close();
        }
    }

几个事实:

  1. 使用JDK 1.6或1.5独立运行(调用main)可以完美运行(生成PDF)
  2. 但是,当通过URLClassLoader从现有的Web应用程序加载时,它将失败并显示以下错误:

    由以下原因引起:org.w3c.dom.DOMException:NAMESPACE_ERR:试图以对名称空间不正确的方式创建或更改对象。
    在org.apache.xerces.dom.AttrNSImpl.setName(未知来源)
    在org.apache.xerces.dom.AttrNSImpl。(来源不明)
    在org.apache.xerces.dom.CoreDocumentImpl.createAttributeNS(未知来源)
    在org.apache.xerces.dom.ElementImpl.setAttributeNS(未知来源)
    在org.apache.xml.utils.DOMBuilder.startElement(DOMBuilder.java:307)
    …另外19个

在错误的位置寻找了一段时间后(例如,我怀疑是xalan / xerces
jars,创建了一个孩子优先/父母最后的类加载器,但仍然失败了),我终于缩小了根本原因:

似乎加载我的代码的Web应用程序具有旧的 xalan.jar ,规范版本1.2

我做了一些测试,以独立的方式运行了上面的代码(之前运行良好),但是这次我将Web应用程序中的 xalan.jar
添加到了它的类路径和bingo中,这与Web应用程序场景中的错误相同

因此,我检查了那个旧的xalan.jar并想知道,什么会导致JVM加载它的旧的xalan实现而不是JDK的实现?毕竟,我的子优先级类加载器也是最后一个父级加载器,例如中间的系统,要说:在父级之前搜索系统类加载器(以避免加载父级覆盖的JDK
jar,就像这种情况下,父级的xalan.jar覆盖了JDK的xalan实现)

然后,有些事情引起了我的注意-文件 xalan.jar / META-INF / services /中 名为
javax.xml.transform.TransformerFactory的 内容如下:

org.apache.xalan.processor.TransformerFactoryImpl

因此,我立即在eclipse中按下Ctrl+ T并寻找完整的限定名称…仅在 xalan.jar中

然后,我仅搜索“ TransformerFactoryImpl”,这就是JDK的功能:

com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl

容易看出差异

因此,如果您读到这里,我的底线问题是: 如何使我的TransformerFactory使用JDK的实现而不是旧的Xalan的实现?
(我无法从加载我的代码的网络应用中删除该jar)


问题答案:

答案似乎比我想的要简单。

  1. 在您的类加载器中,将此文件夹添加到类路径(不需要jar): /META-INF/services/

  2. 在其中创建一个名为 javax.xml.transform.TransformerFactory

  3. 编辑它,并将其设置为以下内容: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl

而已!

为什么行得通?请参阅Java用来加载Xalan实现的此类。

请注意,对于该特定的“ META-
INF”条目,它似乎事实上是父后(或子优先)加载器(与常规Java类加载器的工作方式相反,例如,父先/子后)。如果我错了纠正我

摘录自 javax.xml.datatype.FactoryFinder

   /*
     * Try to find provider using Jar Service Provider Mechanism
     *
     * @return instance of provider class if found or null
     */
    private static Object findJarServiceProvider(String factoryId)
        throws ConfigurationError
    {

        String serviceId = "META-INF/services/" + factoryId;
        InputStream is = null;

        // First try the Context ClassLoader
        ClassLoader cl = ss.getContextClassLoader();
        if (cl != null) {
            is = ss.getResourceAsStream(cl, serviceId);

            // If no provider found then try the current ClassLoader
            if (is == null) {
                cl = FactoryFinder.class.getClassLoader();
                is = ss.getResourceAsStream(cl, serviceId);
            }
        } else {
            // No Context ClassLoader, try the current
            // ClassLoader
            cl = FactoryFinder.class.getClassLoader();
            is = ss.getResourceAsStream(cl, serviceId);
        }

        if (is == null) {
            // No provider found
            return null;
        }

        ...


 类似资料:
  • 因此,在我的主程序中,我运行以下内容。 它总是返回false,这意味着它没有找到'dummydevice' 在我的eclipse项目中,我在'src'处创建了一个名为META-INF的文件夹,在它下面创建了一个名为'services'的子文件夹。 我做对了吗?我看到的每一个关于SPI的例子都是关于加载JAR的。我不是在加载一个JAR,我是想在同一个项目中运行一个类。这个方法只适用于装入罐子吗?我希

  • 我的CharsetProvider的类是在文件中指定的,该文件位于中,所有GET都正常加载并按预期工作。 然而,现在我也在android上使用lib,但是charset没有加载到android-app中。 我如何整合我的字符集,使它可以像预期的那样在一个Android应用程序中使用? 目前我正在做这样的变通: 这是可行的,但在我看来是无效的,因为每次我尝试用自己的charset进行这样的解码时,都

  • 有没有一种方法可以用Maven在Meta-INF/services中创建自定义服务文件?这就是您使用Ant的方法:https://ant.apache.org/manual/tasks/jar.html 我知道在我的源代码中创建一个resources/meta-inf/并放置我想要的任何服务文件是可能的。然后,Maven会自动将这些文件拉到我的JAR中。这不能解决我的问题。 在我的源代码中有多个版

  • 我正在Eclipse中处理一个Java项目,该项目是使用Maven构建的。我使用的是一个旧项目中的一些循环代码,其中一个类在JAR的文件夹中查找一个具有特定名称的文件,然后解析该文件的文本。在这个特定的示例中,它查找一个具有Java接口名称的文件,然后从文件内部获取实现的类名。

  • 问题内容: 我正在使用Eclipse构建Java项目,该项目是使用Maven构建的。我使用的是旧项目中的一些再生代码,这些类之一在JAR文件夹中查找具有特定名称的文件,然后解析该文件的文本。在此特定示例中,它将查找具有Java接口名称的文件,然后从文件内部获取实现的类名称。 因此,基本上我想做的是 在JAR的“ META-INF / services”文件夹中包含一个文件名(X)和一行文本(Y)的

  • 我正在Eclipse中处理一个Java项目,该项目是使用Maven构建的。我使用的是一个旧项目中回收的代码,其中一个类在JAR的文件夹中查找具有特定名称的文件,然后解析该文件的文本。在这个特定的例子中,它查找一个名为Java接口的文件,然后从文件中获取实现的类名。 所以基本上,我要做的是在JAR的“META-INF/services”文件夹中包含一个文件,文件名为(X),一行文本为(Y)。我猜这应