Class loading

Hello!

Is there a possibility to set the own class loader for the whole application? I know about the possibility to do this for each case:

Object o = myClassLoader.LoadClass("Object").newInstance();

Could it be done for all classes without having to write it each time?

Thanx
shternAsked:
Who is Participating?
 
Sasha_MapaConnect With a Mentor Commented:
This works for me:

import java.lang.reflect.*;
import java.io.*;

public class Wrapper{

  public static void main(String [] args) throws Exception{
    MyCustomClassLoader loader = new MyCustomClassLoader();
    Class appClass = loader.loadClass(args[0],true);
    String [] realArgs = new String[args.length-1];
    System.arraycopy(args,1,realArgs,0,realArgs.length);
    Method mainMethod = appClass.getMethod("main",new Class[]{String [].class});
    mainMethod.invoke(null,new Object[]{args});
 }

}


class MyCustomClassLoader extends ClassLoader{


  private byte [] loadClassData(String name) throws IOException{
    System.out.println(name.replace('.',File.separatorChar)+".class");
    InputStream in = new FileInputStream(name.replace('.',File.separatorChar)+".class");
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int b;
    while ((b=in.read())!=-1){
      buf.write(b);
    }
    return buf.toByteArray();
  }


  public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException{
    byte data [];
    try{
      data = loadClassData(name);
    } catch (IOException e){
        return findSystemClass(name);
      }
    Class c = defineClass(data, 0, data.length);
    if (resolve)
      resolveClass(c);
    return c;
  }

}



public class Application{

 static{
   System.out.println("Class Application loaded with "+Application.class.getClassLoader()+" classloader");
 }

 public static void main(String [] args){
   System.out.println("Main invoked");
 }

}


What you must have done wrong is first trying to use ClassLoader.findSystemClass() and only then your way of loading. Since your class is probably in the classpath, the bootstrap classloader will have no problem loading it...

Sasha Maryanovsky.

0
 
dnoelppCommented:
You can't I am afraid. But you can set a context class loader for a thread.

Use: Thread.getCurrentThread().setContextClassLoader(myClassLoader);

Hope this partial solution helps you.

0
 
dnoelppCommented:
A workaround for the limitation that you can only set the class loader for a thread I suggest to do the following.

In the main() function of your application create a thread and set the class loader of this thread. Start this thread.
In this thread the first thing is to load the first class with the new class loader and invoke the application with it.

This is called boot strapping, I think so.
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
dnoelppCommented:
Like this:

// A function in the thread. When this function
// gets called, the new classloader is already set.

// Loads the class app.BootStrapper with a method boot()
// and invokes it.
public void run() {
    try {
        Object bootStrap = Class.forName("app.BootStrapper");
        Method boot = bootStrap.getClass().getMethod("boot", null);
        boot.invoke(bootStrap, null);
    } catch (Exception exc) {
        exc.printStackTrace();
    }
}
0
 
Sasha_MapaCommented:
Create a wrapper main method around your real main method. The wrapper main method would belong to a different class, it would load the real main class using your custom classloader and then invoke its main method. This will cause your main class, and thus all the other classes, to be loaded with your custom classloader.

Sasha Maryanovsky.
0
 
dnoelppCommented:
Yes that's a simpler solution, you are right. Without the thread spawning stuff.
0
 
shternAuthor Commented:
Sasha,

could you please give me a short example, somehow I can't get it working.

Thank you.
0
 
dnoelppCommented:
// This is the wrapper class
package app;

public class Wrapper {
    public static void main(String[] args) {

        ClassLoader myClassLoader;
        // code here to define your custom class loader

        Thread.getCurrentThread().setContextClassLoader(myClassLoader);

        Application.main(args);
    }
}

*** ***

// This is your real main class
package app;

public class Application {
 
    // your stuff here

    static void main(String[] args) {
       // your stuff here
    }
}
0
 
Sasha_MapaCommented:
dnoelpp, that's not quite what I meant. Here it is:

import java.reflect.*;

public class Wrapper{

  public static void main(String [] args) throws Exception{
    ClassLoader loader = new MyCustomClassLoader();
    Class appClass = loader.loadClass(args[0],true);
    String [] realArgs = new String[args.length-1];
    System.arraycopy(args,1,realArgs,0,realArgs.length);
    Method mainMethod = appClass.getMethod("main",(String[]).class);
    mainMethod.invoke(null,new Object[]{args});
  }

}


public class Application{

  static{
    System.out.println("Class Application loaded with "+Application.class.getClassLoader()+" classloader");
  }

  public static void main(String [] args){
    System.out.println("Main invoked");
  }

}


You would then run the program with "java Wrapper Application <the real arguments here>"

Sasha Maryanovsky.
0
 
Sasha_MapaCommented:
Err, mainMethod should be invoked with realArgs, not args, sorry.

Sasha Maryanovsky.
0
 
dnoelppCommented:
Ah, that's sort of a generic wrapper utility... Good idea, this way you can wrap all applications that they use the new class loader.
0
 
shternAuthor Commented:
Sorry, people,

I've tried your both examples, and they seem not to work. By testing which ClassLoader loads the Application I become sun.misc.Launcher$AppClassLoader@6f241 as a result.
0
 
shternAuthor Commented:
Some ideas? It's really important for me!
0
 
shternAuthor Commented:
Yes, you're right. Thank you very much. The points are already yours.

Just one more question: have you maybe tried to replace a class with another one while class loading? This another one extends that class. Is it possible at all?
0
 
Sasha_MapaCommented:
Sorry, I'm not sure what you mean...

Sasha Maryanovsky.
0
 
shternAuthor Commented:
I have to "wrap" the objects of my app with the ones which extend their functionality in some way. That's, for each class a wrapper class will be generated, which extends this class and adds something. Then, these classes must be used instead of the old ones. But it may not be programmed in the app itself, it should work with each app.
0
 
dnoelppCommented:
That's an interesting idea. Please tell us more about it. What functionality is put to the classes?
0
 
Sasha_MapaCommented:
I think you should try adding methods to java.lang.Object in that case... If you want class specific information, you will need to modify the byte array you load for each class by adding methods to the class. To do that you need to learn the class file format, whose description is available at http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html

Sasha Maryanovsky.
0
 
shternAuthor Commented:
dnoelpp,
what I have to do is "wrap" each class of my app, so that this wrapper adds some attributes to the class and overwrites each method so that there will be some action done and the method of superclass called.

Sasha, we've already tested in some way the idea with Object class and virtual machine modifying. What we want is that it works on each virtual machine and with each program without having to write it in some special way. We run first some art of "postcompiler" which generates these "wrappers" and then run our app with the custom classloader, which should replace old classes with wrappers. But until now I couldn't get it working. The main problem now: I can replace the class in class loader, but then the constructor can't be found.
0
 
dnoelppCommented:
Did you try bcel (http://bcel.sourceforge.net/), the ByteCode Engineering Library? They offer the possibility to modify class files during run time.

Another pointer: Aspect oriented programming. This is an extension of Java which allows to crosscut all classes of an application with some functionality. (http://www.parc.xerox.com/csl/projects/aop/)

0
 
dnoelppCommented:
Please look at AspectJ on the AOP page, too.
0
 
Sasha_MapaCommented:
shtern, you need to do what I said my last comment - read it. Wrappers won't do it because you will be trying to load a class that the JVM didn't ask to load, this breaks the ClassLoader's contract.

Sasha Maryanovsky.
0
 
dnoelppCommented:
Sasha, in this case bcel will be of help, what do you think?
0
 
shternAuthor Commented:
dnoelpp, I've looked at bcel. OK, the problem is I have to work the idea with classloading over. I may not just say: OK, we take bcel instead. I have to say: I've tried this and this. And it's not possible because...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.