Jens
Jens

Reputation: 53

Load external Java method from inside of a XSL stylesheet with JDK internal Xalan and SecurityManager

In our project we currently moved to Java 8 and want to use now the internal XML libraries instead of additional ones. For that we removed e.g. our xalan.jar from our classpath.

This leads to ClassNotFoundExceptions when trying to render our XML files. Within the XSL stylesheets we ue to transform the XML files, we also call external Java methods as in the following example:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fo="http://www.w3.org/1999/XSL/Format"
   xmlns:java="http://xml.apache.org/xalan/java">

...

<xsl:template name="example">
  <fo:block>
    <xsl:value-of select="java:my.package.name.JavaClass.testMethod('test')"/>
  </fo:block>
</xsl:template>
...

However, always when the external method testMethod() should be called, the process stops with a ClassNotFoundException. I debugged the code in the com.sun.org.apache.xalan.internal.xsltc.compiler.FunctionCall class and found that XSLTC tries to instantiate the my.package.name.JavaClass in order to call the testMethod(). Which is okay. But...

The class is tried to be instantiated/loaded within the following code of com.sun.org.apache.xalan.internal.utils.ObjectFactory:

/**
     * Find a Class using the same class loader for the ObjectFactory by default
     * or boot class loader when Security Manager is in place
     */
    public static Class<?> findProviderClass(String className, boolean doFallback)
        throws ClassNotFoundException, ConfigurationError
    {
        return findProviderClass (className,
                findClassLoader (), doFallback);
    }

which further calls findClassLoader() to get the correct class loader to load my JavaClass:

/**
     * Figure out which ClassLoader to use.  For JDK 1.2 and later use
     * the context ClassLoader.
     */
    public static ClassLoader findClassLoader()
    {
        if (System.getSecurityManager()!=null) {
            //this will ensure bootclassloader is used
            return null;
        }

        // Figure out which ClassLoader to use for loading the provider
        // class.  If there is a Context ClassLoader then use it.
        ClassLoader context = SecuritySupport.getContextClassLoader();
        ClassLoader system = SecuritySupport.getSystemClassLoader();

        ClassLoader chain = system;
        while (true) {
            if (context == chain) {
...loop to get correct class loader
        }

Now in our project we have the 'problem' that we have a SecurityManager implementation in place which means this implementation above just returns null instead of the context classloader.

BTW: I would also expect to get the context classloader here, but with additional checks later if the SecurityManager allows to load a class, why des it just return null here?

This again means that my class is tried to be loaded with the boot classloader which does not know my class and therefore throws the exception. Removing the SecurityManager returns the context classloader which is able to load my class and the XML can be successfully transformed.

So - if you are still here and asleep - is there a way to be able to still use my external Java methods in the XSL stylesheets? Is there a way to load my class in this situation? I thought about the following maybe possible solutions, but they all do not really satisfy me:

However, the last way is also not working as the class is also loaded with the AppClassLoader and probably also not available during the parsing process. But maybe there is a similar solution?

Thanks in advance.

Best Regards, Jens

Upvotes: 3

Views: 1215

Answers (1)

ptha
ptha

Reputation: 916

Does something like this work:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fo="http://www.w3.org/1999/XSL/Format"
   xmlns:myHelper="http://xml.apache.org/xalan/java/my.package.name.JavaClass">

...

<xsl:template name="example">
  <fo:block>
    <xsl:value-of select="myHelper:testMethod('test')"/>
  </fo:block>
</xsl:template>

How the namespace (in this case myHelper) is specified in the stylesheet declaration depends on what you are using to process the XSL, the example above is for Xalan.

Upvotes: 0

Related Questions