Java Forum / General / March 2007
Reflection: Instantiate All Classes in a Package?
Jason Cavett - 23 Mar 2007 18:43 GMT I was wondering...
Is it possible, by using Java reflection, to instantiate all classes existing in a package without knowing the names of those classes. I'm envisioning something like this (pseudocode):
Start my class Class goes to package x Package x contanis all the classes I need to instantiate Using a (loop/something?) I loop through all the classes and instantiate each one
To clarify what I'm trying to do, I am creatnig an error checking application that relies on a series of rules that groups of developers will code in Java (yeah, I realize I could have it in XML or something that makes more sense, but I am the third or fourth developer to work on this project). All the (compiled) classes are placed in a specific package, but I never will know exactly which classes are there. I was hoping for some way to discover and initialize them at runtime. (They all implement the same interface, so that part is easy.)
Is this even possible? Is there a better solution? Thanks for any clarification.
Joshua Cranmer - 23 Mar 2007 22:23 GMT > I was wondering... > [quoted text clipped - 19 lines] > Is this even possible? Is there a better solution? Thanks for any > clarification. Using Java reflection, the answer is NO. For more information, check the message thread "Getting a list of classes in a package"; there is a nice long discussion on class/package/reflection.
P.S. it generally helps to search recent posts on Usenet before asking a question.
Jason Cavett - 23 Mar 2007 22:35 GMT > > I was wondering... > [quoted text clipped - 28 lines] > > - Show quoted text - My mistake. Thanks for pointing me to that thread.
Oliver Wong - 23 Mar 2007 23:26 GMT >> I was wondering... >> >> Is it possible, by using Java reflection, to instantiate all classes >> existing in a package without knowing the names of those classes. [...]
> Using Java reflection, the answer is NO. For more information, check the > message thread "Getting a list of classes in a package"; there is a nice > long discussion on class/package/reflection. Actually, the answer turned out to be "yes" (though I can't find the thread where we concluded this), but you would probably never want to instantiate all the classes existing in a package anyway, because there are an infinite number of such classes.
OP, instead of instantiating all classes in a package, how about instantiating all classes located within a specific directory on the local harddrive?
- Oliver
Oliver Wong - 23 Mar 2007 23:28 GMT >>> I was wondering... >>> [quoted text clipped - 8 lines] > Actually, the answer turned out to be "yes" (though I can't find the > thread where we concluded this), Found it: http://groups.google.ca/group/comp.lang.java.programmer/browse_frm/thread/4017ee 8e8edf3690/e7ca74ec29d74031
- Oliver
Mark Rafn - 24 Mar 2007 00:12 GMT >>> Is it possible, by using Java reflection, to instantiate all classes >>> existing in a package without knowing the names of those classes. >[...] >> Using Java reflection, the answer is NO. For more information, check the >> message thread "Getting a list of classes in a package"; there is a nice >> long discussion on class/package/reflection.
> Actually, the answer turned out to be "yes" (though I can't find the >thread where we concluded this) Um, no. The answer turned out to be "No, but if you define your problem more clearly, we can suggest alternatatives that are possible, like enumerating classes in certain known locations and instantiating those that implement a given interface."
> OP, instead of instantiating all classes in a package, how about >instantiating all classes located within a specific directory on the local >harddrive? Indeed! -- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Chris Uppal - 24 Mar 2007 03:08 GMT > > Actually, the answer turned out to be "yes" (though I can't find the > > thread where we concluded this) > > Um, no. The answer turned out to be "No" No, /that/ conversation concluded -- correctly -- that the answer is "yes". It is trivial, albeit a little slow, to probe a classloader for all the possible potential names of classes -- see the link in Oliver's follow-up post for details and further speculation.
-- chris
Joshua Cranmer - 24 Mar 2007 14:14 GMT >>> Actually, the answer turned out to be "yes" (though I can't find the >>> thread where we concluded this) [quoted text clipped - 6 lines] > > -- chris When I said that the answer is "no", I meant that purely using reflection, i.e. stock java.lang.reflect.*/ClassLoader, this could not be done. Through writing custom ClassLoaders or (my preference), parsing the class path/bootstrap path/extensions directory, one can obtain the needed classes.
The OP originally asked for the answer using /reflection/ -- he was more or less asking if the answer could there was a method along the lines of getAllClasses(String package).
In summary: Yes, one can get a list of classes in a certain package through various means, but no, it cannot be done through /pure/ reflection. Happy now?
Chris Uppal - 25 Mar 2007 11:19 GMT > In summary: Yes, one can get a list of classes in a certain package > through various means, but no, it cannot be done through /pure/ > reflection. Happy now? No, It can be done through nothing more than pure reflection (using only ClassLoader.findClass() as exposed via Class.forName(String, ClassLoader)) Read the thread that Olver referenced. I was going to post code but, what with the difficulties of handling Unicode in Java, and the absence of standard combinatorial generators in the library, it's a bit more effort to do properly than it's worth.
-- chris
Joshua Cranmer - 25 Mar 2007 21:43 GMT >> In summary: Yes, one can get a list of classes in a certain package >> through various means, but no, it cannot be done through /pure/ [quoted text clipped - 8 lines] > > -- chris Should I append 'feasibly' to my list? To use ClassLoader.findClass() would require checking more than 64K^64K ~ 10^1M combinations to find every class and probably on the order of 10^22 for more reasonable assumptions (100 possible characters, 20-character lengths). It would be much more efficient to open the Jar-files, find the package directory, and load the classes.
Chris Uppal - 26 Mar 2007 09:36 GMT > > > In summary: Yes, one can get a list of classes in a certain package > > > through various means, but no, it cannot be done through /pure/ [quoted text clipped - 3 lines] > > only ClassLoader.findClass() as exposed via Class.forName(String, > > ClassLoader))
> Should I append 'feasibly' to my list? Please feel free ;-)
> To use ClassLoader.findClass() > would require checking more than 64K^64K ~ 10^1M combinations to find > every class I did warn that the technique was a little slow...
-- chris
Oliver Wong - 26 Mar 2007 18:52 GMT > It would be much more efficient to open the Jar-files, find the package > directory, and load the classes. It sounds like you haven't read the thread that I linked to. I don't know why you might want to avoid reading that thread, but this post will mainly be a regurgitation of what was written in that thread, since I'm assuming you haven't read it. Your solution does not solve the problem that the OP originally *stated* (though it probably solves the problem that the OP originally *intended*).
There is not a one-to-one correspondence between packages and directories on computers. So for example, if you were using the "scan directories" approach and were interested in all classes in package "foo", it is not sufficient to merely scan directories named "foo" on your computer. You'd also have to scan directories named "foo" on my computer, and on computers which I may have thrown into black holes. (This is where we initially, and incorrectly, concluded that it was completely impossible).
Later, it was decided that two classes are the same if they have the same bytecode, even if they reside on different computers. E.g. if I write a class on a computer, and then throw that computer into a black hole, and you also write a class, and that class has the same bytecode as the class that I wrote, then they are by definition the same class. (This is philosophically comparable to the idea that if I write "3" on a piece of paper, and you write "3" on a different piece of paper, we are both wrote down the same number, the number itself being an abstract concept which is not directly associated to either of our pieces of paper.)
So one could write an iterator which returns every possible sequence bytecode, much like you can iterate through every possible integer, and turn the bytecode sequence into a Java class. Some of these bytecode sequences might declare names that conflict with each other (e.g. there's more than one class in package "foo" with the name "Bar", but they are distinct classes, having different bytecode), and so you'd need to separate these classes into different classloaders.
Note that classes may "exist" in the "foo" package, even if they are not stored on any local harddrive. This is philosophically comparable to the idea that numbers "exists", conceptually, even if no one has ever bothered to write them down yet.
This is also why I suspect that the OP doesn't really want to load all classes from a given package, but instead, wants to load all classes located in a given local directory (perhaps with certain additional conditions).
- Oliver
Mark Thornton - 26 Mar 2007 20:00 GMT > This is also why I suspect that the OP doesn't really want to load all > classes from a given package, but instead, wants to load all classes > located in a given local directory (perhaps with certain additional > conditions). In which case you shouldn't add such a method to ClassLoader (because not all class loaders can reasonably implement the method), but rather to some sub class of ClassLoader (or an interface which ClassLoaders might optionally implement). Alternatively if you do put the method on ClassLoader you have to document that implementation is optional or might only return classes that had already been loaded. Perhaps add another method which returned a value specifying the degree of enumeration that was possible.
Mark Thornton
Jason Cavett - 26 Mar 2007 17:55 GMT > >>> Is it possible, by using Java reflection, to instantiate all classes > >>> existing in a package without knowing the names of those classes. [quoted text clipped - 17 lines] > -- > Mark Rafn d...@dagon.net <http://www.dagon.net/>
> Um, no. The answer turned out to be "No, but if you define your problem more > clearly, we can suggest alternatatives that are possible, like enumerating > classes in certain known locations and instantiating those that implement a > given interface." Sorry...I've been away for a bit.
Each class will implement the same interface. Each class will exist in the same package.
I want a way (without knowing the actual names of the classes in package X) to instantiate those classes. This way, developers can continuously add new rules (errors and warnings) and the JAR can easily be redistributed just by packaging it up and pushing it out to the main system.
Any additional suggestions on how to do this?
P.S. Another alternative I thought of is have some sort of configuration file where a developer adds the name of his class to the config file every time he adds a new class. The major problem with this is, 1, it will have to be read every time the error checker is run and, 2, it is prone to error if a developer types the class name incorrectly.
Thanks
Andrew Thompson - 26 Mar 2007 18:10 GMT ..
> I want a way (without knowing the actual names of the classes in > package X) to instantiate those classes. This way, developers can > continuously add new rules (errors and warnings) and the JAR can > easily be redistributed just by packaging it up and pushing it out to > the main system. 1) Menu item (button or D'n'D funtionality) to 'add new rules archive'. Once the app. knows of the jar.. 2) Copy the jar to a known location, 3) Iterate the ZipEntry's looking for classes in the right package, 4) do the biz to determine if they implement the interface, then.. 5) add them to a single list of class names that can be serialised for later loading.
(That's how I would approach it, failing better suggestions from the design gurus.)
Andrew T.
Mark Rafn - 26 Mar 2007 21:50 GMT >> > OP, instead of instantiating all classes in a package, how about >> >instantiating all classes located within a specific directory on the local >> >harddrive?
>Each class will implement the same interface. >Each class will exist in the same package. As stated, it's impossible. s/package/searchable location/ and you're golden.
>I want a way (without knowing the actual names of the classes in >package X) to instantiate those classes. This way, developers can >continuously add new rules (errors and warnings) and the JAR can >easily be redistributed just by packaging it up and pushing it out to >the main system. Great. A jar is a searchable location. It's nearly trivial to list all class files in a given subdirectory of a jar, and you don't even need reflection to access them. Use the java.util.jar.JarFile#entries method to list files in the jar, translate them to classnames, and call Class.forName(className).isAssignableTo(yourInterface) to see if it's the right interface.
>Any additional suggestions on how to do this? The above is very easy to write.
>P.S. Another alternative I thought of is have some sort of >configuration file where a developer adds the name of his class to the >config file every time he adds a new class. The major problem with >this is, 1, it will have to be read every time the error checker is >run and, 2, it is prone to error if a developer types the class name >incorrectly. The config file will be faster than scanning the jar, and is a much more direct reflection of developer intent than trying to discover things by magic. It also allows the implementation to be in a different jar (or non-jar classpath location) and still be found by your app.
I'd HIGHLY recommend using the config file.
-- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Daniel Pitts - 26 Mar 2007 22:03 GMT > >> > OP, instead of instantiating all classes in a package, how about > >> >instantiating all classes located within a specific directory on the local [quoted text clipped - 38 lines] > -- > Mark Rafn d...@dagon.net <http://www.dagon.net/> Indeed. This is called Inversion of Control, and is a great boon to complex, extensible designs. Spring Framework does this quite well, with a intuitive XML configuration.
Jason Cavett - 26 Mar 2007 23:07 GMT On Mar 26, 5:03 pm, "Daniel Pitts" <googlegrou...@coloraura.com> wrote:
> > >> > OP, instead of instantiating all classes in a package, how about > > >> >instantiating all classes located within a specific directory on the local [quoted text clipped - 45 lines] > > - Show quoted text - Okay, thank you both, Mark and Daniel (and others). I guess I always got the impression through schooling/reading/whatever that a config file in this type of situation would *not* be a good thing (not even sure why I thought that). Glad to hear otherwise - especailly because it seems like such a good and simple solution.
Thanks again.
Wojtek - 26 Mar 2007 20:20 GMT Jason Cavett wrote :
> They all implement the same interface, so that part is easy. Even if they implement the same interface does not guarantee that they have a constructor which you can easily use. If the class does not have a parameter-less constructor, then you need to do some creative work to find all the primitives/classes which the available constructors do use.
And of course if those class's constructors need parameters....
 Signature Wojtek :-)
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|