[Java] Loading JAR files in to the classpath at runtime

Started by Camel, September 08, 2007, 01:35:54 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Camel

JavaOp appears to load plugin JARs in to the CP; if that's how it works, how's it done?

I want to be able to load JDBC drivers on-the-fly.

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

iago

It's opensource, have a look!

I seem to remember using Class.forName(), though. The Class class (ha!) has what you need, I think.

Camel

Class.forName(..) just returns a <Class>; its purpose is to verify that a class is in the classpath, and to kick off any static initializers. That particular method will not add new JARs to the classpath.

I'll have a look at the rest of Class's methods, though.

[edit] Nevermind, you were right, iago. There are two forNames(); I didn't realize there was one that took a ClassLoader.

http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
URL u = new URL("jar:file:/path/to/pgjdbc2.jar!/");
String classname = "org.postgresql.Driver";
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Driver d = (Driver)Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverShim(d));
DriverManager.getConnection("jdbc:postgresql://host/db", "user", "pw");

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

Camel

Got it working. I wrote a class that provides a new forName(String), and will load any class out of any jar in the lib folder.

http://bnubot.googlecode.com/svn/trunk/BNUBot/src/net/bnubot/JARLoader.java

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

Joe

I'm a bit rusty. The return from that method should be cast to match an Interface, correct?
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


Camel

I assume you're referring to JARLoader.forName(String)? Since it's a simple redirect to URLClassLoader.loadClass(String), you could consult the documentation for that method, but I'll take a stab at it anyways, even though I'm not sure I understand your question entirely.

The return value of the method is Class<?>, which is the standard way of specifying unknown origin in Java 1.5+ -- it's functionally equivalent to saying Class<Object>, but is more specific. With a Class object, you can induce reflection upon the class, create an instance according to the constructor "new ?()", and do a number of other things.

Why would you want to cast a Class<?> to an interface? It does implement a few things (Serializable, and three reflection-specific things), but the reduction is fruitless.

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!

Joe

Can you access methods in the Class<?> just by calling them? The reason I thought you'd have to have to cast it to an interface is because the Loader doesn't know the loaded class' methods at compile-time.
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


Chavo

If you use reflection, you can invoke a method (or constructor) without knowing the class structure at compile time (although it helps to avoid invocation exceptions).  The javadoc on reflection is pretty good, you should read it.  I think I have an old topic in here somewhere about the performance differences associated with reflection as well (Myndfyre even made some pretty graphs ;))

Camel

Quote from: Joex86] link=topic=10210.msg129802#msg129802 date=1189443013]
Can you access methods in the Class<?> just by calling them? The reason I thought you'd have to have to cast it to an interface is because the Loader doesn't know the loaded class' methods at compile-time.

The method returns an object of type Class<?>.

Class is defined like so:

public class Class<T> {
public T newInstance() throws ...;
}


Actually, if you look at the real definition, that's not how it works (it always returns an Object), but it's guaranteed to either return one of whatever the class was, or throw an exception. Therefore, it's safe to cast to what you were expecting without type-checking. Just be aware you could get a cast exception if you create something that you weren't expecting.


Driver d = (Driver)JARLoader.forName(driver).newInstance();
DriverManager.registerDriver(new DriverShim(d));

<Camel> i said what what
<Blaze> in the butt
<Camel> you want to do it in my butt?
<Blaze> in my butt
<Camel> let's do it in the butt
<Blaze> Okay!