List All Loaded Classes in the Java JVM Using Nashorn JavaScript
As I was working through an issue the other day, at one point I wanted to see what was loaded in the Java Virtual Machine (JVM). To make matters a bit more tricky, I had to accomplish this using Nashorn JavaScript. So after a bit of poking around, I found this in Java:
import java.lang.reflect.Field; import java.util.Iterator; import java.util.Vector; public class ListLoadedClasses { private static Field ClassLoader_classes_field = null; private static Iterator list(ClassLoader CL) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Class CL_class = CL.getClass(); while (CL_class != java.lang.ClassLoader.class) { CL_class = CL_class.getSuperclass(); } ClassLoader_classes_field = CL_class .getDeclaredField("classes"); ClassLoader_classes_field.setAccessible(true); Vector classes = (Vector) ClassLoader_classes_field.get(CL); return classes.iterator(); } public static void main(String args[]) throws Exception { ClassLoader myCL = Thread.currentThread().getContextClassLoader(); while (myCL != null) { System.out.println("ClassLoader: " + myCL); for (Iterator iter = list(myCL); iter.hasNext();) { System.out.println("\t" + iter.next()); } myCL = myCL.getParent(); } } }
So in the above snippet, you can see that we’re getting the ClassLoader objects from the head, and iterating over their respective loaded classes. All-in-all, pretty straight forward.
JavaScript, For the Win, again, again
But what if we didn’t have access to a Java environment? What if we were working in, say, a Nashorn JavaScript environment and wanted to do this same thing. We can accomplish that by porting the above code over to Nashorn, which looks like this:
var listLoadedClasses = function(doc){ var e = java.lang.Exception; var Class = java.lang.Class; var Thread = java.lang.Thread; var ClassLoader = java.lang.ClassLoader; var System = java.lang.System; var Iterator = java.util.Iterator; try{ var myCL = Thread.currentThread().getContextClassLoader(); var str = ""; while (myCL !== null) { str += " ClassLoader: " + myCL +" \n"; for (var iter = list(myCL); iter.hasNext();) { str += " \t" + iter.next() + " \n"; } myCL = myCL.getParent(); } logger.info(str); }catch(e){ } function list(CL){ var ex = java.lang.Exception; var Vector = java.util.Vector; var ClassLoader_classes_field = java.lang.reflect.Field; try{ var CL_class = CL.getClass(); while (CL_class != java.lang.ClassLoader.class) { CL_class = CL_class.getSuperclass(); } ClassLoader_classes_field = CL_class.getDeclaredField("classes"); ClassLoader_classes_field.setAccessible(true); var classes = ClassLoader_classes_field.get(CL); return classes.iterator(); }catch(ex){ } } return doc; }
So it looks a bit different, but the end result is exactly the same.
Ultimately, there is really nothing you can’t do with Nashorn, and that is what makes it so cool.