Search code examples
javaclassloaderlibreofficejava-platform-module-system

How to load Libreoffice jars dynamically in modulairzed java 11 application without getting a ClassCastException from custom class loader


I am trying to load and access the libreoffice uno jars from a modular java 11 application at run time.

To use the libreoffice classes at compile time and to avoid a problem with split packages, we merged all jars together into a single one with an automatic module name org.jabref.thirdparty.libreoffice.

To load the jars from the libreoffice installation directory (e.g. C:\Program Files\LibreOffice\program\classes To ensure that the jars are loaded from the program files and not from my module path I created a custom Classloader.

   URL[] urls = jarUrls.toArray(new URL[3]);
    Class<Bootstrap> clazz  = (Class<Bootstrap>) Class.forName("com.sun.star.comp.helper.Bootstrap", true, new ChildFirstClassLoader(urls, this.getClass().getClassLoader()));
    Boostrap boot = clazz.getDeclaredConstructor().newInstance();
    XComponentContext xContext = boot.bootstrap():

Now this gives me the following error:

 java.lang.ClassCastException: class com.sun.star.comp.helper.Bootstrap cannot be cast to class com.sun.star.comp.helper.Bootstrap (com.sun.star.comp.helper.Bootstrap is in unnamed module of loader org.jabref.logic.openoffice.ChildFirstClassLoader @13c4b54c; com.sun.star.comp.helper.Bootstrap is in module org.jabref.thirdparty.libreoffice of loader 'app')

I do understand the problem here and read a lot of things about this, but could not find a solution to this problem. The key problem is that I must use the jars from the LO folder, because otherwise it won't find the libreoffice instance. I thought about putting the modularized jar into the LO folder as well, but not sure if that would work.

Under Java 8 we used the typical "reflection + addUrls" approach cause all was on the classpath.

This is the custom class laoder:

public class ChildFirstClassLoader extends URLClassLoader {

    public ChildFirstClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // has the class loaded already?
        Class<?> loadedClass = findLoadedClass(name);
        if (loadedClass == null) {
            try {
                // find the class from given jar urls 
                loadedClass = findClass(name);
            } catch (ClassNotFoundException e) {
                // Hmmm... class does not exist in the given urls.
                // Let's try finding it in our parent classloader.
                // this'll throw ClassNotFoundException in failure.                  
                loadedClass = super.loadClass(name, resolve);
            }
        }
        if (resolve) { // marked to resolve
            resolveClass(loadedClass);
        }
        return loadedClass;
    }
}

Solution

  • Starting with LibreOffice 7.0, there is now a combined libreoffice.jar which works with the Java module system.