2

Hi I am creating a plugin which requires loading jars dynamically and accessing the classes and methods of these jars. I tried using URLClassLoader and am able to load the classes as shown below

URL myJarFile = new URL("jar","","file:"+jarPath);
URLClassLoader sysLoader =(URLClassLoader)ClassLoader.getSystemClassLoader();
Class sysClass = URLClassLoader.class;
Method sysMethod = sysClass.getDeclaredMethod("addURL", new Class[]{URL.class});
sysMethod.setAccessible(true);
sysMethod.invoke(sysLoader, new Object[]{myJarFile});

But the issue with this is that we have to load classes into classLoader by specifying their name individually. What I want is to load all the classes from all jars in class-path and access them any point of time.

Is it possible with URLClassLoader? If not what are the other options? How much helpful is OSGI in achieving this?

Thanks in advance!

Yunkhan
  • 53
  • 3
  • 10
  • "What I want is to load all the classes from all jars in class-path and access them any point of time." Why??? Your question is not answerable without some idea about your motivation. If you're trying to build an extensible application with the ability to add plugins then you should *absolutely* be using OSGi. – Neil Bartlett Feb 22 '14 at 09:25

2 Answers2

4

You need to load your jar first and then load the required class from there.

URL myJarFile = new URL("jar","","file:"+jarPath);
URLClassLoader child = new URLClassLoader (myJarFile , this.getClass().getClassLoader());
Class classToLoad = Class.forName ("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod ("myMethod");
Object instance = classToLoad.newInstance ();
Object result = method.invoke (instance);

Then you can get a list of all the classes in the jar file first:

List<String> classNames=new ArrayList<String>();
ZipInputStream zip=new ZipInputStream(new FileInputStream("/path/to/jar/file.jar"));
for(ZipEntry entry=zip.getNextEntry();entry!=null;entry=zip.getNextEntry())
    if(entry.getName().endsWith(".class") && !entry.isDirectory()) {
        StringBuilder className=new StringBuilder();
        for(String part : entry.getName().split("/")) {
            if(className.length() != 0)
                className.append(".");
            className.append(part);
            if(part.endsWith(".class"))
                className.setLength(className.length()-".class".length());
        }
        classNames.add(className.toString());
    }

Once you have list of your classes do the following:

File file = new File("Absolute Path to your jar");  
            URL url = file.toURI().toURL();  
            URL[] urls = {url};  
            ClassLoader loader = new URLClassLoader(urls);  
            Class myClass = loader.loadClass(classNames.get(0));  
            System.out.println("Executing...");  
            Object tester = myClass.newInstance(); 
        System.out.println("Test");
Mobility
  • 263
  • 2
  • 5
  • Tats the catch.. I will not be knowing what class to load.. thr are many classes in that jar and I want all the classes to be available in class-path... – Yunkhan Feb 20 '14 at 11:09
  • Thanks @Mobility. That will really solve the problem of loadind all the classes. But now if i want to access some particular class of the laoded jar in a way say `SomeJarClass obj = SomeJarClass.getInstance()` this should work since _all the classes of that jar is loaded_ . But, It again gives a class not found exception. – Yunkhan Feb 21 '14 at 04:36
  • I found a solution for it. Actually the way I was calling the class was wrong. Now I am able to laod jars. load one main class which internally uses instances of other classes from other jars and all of them are available at runtime. – Yunkhan Feb 21 '14 at 06:30
1

Apache Felix File Install may be exactly what you want. It will monitor a nominated directory and dynamically load any bundles in it. Only packages exported by the bundles will be available to other bundles on the classpath, but all classes will be loaded.

Holly Cummins
  • 10,767
  • 3
  • 23
  • 25