如何防止具有META-INF\services\javax.xml.transform.TransformerFactory的xalan.jar接管Xalan实现中内置的JDK 1.6? [英] How to prevent xalan.jar that has META-INF\services\javax.xml.transform.TransformerFactory from taking over JDK 1.6 built in Xalan implementation?

查看:159
本文介绍了如何防止具有META-INF\services\javax.xml.transform.TransformerFactory的xalan.jar接管Xalan实现中内置的JDK 1.6?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Consider this code (based entirely on flying saucer's "getting started" code, their rights reserved):

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应用程序中失败,并出现以下错误:





Caused by: org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
    at org.apache.xerces.dom.AttrNSImpl.setName(Unknown Source)
    at org.apache.xerces.dom.AttrNSImpl.(Unknown Source)
    at org.apache.xerces.dom.CoreDocumentImpl.createAttributeNS(Unknown Source)
    at org.apache.xerces.dom.ElementImpl.setAttributeNS(Unknown Source)
    at org.apache.xml.utils.DOMBuilder.startElement(DOMBuilder.java:307)
    ... 19 more

在错误的位置找了一段时间之后(例如,我创造了一个孩子-first / parent-last类加载器怀疑xalan / xerces罐子,但仍然失败),我终于缩小了根本原因:

After looking for a while in the wrong place (for example, I created a child-first / parent-last class loader suspecting xalan / xerces jars, but it still fails), I finally narrowed down the root cause:

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

It seems that the web application that loads my code, has an old xalan.jar, specification version 1.2

我做了一些测试,我将上面的代码作为独立运行(之前运行良好),但是这次我将来自网络应用的 xalan.jar 添加到了它的类路径和宾果游戏中,这与网络应用场景中的错误相同io

I did a little test, I ran the code above as standalone (which worked fine before) but this time I added the xalan.jar from the web app to it's classpath, and bingo, the same error as in the web app scenario

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

So I inspected that old xalan.jar and wondered, what can cause the JVM to load it's old xalan implementation instead of the JDK's? after all my child-first class loader is also parent-last e.g. system in the middle, to say: searching the system classloader before the parent (to avoid loading parent overriden JDK jars, just like this case of the parent's xalan.jar overriding the JDK's xalan implementation)

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

Then something cought my eyes - a file in: xalan.jar/META-INF/services/ named javax.xml.transform.TransformerFactory with this content:

org.apache.xalan.processor.TransformerFactoryImpl

所以我立即在eclipse中按 Ctrl + T 并查找全限定名...仅在 xalan.jar

So I imediately pressed Ctrl+T in eclipse and looked for the full qualified name... only in xalan.jar!

然后我仅搜索 TransformerFactoryImpl,这就是JDK的内容:

Then I searched only for "TransformerFactoryImpl", and this is what the JDK has:

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

容易看到差异

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

So, if you read till here, my bottom line question is: How do I make my TransformerFactory use the JDK's implementation and not the old Xalan's one? (I can't remove that jar from the web app my code will be loaded from)

推荐答案

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

It seems the answer is simpler than I thought.


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

在其中创建一个名为 javax.xml.transform.TransformerFactory <的文件/ code>

In it, create a file named javax.xml.transform.TransformerFactory

对其进行编辑并将其设置为以下内容: com.sun.org.apache.xalan。 internal.xsltc.trax.TransformerFactoryImpl

Edit it and set this as it's content to: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl

就是这样! >

为什么起作用?请参阅Java用来加载Xalan实现的此类。

Why does it work? see this class used by Java for loading the Xalan implementation.

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

Notice that it seems de-facto a parent-last (or child-first) loader for that specific "META-INF" entry (the oposite of how regular Java class loaders work, e.g. parent-first / child-last) but feel free to correct me if I'm wrong

来自 javax.xml.datatype.FactoryFinder 的片段

Snippet from 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;
        }

        ...

这篇关于如何防止具有META-INF\services\javax.xml.transform.TransformerFactory的xalan.jar接管Xalan实现中内置的JDK 1.6?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆