Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I run my code upon class load?

Is there a feasible way to get my own code run whenever any class is loaded in Java, without forcing the user explicitly and manually loading all classes with a custom classloader?

Without going too much into the details, whenever a class implementing a certain interface read its annotation that links it with another class, and give the pair to a third class.

Edit: Heck, I'll go to details: I'm doing an event handling library. What I'm doing is having the client code do their own Listener / Event pairs, which need to be registered with my library as a pair. (hm, that wasn't that long after all).

Further Edit: Currently the client code needs to register the pair of classes/interfaces manually, which works pretty well. My intent is to automate this away, and I thought that linking the two classes with annotations would help. Next, I want to get rid of the client code needing to keeping the list of registrations up to date always.

PS: The static block won't do, since my interface is bundled into a library, and the client code will create further interfaces. Thus, abstract classes won't do either, since it must be an interface.

like image 486
Henrik Paul Avatar asked Oct 26 '10 08:10

Henrik Paul


2 Answers

If you want to base the behavior on an interface, you could use a static initializer in that interface.

public interface Foo{

    static{
        // do initializing here
    }

}

I'm not saying it's good practice, but it will definitely initialize the first time one of the implementing classes is loaded.

Update: static blocks in interfaces are illegal. Use abstract classes instead!

Reference:

  • Initializers (Sun Java Tutorial)

But if I understand you right, you want the initialization to happen once per implementing class. That will be tricky. You definitely can't do that with an interface based solution. You could do it with an abstract base class that has a dynamic initializer (or constructor), that checks whether the requested mapping already exists and adds it if it doesn't, but doing such things in constructors is quite a hack.

I'd say you cleanest options are either to generate Code at build time (through annotation processing with apt or through bytecode analysis with a tool like asm) or to use an agent at class load time to dynamically create the mapping.


Ah, more input. Very good. So clients use your library and provide mappings based on annotations. Then I'd say your library should provide an initializer method, where client code can register classes. Something like this:

YourLibrary.getInstance().registerMappedClasses(
    CustomClass1.class,
    CustomClass2.class,
    CustomClass3.class,
    CustomClass4.class
)

Or, even better, a package scanning mechanism (example code to implement this can be found at this question):

YourLibrary.getInstance().registerMappedClassesFromPackages(
    "com.mycompany.myclientcode.abc",
    "com.mycompany.myclientcode.def"
)

Anyway, there is basically no way to avoid having your clients do that kind of work, because you can't control their build process nor their classloader for them (but you could of course provide guides for classloader or build configuration).

like image 154
Sean Patrick Floyd Avatar answered Oct 16 '22 02:10

Sean Patrick Floyd


If you want some piece of code to be run on any class loading, you should:

  1. overwrite the ClassLoader, adding your own custom code at the loadClass methods (don't forget forwarding to the parent ClassLoader after or before your custom code).
  2. Define this custom ClassLoader as the default for your system (here you got how to do it: How to set my custom class loader to be the default?).
  3. Run and check it.

Depending on what kind of environment you are, there are chances that not all the classes be loaded trouugh your custom ClassLoader (some utility packages use their own CL, some Java EE containers handle some spacific areas with specific classLoaders, etc.), but it's a kind of aproximation to what you are asking.

like image 36
Tomas Narros Avatar answered Oct 16 '22 02:10

Tomas Narros