find all implementors of an interface?

Sometimes I wish I was still a Smalltalk programmer … :-/

Is it possible to find all the implementors of an interface? That is, all sublclasses - not instances. After a thorough run through of the Reflection API and the classes Class, ClassLoader, and Package I’m inclined to say this isn’t possible.

Can I inject my own classloader in somewhere? The desired functionality is this: You add your class to the classpath, and I know automatically at runtime.

Thanks!

edit - added that the goal is subclasses, not instances

It is only possible in the sense that you will need to scan every class and test if it implements the interface… This is one way of dealing with plugins for instance. But the search is limited to a specific folder or package. Maybe that is good enough for you.

That would be good enough for now, but I don’t see from where I can get a list of classes. ClassLoader and Package don’t offer lists of classes they know about, and Class only goes up the hierarchy.

I’m all ears if you know of a way to get a list of classes or can point out what I’ve missed.

If this is a one-off task, JavaDoc will tell you the heirarchy of your classes. If you want to do this at runtime, sorry!

[quote]Sometimes I wish I was still a Smalltalk programmer … :-/
[/quote]
Really? :stuck_out_tongue:

Replace the main system classloader. There’s several things that could be considered to be the “main system” classloader, but it’s fairly obvious which the important one is when you look at the ClassLoader class API docs.

There are several articles on the net (I recall at least one on the JDC) that explain fun tricks to do with classloaders, and interposing your own classloader(s). The API docs (just had a quick look) explain how you can do it using a system property, but there are other ways too (just make sure you load your classloader before you reference any classes, IIRC).

There are static analysis tools that will do this for a codebase. At ru-time yeah you need to implement your own sub-class of ClassLoader (I suggest sub of URLClassLoader actually) that wil let you peek at whats been loaded/cached.

Realize though that any analysis only gives you the answer for oen state. Since classes are loadable dynamically, and under certai ncondistions ar even unloadable (collectable really), there is no one answer that is gauranteed correct for the entire run of the program.

…but the classloader approach will give you an answer that is correct everytime you need it, AND contains the sum total “history” to date, too.

I see now that we’ve put the cart before the horse. I found some code to change the system Classloader, but then I realized that for the ClassLoader approach to work my codebase would have to already know the name of the subclass in order for it to be loaded.

Now I’m thinking that I should analyze java.class.path and run through all the directories and jars, force eveything to load, and use instanceof. Can’t wait to see how slow this is!

[quote]Really? :stuck_out_tongue:
[/quote]

OrderedCollection subs := MyClass allSubclasses.

Only sometimes :wink:

[quote]I see now that we’ve put the cart before the horse. I found some code to change the system Classloader, but then I realized that for the ClassLoader approach to work my codebase would have to already know the name of the subclass in order for it to be loaded.
[/quote]
You’ve lost me now; I have no idea why you would need to already know the name of each of the subclasses?. Perhaps you should explain what it is you’re trying to achieve, rather than just ask about one low-level feature you’re not sure about how/why to use (…in java; i.e. what you’re familiar with from other environments seems to be sufficiently dissimilar to “the java way” for this particular situation as to be non helpful…).

My goal is stated above.

[quote]The desired functionality is this: You add your class to the classpath, and I know automatically at runtime.
[/quote]
You asked:

[quote]I have no idea why you would need to already know the name of each of the subclasses?
[/quote]
Though earlier, you said:

[quote](just make sure you load your classloader before you reference any classes, IIRC).
[/quote]
If I don’t know the name of your class, I can’t reference it in my code. If I reference your class, I already know what type it is.

You want to scan the jars and directories on the classpath (or a subset of it) and then peek at the files ending with .class using your classloader.
In otherwords if they aren’t loaded yet - load them. Hopefully they don’t have to stay loaded… I haven’t actually done this before.

It sounds like you are trying to do what the Plugin code in JInput does, which is find all the installed implementors oif a given interface.

JInput does it the easy way. It uses a naming convention (*Plugin.class) to identify likely candidates, loads and instances them, and then uses reflection to make sure they really are plug-ins (implementors of the Plugin interface,)

This code is all available as part of JUtils.

If you dont want to use a naming convention and instance though you are going to have to dig into the VM spec and figure out how to read the inheritance data out of a raw .class file.

Nasty.

[quote]My goal is stated above.
You asked:
Though earlier, you said:

If I don’t know the name of your class, I can’t reference it in my code. If I reference your class, I already know what type it is.
[/quote]
Sorry, I wrongly assumed the classes would get referenced by someone else’s code. You can reference one class belonging to someone else and end up loading many classes, none of which you have any idea existed (this is all done automatically).

If your use-case is “people give me class files; I load them without any further involvement of the author(s)”, then I now understand OK. As Jeff has pointed out, the standard approach is to have a directory where the classes will be found and/or use a filename-prefix (the file-naming scheme is not mandatory to make this succeed).

Unfortunately, the design (flawed, IMHO, although most people disagree :)) of java classloaders means that “.isInstance(…)” will always return false for a class loaded by a different classloader. So, when you’re trying to check which are instances and which aren’t, the object you use for comparison must be created with the same classloader as is loading these external classes; this sometimes bites people who wonder why none of the imported classes seem to be accepted by their classloader…

A naming convention sounds like a great compromise! Then I could scan all directories and jar files, but only load and check instanceof with the ideal subset. First, I think I’ll check out JUtils though … :slight_smile:

Thanks everyone!

blahblahblahh: Good point. One example of being bitten by a ClassLoader is trying to use XmlEncoder on an externally loaded class.

One way around that can be found here: http://forum.java.sun.com/thread.jsp?thread=344817&forum=39&message=1423943

This “flaw” is vital to the operation of many more sophisticated Java systems such as RMI and Jini. Without name-space separation it becomes virtually impossible to do either code-mobility or code-container infra-structures.

The key is to understand that a ClassLoader does more then load classes. It is the public face of a class namespace and is well-isolated from other such namespaces. Class “foo” loaded nby classloader 1 IS a different class then class “foo” loaded by classloader 2 even if they are loaded from the same classfile.

This allows such things as static variables to operate as expected in the face of multiple apps running in the same VM and based on the same source.

[quote] So, when you’re trying to check which are instances and which aren’t, the object you use for comparison must be created with the same classloader as is loading these external classes;
[/quote]
Actually this isn’t exactly true. Look at JUtils. The trick here is that class loaders chain and they defer to their parents first, so if a parent has loaded a class that is the class you will get. The simplest way to handle this is to have the Interface you are checking for either in the bootclasspath or the classpath. These loaders by definition MUST be at the beginning of a loader chain.

Doesn’t mean it has to be mandatory; it could be optional (theoretically - I’m not claiming it would have been easy to integrate with the other requirements of the original spec).

Given how many java programmers don’t use RMI nor Jini (although probably many more should use the latter, and many fewer should use the former), but do use isInstance(), I think it’s fair enough to say this part of the design could have been done better. I’m not claiming the current behaviour isn’t valuable, just that IMHO it would be more intuitive NOT to be the default.

I agree entirely, and this is a large part of why I consider the current design “flawed”. Since it does “much more than load classes” it should NOT be named “ClassLoader”.

IMHO, a better API design would start from the concept of splitting the namespace-management, the class-loading, and the class-management (i.e. for stuff like type comparisons) into two, or possibly three, separate classes / sets of classes. I suspect that “hierarchy” namespace-management and “class” namespace management are two separate things, hence the need for three rather than two classes. The former deals with sandboxing, and separating differently-sourced class hierarchies; the latter is sort-of aspect-oriented, and cuts across sandboxes. Using both in conjunction, abstracted into separate classes, could give you all the benefits of both.

This could lead to a worse design, of course; as a systems architect, I don’t feel that’s a reason not to try :). I live in hope that the ClassLoader’s etc will get a “refresh” in some future release of java…

Yes, sorry, I wasn’t as precise as I could have been :(. The important point, of course, is the gotcha, and there’s more than one way to skin the cat :).

I’ll grant you that ClassLoaders and all they do isn’t immediately obvious or intuitive at first. “ClassSpace” might have been a better name.

But I can’t think of another way to accomplish what they accomplish is cleanly and uncomplicatedly as they do.

And the things they make possible IMO are well worth the learning curve.

shrug

'srite, if you need to use classloaders you’re probably doing something weird and difficult anyway.

Cas :slight_smile: