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.
Note, you don't need this exact page to make it fail. Notice that the title attribute is missing the ending quote: "${pageTitle}Code:<#include "/lib/rns.ftl" /> <@html title="${pageTitle}> <@rnsTransactionListing title="${tableTitle}" transactions=rnsTransactions /> </@html>
This is an easy mistake to make however, this gives the following exception:
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: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)
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.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)
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


Reply With Quote