12

I have a String with some value. I want to iterate over all classes in a package calling a specific method, and if the value returned by the method is equals the value in my String, create an object of that class.

I want do this in a dynamic way, so if I add a class in this package, it will automatically be in the iteration.

Is possible do this? If not, there is a way to do what I want?


I was expecting something like.

for(Class clazz: SomeClass.listClasses("org.package")){
     //code here
}
Renato Dinhani
  • 35,057
  • 55
  • 139
  • 199
  • What does "add a class in this package mean"? How does it get in the classpath of the java process? – Miserable Variable Mar 27 '12 at 21:47
  • @Jeffrey I was reading about Reflection and I think this is the only way, but I don't know nothing about Reflection. I tried a "normal way" adding a verification for each class I have in that package, but I don't want this way because is not expansible. – Renato Dinhani Mar 27 '12 at 21:47
  • @MiserableVariable In development time, I add some new class in the package (all classes extends an abstract class called Document). – Renato Dinhani Mar 27 '12 at 21:49
  • @RenatoDinhaniConceição Reflection is a way to go with this, but have you tried anything with reflection? There are pretty good [tutorials](http://docs.oracle.com/javase/tutorial/reflect/) out there... – Jeffrey Mar 27 '12 at 21:49
  • 1
    I don't see how this is a job for reflection. More of a file system/class loader job. – Hot Licks Mar 27 '12 at 21:59

3 Answers3

8

No, this is not possible in a totally reliable way; however, it may be practical to implement in many cases.

Due to the flexibility of Java class loaders, the classes defined under a particular package may not be known at runtime (e.g. consider a special classloader which defines classes on-the-fly, perhaps by loading them from the network, or compiling them ad-hoc). As such, there is no standard Java API which allows you to list the classes in a package.

Practically speaking, however, you could do some tricks by searching the classpath for all class and JAR files, building a collection of fully-qualified class names, and searching them as desired. This strategy would work fine if you are sure that no active classloader will behave as described in the previous paragraph. For example (Java pseudocode):

Map<String, Set<String>> classesInPackage = new HashMap();
for (String entry : eachClasspathEntry()) {
  if (isClassFile(entry)) {
    String packageName = getPackageName(entry);
    if (!classesInPackage.containsKey(packageName)) {
      classesInPackage.put(packageName, new HashSet<String>());
    }
    classesInPackage.get(packageName).add(getClassName(entry));
  } else if (isJarOrZipFile(entry)) {
    // Do the same for each JAR/ZIP file entry...
  }
}
classesInPackage.get("com.foo.bar"); // => Set<String> of each class...
maerics
  • 151,642
  • 46
  • 269
  • 291
  • But a custom classloader could, at least in theory. – Miserable Variable Mar 27 '12 at 21:48
  • @MiserableVariable: imagine I wrote a custom classloader which implements the `defineClass(String)` method by returning the bytecode for a class which defines an empty class by the given class name. This is a totally valid classloader and there is no (practical) way to list every class that it could define. – maerics Mar 27 '12 at 21:52
  • Yes, in general the problem is not solvable. But it is different for specific narrow situation -- I could want to check all .class files in a folder names `plugins` and create an instance on every class that has a `register` method. – Miserable Variable Mar 27 '12 at 22:08
2

I can think of two ways to solve what I think your problem is, though neither truly iterate over all classes in a package.

One is to create a separate file that lists classes on which that specific method should be called. This is quite easy to implement. You might have some work creating the file, but that could be automated.

The second option is to look for .class files at some well known place -- say a single folder or a set of folders -- and guess what the class name would be and load it. If this is a simple development process, the classfiles from a single package are probably in a single directory.

Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
1

Yes, but not as a general case solution. You'll have to package up your code and invoke the JVM in specific way. Specifically, you'll need to create an Instrumentation agent, and call java.lang.instrument.Instrumentation.getAllLoadedClasses().

The package documentation for java.lang.instrument has lots of details on how to create and instantiate an agent.

ataylor
  • 64,891
  • 24
  • 161
  • 189