java - Dynamically loading plugin jars using ServiceLoader -


i'm trying create plugin system application, , want start simple. every plugin should packed in .jar file , implement simpleplugin interface:

package plugintest;  public interface simpleplugin {     public string getname(); } 

now i've created implementation of simpleplugin, packed in .jar , put in plugin/ subdirectory of main application:

package plugintest;  public class plugintest implements simpleplugin {     public string getname() {         return "i'm plugin!";     } } 

in main application, want instance of plugintest. i've tried 2 alternatives, both using java.util.serviceloader.

1. dynamically extending classpath

this uses known hack use reflection on system class loader avoid encapsulation, in order add urls the classpath.

package plugintest.system;  import plugintest.simpleplugin;  import java.io.file; import java.io.ioexception; import java.net.url; import java.net.urlclassloader; import java.util.iterator; import java.util.serviceloader;  public class manageplugins {     public static void main(string[] args) throws ioexception {         file loc = new file("plugins");         extendclasspath(loc);          serviceloader<simpleplugin> sl = serviceloader.load(simpleplugin.class);         iterator<simpleplugin> apit = sl.iterator();         while (apit.hasnext())             system.out.println(apit.next().getname());     }      private static void extendclasspath(file dir) throws ioexception {         urlclassloader sysloader = (urlclassloader) classloader.getsystemclassloader();         url urls[] = sysloader.geturls(), udir = dir.touri().tourl();         string udirs = udir.tostring();         (int = 0; < urls.length; i++)             if (urls[i].tostring().equalsignorecase(udirs)) return;         class<urlclassloader> sysclass = urlclassloader.class;         try {             method method = sysclass.getdeclaredmethod("addurl", new class[]{url.class});             method.setaccessible(true);             method.invoke(sysloader, new object[] {udir});         } catch (throwable t) {             t.printstacktrace();         }     } } 

the plugins/ directory added expected (as 1 can check calling sysloader.geturls()), iterator given serviceloader object empty.

2. using urlclassloader

this uses definition of serviceloader.load second argument of class classloader.

package plugintest.system;  import plugintest.simpleplugin;  import java.io.file; import java.io.filefilter; import java.io.ioexception; import java.net.url; import java.net.urlclassloader; import java.util.iterator; import java.util.serviceloader;  public class manageplugins {     public static void main(string[] args) throws ioexception {         file loc = new file("plugins");          file[] flist = loc.listfiles(new filefilter() {             public boolean accept(file file) {return file.getpath().tolowercase().endswith(".jar");}         });         url[] urls = new url[flist.length];         (int = 0; < flist.length; i++)             urls[i] = flist[i].touri().tourl();         urlclassloader ucl = new urlclassloader(urls);          serviceloader<simpleplugin> sl = serviceloader.load(simpleplugin.class, ucl);         iterator<simpleplugin> apit = sl.iterator();         while (apit.hasnext())             system.out.println(apit.next().getname());     } } 

once again, iterator has never "next" element.

there's surely i'm missing since it's first time i'm "playing" class paths , loading.

the problem simple. , stupid. in plugin .jar files /services/plugintest.simpleplugin file missing inside meta-inf directory, serviceloader couldn't identify jars services , load class.

that's pretty all, second (and cleaner) way works charm.

i thought had cheer 200th answer... it's question of mine =__=


Comments

Popular posts from this blog

node.js - Bad Request - node js ajax post -

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -