Have been trying this since few days and can't get it working!
I am trying to build a pluggable java application where I can run it from command line and provide plugins (jars) in a separated folder. It seems the ServiceLoader
would fit my requirement but I think I need a special case where the jars are not part of the classpath whereas they are stored in a different location, and for this reason I would need to use a ClassLoder
pointing its url to this file system path.
One of the plugin i want to provide to the main application is a log jar with some custom features.
Here below the code I am using , but can't get to go into the for/loop .. it means that the ServiceLoader
is not able to identify/match any class implementation :
final URL u = new File("C:\\data\\myLogJar-1.0-SNAPSHOT.jar").toURI().toURL();
ClassLoader ucl = new URLClassLoader(new URL[] {u});
ServiceLoader<Log> loader = ServiceLoader.load(Log.class, ucl);
for (Iterator<Log> iterator = loader.iterator(); iterator.hasNext(); ) {
System.out.println(iterator.next());
}
loader = ServiceLoader.load(Log.class,ucl);
for (final Log log : loader) {
log.info("Test log");
}
I wish you could help! Thanks a lot
==== adding project files :
Main pluggable application :
package com.company.dep.automation;
import com.company.dep.automation.pluggable.Log;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
public class Main {
private static ServiceLoader<Log> serviceLoader;
public static void main(String[] args) {
final URL u;
ClassLoader ucl = null;
try {
u = new File("C:\\data\\myLogJar-1.0-SNAPSHOT.jar").toURI().toURL();
ucl = new URLClassLoader(new URL[]{u});
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
ServiceLoader<Log> loader = ServiceLoader.load(Log.class, ucl);
for (Iterator<Log> iterator = loader.iterator(); iterator.hasNext(); ) {
System.out.println(iterator.next());
}
loader = ServiceLoader.load(Log.class, ucl);
for (final Log log : loader) {
log.info("Test log");
}
}
}
the "Log" plugin
The interface Log
package com.company.automation.service;
public interface Log {
void trace(String message);
void debug(String message);
void info(String message);
void warn(String message);
void severe(String message);
void error(String message);
void fatal(String message);
}
Its implementation
package com.company.automation.service.impl;
import com.company.automation.service.Log;
public class LogImpl implements Log {
@Override
public void trace(String message) {
log("TRACE --> " + message);
}
@Override
public void debug(String message) {
log("DEBUG --> " + message);
}
@Override
public void info(String message) {
log("INFO --> " + message);
}
@Override
public void warn(String message) {
log("WARN --> " + message);
}
@Override
public void severe(String message) {
log("SEVERE --> " + message);
}
@Override
public void error(String message) {
log("ERROR --> " + message);
}
@Override
public void fatal(String message) {
log("FATAL --> " + message);
}
private void log(String message) {
System.out.println(message);
}
}
=================
Adjusted the project structure as following but still doesnt work :
It doesn't work because it is not the same class Log
, your main method try to find implementations of com.company.dep.automation.pluggable.Log
while your jar defines an implementation of com.company.automation.service.Log
such that ServiceLoader.load
simply cannot find anything.
You should move the interface com.company.automation.service.Log
from the extension jar to the project with your Main
class and import com.company.automation.service.Log
instead of com.company.dep.automation.pluggable.Log
in your Main
class then everything should work.