ServiceLoader.next causing a NoClassDefFoundError
Asked Answered
H

1

8

I'm asking because I'm totally not sure I've done the right thing. I'm using Eclipse for a web project. Let's call it WebProject (duh) in the package com.web.project.

I want WebProject to load JAR plugins at runtime, so I thought I could take advantage of java.util.ServiceLoader. So I created an interface com.web.project.WebProjectPlugin in the WebProject project with all the methods the plugins must implement.

Then I created the project PluginProject, adding WebProbject/build/classes in its Build path as a class folder:

package com.web.project.plugin;

import com.web.project.WebProjectPlugin;

public class TestPlugin implements WebProjectPlugin {
    // Implementation of the interface methods...
}

Then I created a META-INF/services folder in the plugin project, put the text file com.web.project.WebProjectPlugin inside, containing the sole line "com.web.project.plugin.TestPlugin".

I exported the JAR file checking out the added build/classes folder and put it somewhere in the hard drive. When WebProject starts up, it does the following:

File[] jlist = pluginsDir.listFiles(new FileFilter() {
    public boolean accept(File file) {
        return file.getPath().toLowerCase().endsWith(".jar");
    }
});
URL[] urls = new URL[jlist.length];
for (int i = 0; i < jlist.length; i++)
    urls[i] = jlist[i].toURI().toURL();
URLClassLoader ucl = new URLClassLoader(urls);

ServiceLoader<WebProjectPlugin> srvl =
    ServiceLoader.load(WebProjectPlugin.class, ucl);
Iterator<WebProjectPlugin> iter = srvl.iterator();
while (iter.hasNext()) {
    WebProjectPlugin plugin = iter.next();
    plugins.add(plugin);
}

pluginsDir is a File object pointing to the directory the JAR file is in. At first it seems that srvl does its job, since iter isn't empty, but then it throws the dreaded NoClassDefFoundError when it reaches iter.next().

I've already managed to create a plugin manager project to test ServiceLoader, and it runs just fine, but it's a plain console Java application, not a web project. So, what am I doing wrong here?

I'm a little puzzled: how can it not find the class definition for com.web.project.WebProjectPlugin, since it's in the same project that is running? Has that something to do with the URLClassLoader object I'm using?

This is the stack trace.

Herringbone answered 30/4, 2013 at 8:5 Comment(0)
S
8

Try assigning the parent classloader to your URLClassLoader

URLClassLoader loader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());

A WebProject expects a certain hierarchy of class loaders, so it might be that your classes are not visible to each other if the parent/child hieararchy is not set properly.

Santa answered 30/4, 2013 at 8:9 Comment(1)
I think you meant Thread.currentThread().getContextClassLoader(), but you know what? It runs just fine! Thanks!Herringbone

© 2022 - 2024 — McMap. All rights reserved.