10

I am attempting to load classes dynamically into a component. I am using a file chooser to select the .JAR file that will be loaded and then a option pane to get the name of the class.

I have trawled the internet looking for how to convert a java file to a URL in order to load it in URLClassLoader and I have come up with:

File myFile = filechooser.getSelectedFile(); String className = JOptionPane.showInputDialog( this, "Class Name:", "Class Name", JOptionPane.QUESTION_MESSAGE); URL myUrl= null; try { myUrl = myFile.toURL(); } catch (MalformedURLException e) { } URLClassLoader loader = new URLClassLoader(myUrl); loader.loadClass(className); 

I am now getting a 'cannot find symbol' error for loading the URL into the URLClassLoader

4

5 Answers 5

8

I like the ClassPathHacker class mentioned in the answer by Zellus, but it's full of deprecated calls and bad practices, so here's a rewritten version that also caches the Classloader and the addUrl method:

import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.io.IOException; import java.io.File; public class ClassPathHacker{ private static final Class<URLClassLoader> URLCLASSLOADER = URLClassLoader.class; private static final Class<?>[] PARAMS = new Class[] { URL.class }; public static void addFile(final String s) throws IOException{ addFile(new File(s)); } public static void addFile(final File f) throws IOException{ addURL(f.toURI().toURL()); } public static void addURL(final URL u) throws IOException{ final URLClassLoader urlClassLoader = getUrlClassLoader(); try{ final Method method = getAddUrlMethod(); method.setAccessible(true); method.invoke(urlClassLoader, new Object[] { u }); } catch(final Exception e){ throw new IOException( "Error, could not add URL to system classloader"); } } private static Method getAddUrlMethod() throws NoSuchMethodException{ if(addUrlMethod == null){ addUrlMethod = URLCLASSLOADER.getDeclaredMethod("addURL", PARAMS); } return addUrlMethod; } private static URLClassLoader urlClassLoader; private static Method addUrlMethod; private static URLClassLoader getUrlClassLoader(){ if(urlClassLoader == null){ final ClassLoader sysloader = ClassLoader.getSystemClassLoader(); if(sysloader instanceof URLClassLoader){ urlClassLoader = (URLClassLoader) sysloader; } else{ throw new IllegalStateException( "Not an UrlClassLoader: " + sysloader); } } return urlClassLoader; } } 
Sign up to request clarification or add additional context in comments.

Comments

5

ClassPathHacker.java found in this forum thread, is an option to load classes dynamically.

import java.lang.reflect.*; import java.io.*; import java.net.*; public class ClassPathHacker { private static final Class[] parameters = new Class[]{URL.class}; public static void addFile(String s) throws IOException { File f = new File(s); addFile(f); }//end method public static void addFile(File f) throws IOException { addURL(f.toURL()); }//end method public static void addURL(URL u) throws IOException { URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader(); Class sysclass = URLClassLoader.class; try { Method method = sysclass.getDeclaredMethod("addURL",parameters); method.setAccessible(true); method.invoke(sysloader,new Object[]{ u }); } catch (Throwable t) { t.printStackTrace(); throw new IOException("Error, could not add URL to system classloader"); }//end try catch }//end method }//end class 

Comments

2

Take a look at this related question: How should I load Jars dynamically at runtime?

Comments

1

The constructor of URLClassLoader takes an array of URLs, not a single URL.

Comments

0

I rewrote this in scala in case anyone needs as it isn't 100% trivial :)

/* * Class which allows URLS to be "dynamically" added to system class loader */ object class_path_updater { val URLCLASSLOADER = classOf[URLClassLoader] var urlClassLoader = getUrlClassLoader var addUrlMethod = getAddUrlMethod /* * addFile - have to use reflection to retrieve and call class loader addURL method as it is protected */ def addFile(s: String) = { val urlClassLoader = getUrlClassLoader try { val method = getAddUrlMethod method.setAccessible(true) val v = (new File(s)).toURI.toURL invoke(urlClassLoader, method, Array[AnyRef](v)) def invoke(proxy: AnyRef, m: Method, args: Array[AnyRef]) = m.invoke(proxy, args: _*) } } private def getAddUrlMethod: Method = { if (addUrlMethod == null) addUrlMethod = URLCLASSLOADER.getDeclaredMethod("addURL", classOf[URL]) addUrlMethod } private def getUrlClassLoader: URLClassLoader = { if (urlClassLoader == null) { val sysLoader = ClassLoader.getSystemClassLoader sysLoader match { case x: URLClassLoader => urlClassLoader = sysLoader.asInstanceOf[URLClassLoader] case _ => throw new IllegalStateException("Not a UrlClassLoader: " + sysLoader) } } urlClassLoader } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.