Say I have this code that uses some input (e.g. a URL path) to determine which method to run, via reflection:
// init
map.put("/users/*", "viewUser");
map.put("/users", "userIndex");
// later
String methodName = map.get(path);
Method m = Handler.class.getMethod(methodName, ...);
m.invoke(handler, ...);
This uses reflection so the performance can be improved. It could be done like this:
// init
map.put("/users/*", new Runnable() { public void run() { handler.viewUser(); } });
map.put("/users", new Runnable() { public void run() { handler.userIndex(); } });
// later
Runnable action = map.get(path);
action.run();
But manually creating all those Runnable
s like that has its own issues.
I'm wondering, can I generate them at runtime? So I'd have an input map as in the first example, and would dynamically create the map of the second example.
Sure, generating it is just a matter of building a string, but what about compiling and loading it?
Note: I know the performance increase is so little it's a perfect example of premature optimization. This is therefore an academic question, I'm interested in runtime generation and compilation of code.
The only ways to generate code dynamically are to either generate source code and compile it or to generate byte code and load it at runtime. There are templating solutiions out there for the former, and bytecode manipulation libraries for the latter. Without a real case and some profiling I don't think you can really say which will be better. From a maintenance point of view I think reflection is the best option when available.
I think you can achieve this with the code found here. It is some time ago I tried this, and I'm not sure anymore where I found the code I was using, but it seems that this is the same.
Basically, you use the 1.6 Compiler API, but use an "untraditional" way to find source files and write class files: The Compiler
takes an Iterable<JavaFileObject>
, where you plug in your memory-backed implementation, and a JavaFileManager
that handles writing class files, where you hold the binary compiler output in memory.
Now that your code was compiled, you only need a custom ClassLoader
that can read from your in-memory byte code and load the class with the right FQCN etc.
And, luckily, all that seems to be ready ;)
Actually, the reflection engine will generate similar invocation stubs internally, if you invoke the same methods over and over again. (Just use the same Method
objects instead of recreating them again and again.)
Well, you could write code to a .java file, compile it with javac (how to do that) and load it into Java using Reflection.
But maybe, as a trade-off, you could also fetch the Method objects during initialization - so you would just have to call the invoke() method for every request.