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 get
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.
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.
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.
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
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();
}
The basic idea of getProperty()
is that programs/code can be configured from outside of the JVM, passing properties on the command line using the java -Dfoo=bar
syntax.
As you may want to configure certain behaviour in other software components (such as a logging component) in situations where you don't have control over the command line - think being deployed in a Servlet container - setProperty()
comes in as a handy way to programmatically alter settings, e.g., before instantiating your logging utility.
The problem that is exhibited by the classpath
issue is that programs will typically only read such system properties exactly once, when they are first initialized. So changing the classpath after JVM startup doesn't change anything for you app itself, because the JVM is already initialized, and changing some logging configuration after you have already obtained a Logger instance (or whatever), typically won't have any effect either.
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.
There is also a way to change java.library.path in runtime, to do that, just do:
System.setProperty( "java.library.path", newPath);
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null); // that's the key.
When this private static field in ClassLoader class is set to null, on next attempt to load native library ClassLoader will be initialized again using the new value in java.library.path.