views:

80

answers:

2

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.

+6  A: 

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.

Reference:


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).

seanizer
(Just added more info to the OP) static blocks or abstract classes won't do. You understood right - this would be done per client-code interface.
Henrik Paul
I'm doing the registering thing currently (except i have no annotations yet, and they are registered in client-defined pairs) which works well. Thought to automatize this. But that package-scanning method seems pretty appealing (apart from the refactoring made harder). I'll take a look at that solution. Alas, no accepting here either, yet.
Henrik Paul
Relax, you just asked the question an hour ago, no need to accept anything just now. BTW: even if you do, you *can* un-accept an answer later.
seanizer
+2  A: 

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: http://stackoverflow.com/q/3801714/212952).
  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 JEE containers handle some spacific areas with specific classLoaders, etc.), but it's a kind of aproximation to what you are asking.

Tomas Narros
Thanks. I'll give this a shot. I won't accept this answer just yet, though.
Henrik Paul