打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
A story about FreeMarker and Velocity(By Max)
A story about FreeMarker and Velocity
03. Feb 2006, 12:24</B< small>
bymax@hibernate.org |Link |11 comments
 
I have been fed up withVelocity’s ability to ignore and even hide errors and exceptions occurring in the templates used inHibernate Tools.
This blog tells about why and howFreeMarker became my new interest. If you just want to see the results then go and fetch the code in theTOOLS_FREEMARKER branch...read on to get the full story.
The problems with Velocity
I started to see more and more forum postings and bug reports about issues that were caused by typo’s in users templates or even worse errors in the Hibernate Tools. Many of these issues would be solvable within seconds if Velocity would actually tell where in the templates the error occurred and unit tests would have failed if underlying exceptions were exposed; but Velocity simply does not.
I have added every safety-precaution I have been able to apply to Velocity error handling. I have created my own UberSpect and EventHandler implementation that will not allow you to invoke methods that does not exist and I have tweaked the logging settings to be more informative; but it does not (hardly) solve all the problems that can occur.
Logging is excessive in Velocity even at WARN and INFO level, one good reason for this is most likely that the developers know that Velocity is ignoring situations where it should actually fail, thus since there is no easy other way implemented in Velocity they put it in the log for users to discover by accident!
The choice originally fell on Velocity since it was the biggest player around, and I added it naively thinking that the error and log handling could not be that bad if so many people were using it and if there were an issue it would be fixed soon.
As time went by I learned that it was definitely not the case.
The beauty of FreeMarker
Last week I decided to look around for alternatives, the only real alternative I found were FreeMarker; everything else looked either too simple or way to complex for the Hibernate Tools needs. Now that I have spent just 1,5 day converting the existing Velocity templates to FreeMarker I’m more than happy I did.
Here are some examples of the beauty of FreeMarker:
Assume we have the following bean:
public class Table { String getName(); }
The bean is available via "table" in the following code:
${table.name}
That typo will just be ignored by default in Velocity, with a custom EventHandler it can be convinced to throw an exception which comes out like this:
Caused by: java.lang.IllegalArgumentException: $seam_appname is not a valid reference. at org.hibernate.tool.hbm2x.HibernateEventHandler.referenceInsert(HibernateEventHandler.java:11) at org.apache.velocity.app.event.EventCartridge.referenceInsert(EventCartridge.java:131) ... 19 more
No information about which template nor where in the temmplate it went wrong.
In FreeMarker I get the following with no special configuration and custom code:
Expression table.namee is undefined on line 15, column 14 in doc/tables/table.ftl. The problematic instruction: ---------- ==> ${table.namee} [on line 15, column 12 in doc/tables/table.ftl] ---------- Java backtrace for programmers: ---------- freemarker.core.InvalidReferenceException: Expression table.namee is undefined on line 15, column 14 in doc/tables/table.ftl. at freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:124) at freemarker.core.Expression.getStringValue(Expression.java:118) at freemarker.core.Expression.getStringValue(Expression.java:93) ...
Nice! And even better, the "on line 15, ..." works like a link in e.g. Eclipse Console view. Clicking it brings you to the location of the error in the table.ftl. file.
Similar and precise error messages you get if you refer to non existing methods, Just brilliant! The great thing is that if I really wanted FreeMarker to ignore this I could do so by installing a different Exception handler. But that is my choice, not a hard to change behavior.
The built in primitives in FreeMarker is also great, e.g. <#assign> that allows me to store any generated output in a variable for later usage.
${pojo.getPackageDeclaration()} // Generated ${date} by Hibernate Tools ${version} <#assign classbody> <#include "PojoTypeDeclaration.ftl"/> { ..more template code.. } </#assign> ${pojo.generateImports()} ${classbody}
This allows me to remove the need to have a magically second-pass which I did with Velocity. There are more gems like these to be found in the excellent FreeMarkerdocumentation.
Another big plus in FreeMarker‘s favor is theConfiguration API. Let us compare, here is our Velocity setup:
engine = new VelocityEngine(); context = new VelocityContext(); EventCartridge ec = new EventCartridge(); ec.addEventHandler(new HibernateEventHandler()); // stricter evaluation ec.attachToContext( context ); Properties p = new Properties(); p.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.tools.generic.log.CommonsLogLogSystem"); p.setProperty(CommonsLogLogSystem.LOGSYSTEM_COMMONS_LOG_NAME, "org.hibernate.tool.hbm2x.template"); p.setProperty( RuntimeConstants.UBERSPECT_CLASSNAME, HibernateUberspect.class.getName() ); // stricter evaluation p.setProperty("velocimacro.library",""); // make it shut up about VM_global_library blah p.setProperty("resource.loader", "file, class"); p.setProperty("file.resource.loader.path", directory ); p.setProperty("class.resource.loader.class", ClasspathResourceLoader.class.getName() ); engine.init(p);
Here is the corresponding FreeMarker config:
engine = new Configuration(); context = new SimpleHash(ObjectWrapper.BEANS_WRAPPER); //Logger.setCategoryPrefix("org.hibernate.tool.hbm2x.template"); // Not really needed since the logging is much more sensible. freeMarkerEngine.setTemplateLoader(new MultiTemplateLoader( new FileTemplateLoader(directory), new ClassTemplateLoader(this.getClass(),"/"));
Notice the difference? FreeMarker has good practice defaults and actually allows me to use java code to configure it; what a neat concept.
The downside of FreeMarker
The only two "bad" things I have found yet with FreeMarker is that it’s syntax is based on <#..> which does not compute very well when trying to show it in an XML editor. This has been "fixed" in the latest release by also allowing [#...] syntax.
Another bigger issue is that ${} and #{} is not escapable. This syntax collides in templates that generates ant build and jsp files.
In Velocity they were just ignored (the only place were it were useful to ignore them). FreeMarker complains because the values are undefined and unfortunately there is no easy-on-the-eyes method to escape these characters. The following show the methods that I found to allow the me to output ${..}:
${r"${build.dir}"} ${‘$’}{build.dir} <#noescape>${build.dir}</noescape>
Still the brilliant exception handling, powerful template language and configuration API makes FreeMarker a much better choice for Hibernate Tools.
What now ?
Velocity served me well and is probably serving many projects well; it just did not cut it well for Hibernate Tools. Today I am convinced that I could have saved myself and the Hibernate world from a lot of trouble if I had decided to use FreeMarker from the beginning.
Come and see for your self in theTOOLS_FREEMARKER branch. The code in there will be merged into the main development in the near future unless someone steps up with a very good reason for not doing so ;)
To be fair, I must tell you that Velocity 1.5 is being worked on right now, and it does seem to solve some of these issues, but not completely and Velocity has some external dependencies I would rather not add to the tools project.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Spring框架集成FreeMarker
java利用freemarker生成html静态页面
Spring发送邮件简单实例
Struts2第十七课:Struts2中使用FreeMarker充当表现层_李飞虎 jav...
freeMarker模板引擎将表格中的数据导出成Excel
freemarker报 java.io.FileNotFoundException:及Te...
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服