Why can't System.setProperty() change the classpath at runtime?

I am refering to the question on changing the classpath programmatically.

I read and found out that there is some function under System class as getproperties where we can retrieve the properties and then also can set it using setProperties().

The answers however I got was that It Wont work. I have not tried this myself, however, i am taking the call.

Just to clarify, then why these setProperty() and getProperty() methods are there if they cannot alter it at run time. Or is this specific to the classpath property only ?

I will appreciate if someone can present a scenario where they are really helpful?


You can certainly set any system properties you want at any point of time. The question is, will it have any effect? In the case of classpath, the answer is NO. The system class loader is initialized at a very early point in the startup sequence. It copies the classpath into its own data structures, and the classpath property is not read again. Changing it affect nothing in the system.

The reason for this may be two-fold. The lesser reason is performance. You may need to have some sort of data structure built for quick lookup of resources, and re-parsing classpath every time may be inefficient. The more important reason is security. You don't want a rogue class change the classpath under you and load compromised version of another class.


Modify Classpath

Even though you cannot set the classpath using the system properties (because the JVM reads system properties once: at startup), you can still change the classpath by forcibly invoking the addURL method of the classloader. Note that the solution below does not take into consideration the current thread. Consequently, it might not be accurate in all situations.

Example Solution

The original source on Sun's website for the following code has been removed:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;                   

import java.io.File;
import java.io.IOException;

import java.net.URL;
import java.net.URLClassLoader;

/**
 * Allows programs to modify the classpath during runtime.              
 */                                                                     
public class ClassPathUpdater {                                         
  /** Used to find the method signature. */                             
  private static final Class[] PARAMETERS = new Class[]{ URL.class };   

  /** Class containing the private addURL method. */
  private static final Class<?> CLASS_LOADER = URLClassLoader.class;

  /**
   * Adds a new path to the classloader. If the given string points to a file,
   * then that file's parent file (i.e., directory) is used as the
   * directory to add to the classpath. If the given string represents a
   * directory, then the directory is directly added to the classpath.
   *
   * @param s The directory to add to the classpath (or a file, which
   * will relegate to its directory).
   */
  public static void add( String s )
    throws IOException, NoSuchMethodException, IllegalAccessException,
           InvocationTargetException {
    add( new File( s ) );
  }

  /**
   * Adds a new path to the classloader. If the given file object is
   * a file, then its parent file (i.e., directory) is used as the directory
   * to add to the classpath. If the given string represents a directory,
   * then the directory it represents is added.
   *
   * @param f The directory (or enclosing directory if a file) to add to the
   * classpath.
   */
  public static void add( File f )
    throws IOException, NoSuchMethodException, IllegalAccessException,
           InvocationTargetException {
    f = f.isDirectory() ? f : f.getParentFile();
    add( f.toURI().toURL() );
  }

  /**
   * Adds a new path to the classloader. The class must point to a directory,
   * not a file.
   *
   * @param url The path to include when searching the classpath.
   */
  public static void add( URL url )
    throws IOException, NoSuchMethodException, IllegalAccessException,
           InvocationTargetException {
    Method method = CLASS_LOADER.getDeclaredMethod( "addURL", PARAMETERS );
    method.setAccessible( true );
    method.invoke( getClassLoader(), new Object[]{ url } );
  }

  private static URLClassLoader getClassLoader() {
    return (URLClassLoader)ClassLoader.getSystemClassLoader();
  }
}

The link no longer works: http://forums.sun.com/thread.jspa?threadID=300557

Example Usage

The following example will add /home/user/dev/java/app/build/com/package to the classpath at runtime:

try {
  ClassPathUpdater.add( "/home/user/dev/java/app/build/com/package/Filename.class" );
}
catch( Exception e ) {
  e.printStackTrace();
}

System.setProperty can be used to set some security or protocol handler at the beginning of a program. Like:

/*
Add the URL handler to the handler property. This informs 
IBMJSSE what URL handler to use to handle the safkeyring 
support. In this case IBMJCE.
*/
System.setProperty("java.protocol.handler.pkgs", "com.ibm.crypto.provider");

or for using SSL:

System.setProperty("javax.net.ssl.keyStore", context.getRealPath(KEYSTORE));
System.setProperty("javax.net.ssl.keyStorePassword", "password");
System.setProperty("javax.net.ssl.trustStore", context.getRealPath(TRUSTSTORE));
System.setProperty("javax.net.debug", "ssl");
HttpClient httpClient = new HttpClient();
GetMethod httpGet = new GetMethod("https://something.com");
httpClient.executeMethod(httpGet);
return new String(httpGet.getResponseBody());

But beware, because it changes the environment at runtime for ALL applications running in the same jvm.
If for example one application needs to run with saxon and the other with xalan and both make use of System.setProperty to set the transformerFactory, then you will run into trouble

As said in Monitored System.setProperty article,
System.setProperty() can be an evil call.

  • It is 100% thread-hostile
  • It contains super-global variables
  • It is extremely difficult to debug when these variables mysteriously change at runtime

Regarding the classpath property, as I said in a previous question, it can not be easily changed as runtime.

In particular, java System property java.class.path is used to build a linked link when the JRE is instantiated, then is not re-read. Therefore, changes you make to the property don't really do anything to the existing virtual machine.