3

I can't get the Service Provider Interface to load an implementation from another JAR in the same directory. It only works when I use -Djava.ext.dirs=. on the command line. Should it not work without?

I have the following interface:

package playground;

public interface TestIface {
    public String test();
}

which is implemented here:

package playground;

public class TestImpl implements TestIface {
    public String test() {
        return "TEST";
    }
}

Here I try to load the implementation:

package playground;
import java.util.Iterator;
import java.util.ServiceLoader;
public class Lalala {
    public static void main(String[] args) {
        ServiceLoader<TestIface> loader = ServiceLoader.load(TestIface.class);
        Iterator<TestIface> it = loader.iterator();
        while (it.hasNext()) {
            TestIface a = it.next();
            System.out.println(a.test());
        }
        System.out.println("DONE");
    }

}

The interface and the last class are packaged in main.jar, the implementation in impl.jar. main.jar has the Main class set and impl.jar has the META-INF/services/playground.TestIface file which contains "playground.TestImpl". Both JARs are in the same directory. Running

java -jar main.jar

only prints "DONE", the implementation apparently is not found.

If I instead run

java -Djava.ext.dirs=. -jar main.jar

it also prints "TEST" as it should.

What am I doing wrong? Why is the implementation from the other JAR not loaded unless I change the java.ext.dirs setting?

1 Answers1

1

The java.ext.dirs setting automatically adds all jar-files found in the specified directory to the main classloader, which is why the ServiceLoader can find and load TestIface.class (from the Apidocs: "Creates a new service loader for the given service type, using the current thread's context class loader.").

But you should not use java.ext.dirs for this (see here for one of the dangers). And when you use java -jar you cannot use java -cp to set a classpath (you can only use one of them). This leaves you the option to use the URLClassLoader to load additional jars and then call ServiceLoader.load(class from another jar).

Tip: to load other jar-files, use the location of the main.jar file as explained in the answers of this question. Other variables (like startup directory) depend on how and from where Java was started and can easily result in not finding the other jar-files.

Community
  • 1
  • 1
vanOekel
  • 6,358
  • 1
  • 21
  • 56
  • URLLoader works well, I just tried it, thanks. So `java.ext.dirs` does not include the current directory by default? – user3004220 Mar 30 '14 at 14:27
  • No, it is meant to include additional jars installed with/added to your Java installation. Anyway it is more a 'system setup' thing than an 'application setup' thing - best to leave it alone. – vanOekel Mar 30 '14 at 14:31