Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is possible iterate over all classes inside a package with Reflection? [duplicate]

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
}
like image 859
Renato Dinhani Avatar asked Mar 27 '12 21:03

Renato Dinhani


3 Answers

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...
like image 197
maerics Avatar answered Oct 22 '22 11:10

maerics


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.

like image 29
Miserable Variable Avatar answered Oct 22 '22 11:10

Miserable Variable


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.

like image 1
ataylor Avatar answered Oct 22 '22 10:10

ataylor