Is there anyway to find all the class names which are extending a particular class by using classloader information?
More Detailed Explanation
I have a jar file which has 3 classes X (extends A), Y (extends A) and Z (extends B). I have put this jar file into the classpath and start the JVM (calling main method of some class). Now from this main method is there any way to find the classes which are sub classes of A? i.e. classes X and Y as they are extending the class A.
Unfortunately there's no easy way to do it. The JVM has no information about a particular class until it gets loaded by a classloader. But to have the classloader actually load the class, you must know the name of the class. Chicken and egg problem.
However, there is some other, but a bit more complicated way.
To determine which .jar files are on the classpath when running your application, you can call the System.getProperty("java.class.path") then split the classpath entries along the File.separatorChar characters. Classpath entries may be numerous, consider filtering them somehow (limiting only to a specific directory, leaving out standard entries like rt.jar, etc.)
If you know which .jar file contains your classes of interest, you can open it with an instance of the class JarFile. Then you can iterate over all entries (eg. .class files) and from their internal path in the JAR file you are able to construct their fully qualified class name.
With the classname in your hand, you can call Class.forName() to load the class, and the you can use reflection to get the superclasses of each class to find out whether it extends your particular class or not.
Note that this method is quite resource consuming, you make the JVM to actually load all the classes from a .jar file (or multiple .jar files), even if you won't use them later. This wastes a fair amount af memory (PermGen space).
There are some low-level libraries that manipulate Java bytecode and class files (see BCEL or ASM). Using them you will be able to determine the superclass for a class without actually (class)loading it, thus this way is more faster and uses less memory.
Your question resembles the way JavaEE application servers work when deploying a web application. To find out which classes to load and initialize as for example HTTP servlets they must examine all classes in the web archive looking for a specific Java annotation or superclass. However they are at least know which .war file to scan. Apache Tomcat for example uses BCEL instead of Java classloading mechanism.
If you're designing some sort of dynamic classloading mechanism for your application, then consider other design options to narrow down the numbers of classes your loader must scan to find the proper class to load: Telling the exact name of the .jar file instead of putting it on the classpath, using some meta information in the JAR (you can use the aforementioned JarFile to read entries from the META-INF/manifest.mf file) to specify which classes to look for, etc.
just fore the sake of completeness
http://code.google.com/p/reflections/
others where mentioned in the linked post
Related
I have a jar file and I can list all classes in the jar. The classes in the jar can be public, protected or package scope. I wonder if it is possible to tell the scope and only list the public classes?
You can do so, and I can think of more than just one way how to do it, here are two:
You can use a bytecode manipulation tool to read the .class files and get the modifier. The downside is that you need an extra library for that. The upside is that this way would be quite safe, as you don't need to load the class into the VM, just into memory, so no code is executed, and if the .jar classes depend on classes which are unavailable, this way would still work.
You can use a ClassLoader with this .jar and load each of the classes, then inspect it using Reflection. The upside is that you do not need any third party libraries for this. The downside is that in order to inspect the classes, they need to be loaded by the ClassLoader, which means the code of these classes (static initializers) will be executed. If this is untrusted third party code, you will want to install a SecurityManager first to sandbox these classes. The other downside is that if these classes depend on other classes that are not available (for example by extending such unavailable classes), this approach would fail.
You can use the javap tool to inspect the classes.
If you are already listing the classes in the jar, you can use the Reflection interface to get the Class objects for those classes by name (String), and then use the Class interface to determine the properties of the class, for example isPublic, isFinal, or isStatic.
A quick search reveals:
http://tutorials.jenkov.com/java-reflection/classes.html#modifiers
I apologize in advance if the answer to this question is a simple one. It seems I don't have enough knowledge about classloading in Java.
Say I have a file called "properties" in my application. My application uses an external JAR and inside that JAR, there's also a file called "properties".
Question:
If the external JAR file attempts to open that file with getClass().getClassLoader().getResourceAsStream("properties"), why doesn't it load the one from my application. Not that I want it to, but wouldn't the ClassLoader in this case be the one that loaded my application? I thought that method would use the absolute path for finding the resource. Do classes in external JARs get loaded with a different classloader?
The class loading mechanism is the same for classes and resources (but the bytes found are treated differently).
See http://docs.oracle.com/javase/tutorial/ext/basics/load.html for the official explanation.
It is the first class loader actually asked which has the resource that wins. If the class loader does not have its resource, try again with the parent.
(Note that for web applications - WAR files - this is deliberately slightly different about which one is asked first).
ThClassLoader#getResourceAsStream(String) calls getResource(String) and this as getResource() on the parent. If this does not find anything, then it will ask the classloaders findResource(String).
It depends on this implementation what it does return, in case of the URLClassLoader this will be URLClassPath.findResource() which steps through all loaders (one loader for each search path entry) and returns the first find.
In a normal application your JARs as well as all libraries are loaded by the same (Application) class loader. In case of the Sun launcher this is sun.misc.Launcher$AppClassLoader which extends URLClassLoader. It puts all JAR and classes from the classpath in the search list.
It is a good idea to make resources either unique (putting them in your packages) or retrieve all resources and pick the right one (or all). The later is for example used by the ServiceLoader when it finds all implementations for a given service.
No, it loads the first found in that class' classloader. If you want to open a file using an absolute path, you open an InputStream pointing at the file.
Classes in external JAR might be loaded using different classloaders (e.g. in a Java EE container) but then classloaders need to be chained in order for you to see them.
In general, how can I write programs to accommodate modding or plugins? Is every method wrapped with other behaviors? All my searching has led to are resources for writing plugins and mods themselves; I can't find anything on writing the systems. With regards to java, how do I expose internal portions of the logic to other systems without using reflection?
One way to do this is by creating your own ClassLoader that can load classes from a specified location that is not on the system classpath. (If it is on the system classpath, the system ClassLoader will find the classes first and you won't be able to unload them.) Creating instances requires a bit of reflection, but once they're created you can treat them just like any other instances.
This works because although only the custom ClassLoader knows about the actual class of those instances, it gets its definition of their superclass (your plugin class or interface) from the system ClassLoader. Therefore, other classes loaded by the system ClassLoader (i.e., the rest of your program) can reference those dynamically created instances by their superclass.
I've used Brian's Clapper's utility library to find classes that extend my plugin class.
Web applications for Tomcat are wrapped into a .war file and thrown into Tomcat. The application can use classes inside the war file and contained jar files. This separates the runtime-classes of Tomcat from the application classes.
When using storm (see storm-project.net), there is no similar segregation. Rather the recommended way requires to create a "fat jar", denoting a jar containing all the necessary class files after unwrapping them from their own individual jars. For simple situations this works, but the resulting fat jar must have all the META-INF/* files from all merged jars correctly merged, which does not work semi-automatically.
I would not be shy to write my own class loader which simulates something like a war-file. Except I have no clue how to intercept the default class loader that loads all the classes I deploy.
My theory is that one of the classes of my applications is loaded first by the default class loader. Presumably in its static-section I would cast the magic class loader spell such that all dependent classes will then be loaded by my own class loader, which would now how to get the necessary classes from whatever I deem suitable.
Any hints towards the general problems described as well as the specific magic needed are appreciated.
Intercepting the classloader: The default classloader is the one which loaded the class that is currently executing. So if you use a separate classloader to bring in the WAR's entry point, every class reference from it or its (run-time/creation) descendents will default to going through that classloader. That classloader can then decide what it should refer back to a higher-level classloader and what it should reload using its own resolution rules -- the simple rule "only ask the parent for things I don't have available in this plug-in", also known as "parent last", is often sufficient.
Is it possible to get a collection of public interfaces and classes in a given package using reflection?
Question is for Java 1.6
Why:
I have a package where some classes are annotated. I want to collect them automcatically for documenting
No, not possible, at least in general. That's because the classloader mechanism is too flexible to permit it: classes can be loaded via network or generated on the fly, and the only operation is "ask the classloader for a class with fully qualified name X, and it will either return class X or throw an exception. You could easily implement a classloader that returns an class for any name in any package, i.e. an infinite number of classes.
For the specific case of loading classes from a directory or JAR file via an URLClassLoader, it's possible to look at the contents of said directory or JAR file.
Do you really have to generate the documentation at runtime? The normal way to use the annotation processing tool (APT): http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/guide/apt/GettingStarted.html