views:

599

answers:

18

So, every Java text book talks about how flexible Java is since it can load classes at run time. Just cobble together a string and give it to Class.forName(), and catch the ClassNotFoundException and handle it. So much for the theory.

Can you give examples of how you've been using Java class loading to achieve a feature which otherwise wouldn't have been possible or easy? Note that I'm not asking "what great things could we do?" - I'm looking for real-world examples, be it an open-source application or - if you can describe this without giving out too much details - a proprietary application.

Edit: Sure, the VM loads classes lazily as it needs them. That's a behind-the-scenes thing as long as I'm sure that all classes I'll ever need are there. How do I handle a ClassNotFoundException? Suppose I've written ten pages worth of text, and the PrinterDriver class can't be found.

+3  A: 

Well, I've used it for dynamically loading JDBC drivers into a J2EE application. Wheteher this could have been done a better way, I have no idea.

It was just easier at the time to do the forName() call.

paxdiablo
Actually, I've never seen any other way to get a JDBC driver. There <i>must</i> be a better way, but I haven't seen it. Fancy that.
doppelfish
An alternative is to set the driver in the jdbc.drivers system property.
Michael Borgwardt
A: 

I use it when I'm building an off-the-shelf application that needs to be tailored by myself or the customer to meet the customer's specific requirements.

Stephen C
+2  A: 

I'm pretty sure plugin loading in Java relies much on that.

The application checks for named functions and executes them

Eclipse actually uses that for plugins

The key idea is to execute code that wasn't planned at developpement time.

Eric
+2  A: 

It can be extremely useful in situations where you're using an API and the API designers actually deprecated some classes from one version to the next (for example the Contacts in Android).

Without reflection and dynamic class loading based on the string name, it would be impossible in this instance to have the same program run on both versions of the platform without getting a class not found exception at runtime. But with it, the same program was tweaked a bit and then could run on both platforms.

JRL
+4  A: 

"PLUGIN" and that is the big word.

Basically, you can load a class that you do not know when or does not exist when you write and compile your program.

For example, if you want a program to do spell check, you can write an interface SpellChecker then load a class from a configuration file that implement the SpellChecker interface. After that, you can write any SpellChecker and set in the configuration file the actual file name. This way, your program does not need to know what class will do the spell checking.

DB driver, Eclipse's plugin, Script language, Cryptography methods are all done this way as the original writer does not know (and in some case, has no idea) what class will actually be used.

Hope this helps.

NawaMan
+2  A: 

The ClassLoader is also used for non-class resources. Configuration files come to mind. Since there is a well-defined search order, it is easy to drop-in your own "log4j.xml" or "hibernate.properties", and the application will find and use it.

Thilo
+1  A: 

i think JUnit may also used a lot of reflection features to make the test framework generic.

Dyno Fu
+8  A: 

Plugins is the first thing that comes to mind. Java class loading makes it very easy compared to languages like C++.

One point that you may not be aware of is that any Java virtual machine heavily relies on class loading internally. Everytime a reference to, say, a method is seen by the bytecode interpreter, it checks whether the class the method belongs to is already loaded, and if it is not, loads it using the very same mechanism behind Class.forName() before resolving the method. This mecanism is very powerful as any Java application truly acts as a set of replaceable components which are all dynamically loaded. If the VM is well written it can for instance load classes through a custom class loader that fetches classes from the network instead of regular files.

The class loading time depends on the virtual machine implementation, but most rely on this late-binding mechanism that loads a class the first time the VM meets it.

Gnurou
Well, GKrellM, implemented in C, does plugins just fine. Put them into your ~/.gkrellm2/plugins/ directory and restart GKrellM for it to find them (it might as well check for new plugins each time the configuration dialog is opened).
doppelfish
It certainly does - my point is that implementing plugins using class loading is much easier and portable than using the traditional dynamic library loading used by C and C++ programs - I'm not trying to say it allows you to do more than in C (and yes, GKremmM does it great!).
Gnurou
A: 

You can use the Class::forName method if the class is in the class path. However if you need to give a path along with the class name i.e c:\document\xyz.class you will have to use the URLClassLoader class.

dev ray
The answer isn't wrong as such, but it doesn't really answer the question.
Joachim Sauer
A: 

See the support for Oracle LOB handling in Spring Framework for example. Only because the framework offers specific support for Oracle you probably don't want to deploy an Oracle datasource as dependency for your e.g. MySQL projects. Therefore you load the Oracle drivers reflectively in the scope of an instance of the LOB handler.

yawn
+5  A: 

Application Servers rely also heavily on ClassLoaders to isolate the different deployed module. E.g.

  • you can deploy the same web app twice under different path
  • two applications can depend on two different version of the same library without conflict.

Thanks to the magic of class loaders...

ewernli
True, but (1) i can start the same binary twice, each time with a different configuration, and (2) I can have different version of one dll (shared object), and binaries can link against its favourite version. Next thing you know, dll hell.
doppelfish
A: 

Servlet containers like Tomcat read your war/webapp configuration file from WEB-INF/web.xml and load your Servlet/Filter/etc. subclasses based on the String values you put in the XML file. For database connections, they pull the class name to load from your configuration, e.g. "com.mysql.jdbc.Driver" for MySQL.

Harold L
+2  A: 

I remember creating a class loader to load classes remotely. The application was running on one node while the classes were stored on another node.

And also by customising the class loader you can transform classes as they are loaded. This is used by some ORM frameworks as well as some AOP frameworks.

Michael Wiles
A: 

Real-world example (as requested in your question), proprietary application (as explicitely allowed by your question)...

Upon startup, the client-side software contacts our server(s) and says "Default implementation of interface Bar I have is Foo (because actually every version 1.03, for example, are using Foo), do you have a better one?" If meanwhile we wrote a better implementation, we answer "yup, Bar is old, use Buz, it's better".

Then on the client side a class loader is used to load the latest implementation.

It's oversimplified but it's a real world example. It's not entirely dissimilar to the example JRL mentioned: where deprecated classes are automagically replaced by newer ones.

Webinator
+1  A: 

The JDBC API is an excellent example for this. This way you can configure the JDBC driver externally in for example a properties file:

driver = com.dbvendor.jdbc.Driver
url = jdbc:dbvendor://localhost/dbname
username = stackoverflow
password = youneverguess

..which you can use as:

Properties properties = new Properties();
properties.load(Thread.currentThread().getResourceAsStream("jdbc.properties"));

String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");

Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);

Every JDBC driver implementation basically registers itself in the DriverManager inside a static initializer block. It's namely the one which get executed during Class#forName().

package com.dbvendor.jdbc;

public class Driver implements java.sql.Driver {

    static {
         java.sql.DriverManager.registerDriver(new Driver());
    }

    private Driver() {
        // ...
    }

    public boolean acceptsURL(String url) {
        return url.startsWith("jdbc:dbvendor");
    }

}

Since the DriverManager roughly look like this (it actually uses the old fashioned Vector)

private static final Set<Driver> drivers = new HashSet<Driver>();

public static void registerDriver(Driver driver) {
    drivers.add(driver);
}

public static Connection getConnection(String url, String username, String password) throws SQLException {
    for (Driver driver : drivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url, username, password);
        }
    }
    throw new SQLException("No suitable driver");
}

...you can get a connection from it without the need to instantiate the driver itself!

This way the JDBC code is highly portable. You can change the DB or distribute the code among users with different DB's without the need to change/hack/rebuild the code itself.

It's not only JDBC which uses this approach, also other API's such as Servlet API, ORM's like Hibernate/JPA, dependency injection frameworks, etcetera uses reflection to load the classes based on externally configureable propertiesfiles, XML config files and/or annotations. It all just makes the code much more portable and pluggable.

BalusC
+1  A: 

The Java classloader mechanism is powerful because it provides an abstraction point at exactly the point where code is loaded, which lets you do things such as:

  • finding the class bits someplace other than the classpath (db, remote url, file system, etc)
  • loading source code you just created and compiled yourself (with the javac api)
  • loading byte code you just generated yourself (say with ASM)
  • loading code and MODIFYING it before you use it (with ASM, Java agents, etc etc)
  • RE-load code on the fly
  • chain loaders together in trees (normal delegation) or webs (sibling-based OSGi style) or whatever you want

On the point of modifying code during load, there are a world of interesting things you can do to remix your code - AOP, profiling, tracing, behavior modifications, etc. At Terracotta we relied on the classloader abstraction to dynamically load a class, then intercept all access to fields and dynamically add the ability to load state from the same object at a remote node in the cluster later. Cool stuff.

Alex Miller
A: 

Using the dynamic class loading is also very useful for loading configuration files as Thilo mentions. More generally, dynamic class loading can make a nice file system abstraction layer in many situations, simplifying writing preference and config sensitive code. Just make sure the resource you need is on the classpath and load it as an InputStream.

Furthermore, with a custom protocol handler in Java it is possible to access items on the classpath via URL. This isn't an advantage specific to dynamic class loading, but it does demonstrate how classpath resources can be accessed via the same API as other resources (even remote ones). http://java.sun.com/developer/onlineTraining/protocolhandlers/

dietrich
A: 

Any framework that is configuration based (struts, jsf, spring, hibernate, etc.) uses this mechanism. Any product that is based on the plugin architecture also uses this feature.

fastcodejava