Bug in Freemark/Spring Support
I have come across a little bug (well, more of an annoyance really) where Spring does not report the true cause of the failure when a freemarker template is not parsed properly. This is a repeatable bug that I've come across at least 6 or 7 times in the last day and it can make working with Freemarker and Spring into a much frustrating endevour.
Here is a simple template that will make it fail.
Code:
<#include "/lib/rns.ftl" />
<@html title="${pageTitle}>
<@rnsTransactionListing title="${tableTitle}" transactions=rnsTransactions />
</@html>
Note, you don't need this exact page to make it fail. Notice that the title attribute is missing the ending quote: "${pageTitle}
This is an easy mistake to make however, this gives the following exception:
Code:
org.springframework.context.ApplicationContextException: Cannot load FreeMarker
template for URL [core\release.transactions.page.ftl]: Did you specify
the correct template loader path?
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.initApplicationContext(FreeMarkerView.java:136)
at org.springframework.context.support.ApplicationObjectSupport.setApplicationContext(ApplicationObjectSupport.java:79)
at org.springframework.web.servlet.view.AbstractCachingViewResolver.loadAndConfigureView(AbstractCachingViewResolver.java:123)
at org.springframework.web.servlet.view.AbstractCachingViewResolver.resolveViewName(AbstractCachingViewResolver.java:78)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:629)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:535)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:321)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:103)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:113)
at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:129)
at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:61)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:84)
at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:211)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:177)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:221)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:263)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:323)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:430)
at com.caucho.util.ThreadPool.run(ThreadPool.java:377)
at java.lang.Thread.run(Thread.java:534)
I assure you, the loader path is not a problem. If one fixes the problem in the template, it will work fine. However, if I re-create the problem, this is what happens:
Code:
freemarker.core.ParseException: Encountered "{" at line 5, column 41.
Was expecting:
"=" ...
at freemarker.core.FMParser.generateParseException(FMParser.java:4411)
at freemarker.core.FMParser.jj_consume_token(FMParser.java:4286)
at freemarker.core.FMParser.NamedArgs(FMParser.java:1886)
at freemarker.core.FMParser.UnifiedMacroTransform(FMParser.java:1771)
at freemarker.core.FMParser.FreemarkerDirective(FMParser.java:2216)
at freemarker.core.FMParser.Content(FMParser.java:2433)
at freemarker.core.FMParser.OptionalBlock(FMParser.java:2601)
at freemarker.core.FMParser.Root(FMParser.java:2773)
at freemarker.template.Template.<init>(Template.java:144)
at freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:376)
at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:347)
at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:229)
at freemarker.template.Configuration.getTemplate(Configuration.java:426)
at freemarker.template.Configuration.getTemplate(Configuration.java:398)
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.getTemplate(FreeMarkerView.java:168)
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:151)
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:160)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:238)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:644)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:535)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:321)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:103)
As you can see, the correct exception is finally thrown. However, if I restart my server with the template problem intact, it's possible to repeat this resource-loader exception bug.
Motivation for fix? While the exceptions are working just fine if a template is already loaded, it makes debugging *new* pages while the server is running, or even old pages after a restart, very problematic. This template is trivial, however, if it were a library template with 600 lines of code, finding the bug would not be trivial. Even further, I noticed that this happens when a pages includes other templates with errors, even if the main template is syntactically correct.
Anyway, I would really appreciate it if you guys could implement a fix since I have quite a few more templates to make :P
Thanks,
Ken Egervari
Re: Bug in Freemark/Spring Support
Quote:
Originally Posted by egervari
Note, you don't need this exact page to make it fail. Notice that the title attribute is missing the ending quote: "${pageTitle}
This is an easy mistake to make however, this gives the following exception:
side note: there are some good FTL plugins that will show such errors up in your editor/IDE. I've used the eclipse one to good effect. http://www.freemarker.org/editors.html
Re: Bug in Freemark/Spring Support
Unfortunately I'm using IDEA and it's not supported. I still think using Freemarker without syntax highlighting is more productive and produces cleaner code than velocity, so I'll stick with it either way. Glad I could help and I'll be sure to use JIRA from now on.
Regards,
Ken