Extends thread http://forum.java.sun.com/thread.jspa?threadID=5246791&tstart=15 in order to give away more duke points.
Is it possible to load a static object with a custom class loader that makes calls to this object without reflection?
Some code:
package tests.classloader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Hashtable;
public class UnloadingTest {
public static void main(String[] args) throws Exception {
CustomClassLoader test = new CustomClassLoader();
Object o = test.loadClass("tests.classloader.Singleton").newInstance();
System.out.println("Instantiated Singleton: " + o.getClass());
System.out.println("Instantiated Singleton classloader: " + o.getClass().getClassLoader());
System.out.println("Static Singleton outside singleton constructor:" + Singleton.class.getClassLoader());
}
}
class CustomClassLoader extends ClassLoader {
private Hashtable<String, Class<?>> classes = new Hashtable<String, Class<?>>();
public CustomClassLoader(){
super(CustomClassLoader.class.getClassLoader());
}
public Class loadClass(String className) throws ClassNotFoundException {
return findClass(className);
}
public Class findClass(String className){
byte classByte[];
Class result=null;
result = (Class)classes.get(className);
if(result != null){
return result;
}
// since findClass is overloaded we'll get a recursive
// call from system class loader here
if (className.indexOf("java") >= 0) {
try{
result = findSystemClass(className);
classes.put(className,result);
return result;
}catch(Exception e){
}
}
try{
String classPath = File.separatorChar + ((String)ClassLoader.getSystemResource(className.replace('.',File.separatorChar)+".class").getFile()).substring(1);
classByte = loadClassData(classPath);
result = defineClass(className,classByte,0,classByte.length,null);
classes.put(className,result);
return result;
}catch(Exception e){
return null;
}
}
private byte[] loadClassData(String className) throws IOException {
File f ;
f = new File(className);
int size = (int)f.length();
byte buff[] = new byte[size];
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buff);
dis.close();
return buff;
}
}
And the separate singleton class:
package tests.classloader;
public class Singleton {
public static boolean loaded = false;
private static Singleton s;
private static int accesses = 0;
public Singleton() {
System.out.println("Singleton constructor: " + Singleton.class.getClassLoader());
if (loaded) {
System.out.println("Already loaded.");
}
loaded = true;
}
public static Singleton getInstance() {
if (!loaded) {
s = new Singleton();
}
return s;
}
public static int getAccesses() {
return accesses++;
}
public static void dispose() {
loaded = false;
s = null;
}
}
The output is:
Singleton constructor: tests.classloader.CustomClassLoader@ca318a
Instantiated Singleton: class tests.classloader.Singleton
Instantiated Singleton classloader: tests.classloader.CustomClassLoader@ca318a
Static Singleton outside singleton constructor:sun.misc.Launcher$AppClassLoader@a9c85c
But I'd like the last line of output to be:
Static Singleton outside singleton constructor: tests.classloader.CustomClassLoader@ca318a
Which seems to be the case in the Singleton constructor.
Is this possible?
Regards
rimu