0

I'm trying to use Javassist to load an abstract method class that is dynamically loaded from a JAR file at runtime. For some reason, this code only runs on the Windows operating system. I get a ClassDefNotFoundException on any other platform. This is the code I used.

public static void example() throws Exception {
    String pathToJar = "pathToJar.jar";
    File JARFile = new File(pathToJar);
    ClassLoader classLoader = URLClassLoader.newInstance(new URL[]{ JARFile.toURI().toURL() });
    Class<?> callBackClass = classLoader.loadClass("package.Callback");

    ProxyFactory factory = new ProxyFactory();
    factory.setSuperclass(callBackClass);
    MethodHandler handler = new MethodHandler() {

        @Override
        public Object invoke(Object self, Method overridden, Method forwarder,
                Object[] args) throws Throwable {
            return forwarder.invoke(self, args);
        }
    };

    factory.setFilter(
            new MethodFilter() {
                @Override
                public boolean isHandled(Method method) {
                    return Modifier.isAbstract(method.getModifiers());
                }
            }
            );
    Object instance = factory.create(new Class<?>[0], new Object[0], handler); /*exception thrown here on non-windows OS*/
}

Is this a problem with the class loader? Or is it a problem with Javassist? It's supposed to be platform independent, but depending on the OS, it may or may not run.

user3435571
  • 11
  • 1
  • 2

2 Answers2

1

exception thrown here on non-windows OS

That's a big clue, suggesting that there's a capitalization difference somewhere. The major file systems used with Windows are case-insensitive, whereas the major file systems used elsewhere (*nix) are case-sensitive. So look very carefully at the capitalization of the resources you're trying to load and ensure what you're loading has exactly the same capitalization in your code as it does in the jar or in the file system.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • The capitalization is correct on all platforms. I use a helper library that retrieves the file path for me and with the proper number of back/forward slashes. – user3435571 Apr 19 '14 at 07:24
  • @user3435571: Yes, but what about the package and class names you have in your code? (And what do slashes have to do with anything?) – T.J. Crowder Apr 19 '14 at 07:35
  • I meant the slashes in the string pathnames. On windows, it's two backslashes into the hierarchy, and on UNIX-like platforms it's one forward slash. The package and class names are also equivalent. – user3435571 Apr 19 '14 at 07:40
  • @user3435571: No, on Windows it's **one** backslash (two is the beginning of a UNC path). It looks like two when you write it in a string literal, because you have to escape it. Anyway, good luck. – T.J. Crowder Apr 19 '14 at 07:44
  • Sorry, I left out 'literal' in the previous comment. Anyway, I have made sure the trivial things like spellings, pathnames, capitalization, etc are in check before posting on StackOverflow. I get a ClassDefNotFound on the factory.create() method. This exception isn't even listed as one of the exceptions thrown according to http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/html/javassist/util/proxy/ProxyFactory.html – user3435571 Apr 19 '14 at 07:50
0

The class that cannot be found and causes the exception is

javassist.util.proxy.ProxyObject

Are you sure that you have the correct jar on your class path on the non-Windows OS? The proxy object interface is implemented by any class that javassist creates. It seems to not being visible to the class loader. Did you try to define an explicit class loader provider?

I agree with the other answer that casing is the most probable cause. Can you provide the command with that you run the application and the exact file names of the jars?

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • I believe that it is. I've actually deducted that the problem actually lies within URLClassLoader and not with ProxyObject. The JAR file I'm trying to link dynamically is one installed with Gurobi optimization. For some reason, if the pathspec to the JAR file is wrong, the classLoader.loadClass method will not throw an exception, but the classLoader classes (element count) will not increment. Even if the pathspec to the JAR is correct I get this same result. The URLClassLoader loads the class without actually loading it, and passes a null reference (or a container that has a null) to the proxy – user3435571 Apr 20 '14 at 21:07
  • Than the class loader simply cannot locate the class on its lookup. A class loader will never throw an IO exception when a ressource cannot be found or read but catches the exception and returns a null reference. This probably also causes a noclassdeffounderror which does not reference the original ioexception. – Rafael Winterhalter Apr 20 '14 at 21:25
  • The problem is that the classLoader doesn't throw any exception at all when I try to load the class, even if I don't load that JAR. Both ways, class count doesn't increment - it should throw a ClassNotFoundException, but it doesn't. For some reason, this only happens with the Gurobi JAR and not some other one (and only when it's installed). In addition, if I uninstall Gurobi after moving the dependencies to another folder and loading from the new location, then classLoader works normally (and so does proxyObject). Then it throws a classNotFoundException if I specify the wrong JAR. Why is this? – user3435571 Apr 21 '14 at 03:40
  • Can you once run the above code but set a class loader provider to javassist that returns the url class loader? – Rafael Winterhalter Apr 21 '14 at 07:19