rocker
rocker copied to clipboard
Compilation and Template class loading at Runtime
Is there a chance we can make Rocker runtime API to compile templates on the fly and load the compiled classes as BindableRockerModel
?
The api should be similar to
Rocker.compileAndLoad(name, template)
name
should be the name of the template and template
can be loaded from filesystem
, classloader
or as a String
Such a feature exists in a similar Java Template Engine called Rythm
I suppose that the JVM Metaspace will be affected for each class reloading but besides that is there a reason why this is a bad idea?
+1
Only risk is the usual JVM + class reloading issues that many other apps & platforms have as well. Obviously also some small performance drawbacks to reflection-based property settings, etc., but those are minimal compared to the ease of use.
Everything should already exist for this to work, I just have never tried it in production or documented it how you'd package it up. But the hot reloading feature of Rocker already lets this work in development, no reason it can't be used in production.
You'd need to include rocker-compiler
and rocker-runtime
in your app. Its critical to load templates using strings for views using com.fizzed.rocker.Rocker.template() method and then dynamically binding values before you render it. The other caveat (and maybe code to polish up this use case), would be supplying Rocker and RockerReloadingBootstrap with enough info to make sure it knows where to find templates. During development, the maven plugin drops in a properties file to your classpath (classes build dir) that includes that information, but in production you'd probably want a different solution (maybe).
Would love your help documenting / submitting PRs for polishing this use case up since I think its a common question.
This is perfect then. I was looking at rocker-compiler and the rocker-maven-plugin and I saw it only generates the Java source code clases. Then I thought I could use the Java Runtime Compiler from Chronicle to compile at runtime and load the templates as instances of RockerTemplate
.
Now that you mention that rocker-runtime can do that on it's own I'll dig more in the code and try to submit a PR in the coming days.
In development mode it makes sense to asume that rocker-runtime will deal with templates available in the classpath via File. It asumes the compiler plugin is present and was correctly hooked to the compiling process.
However, to enable on-the-flight compilation and reloading for production usage it makes sense to do necessary refactors that allows for templates coming from the filesystem, the classpath or string values. This is for example if I don't want to rely on filesystem to store the templates. Does this assumption makes sense?
If so, I don't see how this can be done with small changes. The codebase asumes the template is present in the filesystem.
Will It will make sense to merge compiler and runtime in one project and provide different abstractions on the way templates are loaded to support the 3 usage scenarios? (compiling via compiler plugin, reloading compiled templates while in development and full on-the-flight compilation and reloading)
Should a simpler hack be made to support this issue?
I won't be able to work on this until further notice.
Merging the runtime & compiler together isn't an option IMHO. The compiler has a couple dependencies (e.g. ANTLR) that I don't want to force on users who simply use Rocker templates in the highest performance case -- where all compilation happens in development. That's why they were split up to begin with.
For on-the-fly compilation thru various mechanisms (disk, database, classpath, etc.), Rocker doesn't rely on the filesystem as much as I think you are suggesting. There are 3 areas for on-the-fly: 1) where Rocker finds templates to convert into .java code 2) converting .java files into .class files and 3) loading .class files. 1 and 3 should be pretty straightforward and I'm not sure I agree that any code currently in Rocker would make that difficult to switch to use InputStreams, etc. For 2, that may be easy/hard since a Java compiler is involved. Right now Rocker assumes there's a .java file on the filesystem to get it into a .class file on the filesystem, but obviously many other projects can do that in-memory or temporary files, so that should be doable too.
Just a side remark: Tomcat uses ecj from eclipse (https://github.com/eclipse/eclipse.jdt.core) to compile JSPs on the fly. it's actually a reasonably small jar without any dependencies, and, as an added bonus, ecj is much more forgiving than the openjdk's javac and tries to produce something that runs even in presence of errors.
This also rises a question: how rocker compares to JSP (say, tomcat's jasper) performance wise? After all, JSP is a venerable patriarch of all java template engines and can be pretty fast if used properly.
@oakad JSP doesn't compile down to a String or even anything close though. It actually outputs a Java servlet, which means it has to go through some overheads / hoops that Rocker doesn't.