isystems_uk
isystems_uk

Reputation: 43

How to expose spring tag lib to Freemaker configuration using java and to process Freemarker Template class?

I have been trying to use freemarker.template.Template class to process a given .ftl template. Basiclaly it is not finding the spring tag libs and fails when it encounters the first <@spring.url.../> tag. However, it reads spring macro directives just fine.

Attaching my freemarker config in spring and the error message:

I am using spring 4, with freemarker 2.3.23. While running my Spring MVC application on tomcat 7, it complains about following:

---- FTL stack trace ("~" means nesting-related): - Failed at: @spring.url "/imports/app/vendor/boot... [in template "config/pages/default-page.ftl" at line 5, column 54] ----] with root cause FreeMarker template error: The following has evaluated to null or missing: ==> spring [in template "config/pages/default-page.ftl" at line 5, column 56]

Java stack trace (for programmers): ---- freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...] at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:131) at freemarker.core.UnexpectedTypeException.newDesciptionBuilder(UnexpectedTypeException.java:77) at freemarker.core.UnexpectedTypeException.(UnexpectedTypeException.java:40) at freemarker.core.NonHashException.(NonHashException.java:46) at freemarker.core.Dot._eval(Dot.java:45) at freemarker.core.Expression.eval(Expression.java:78) at freemarker.core.UnifiedCall.accept(UnifiedCall.java:74) at freemarker.core.Environment.visit(Environment.java:324) at freemarker.core.MixedContent.accept(MixedContent.java:54) at freemarker.core.Environment.visit(Environment.java:324) at freemarker.core.Environment.process(Environment.java:302) at freemarker.template.Template.process(Template.java:325) at com.isys.ghp.server.services.web.impls.HtmlRenditionComposer.composeRendition(HtmlRenditionComposer.java:43) at com.isys.ghp.controllers.app.RootControllerApp.welcome(RootControllerApp.java:48) at com.isys.ghp.controllers.app.RootControllerApp$$FastClassBySpringCGLIB$$cebaa583.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) at com.isys.ghp.server.aspects.MethodLogger.around(MethodLogger.java:21) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) at com.isys.ghp.controllers.app.RootControllerApp$$EnhancerBySpringCGLIB$$55180b14.welcome() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858) at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)

Code of MVCConfiguration extends WebMvcConfigurerAdapter

@Bean 
public FreeMarkerViewResolver freemarkerViewResolver() {
    LOGGER.debug("Executing freemarkerViewResolver()");
    FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
    resolver.setExposeSpringMacroHelpers(true);  
    resolver.setExposeRequestAttributes(true);
    resolver.setCache(true); 
    resolver.setPrefix(""); 
    resolver.setSuffix(".ftl");
    return resolver; 
}

@Bean(name="fmAdvanceConfigFactoryBean")    
public FreeMarkerConfigurer getFreemarkerConfig() throws IOException, TemplateException  {
    FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean = new FreeMarkerConfigurationFactoryBean();
    FreeMarkerConfigurer result = new FreeMarkerConfigurer();
    result.setTemplateLoaderPath("/WEB-INF/views");
    result.setConfiguration(freeMarkerConfigurationFactoryBean.createConfiguration());
    return result;
}   

Template processing block:

Template pageHTML = fmAdvanceConfigFactoryBean.getTemplate("config/pages/default-page.ftl");  
StringWriter pageWriter = new StringWriter();
Map<String, Object> map = new HashMap<>();
pageHTML.process(map, pageWriter);

I have been looking a lot of pages providing advance configuration but none of them is able to resolve this. I am not sure what I am missing here. Any help will be useful and appreciated!

Thanks!

Update: You were right, ddekany! Like you suggested, there was another method in different config file. I have commented that method and checked there is no other point of call. However, now its complaining about not finding the template. See my answer below. You were right. There was another method in different config file. I have commented that method and checked there is no other point of call. However, now its complaining about not finding the template:

freemarker.template.TemplateNotFoundException: Template not found for name "/config/pages/default-page.ftl". The name was interpreted by this TemplateLoader: LegacyDefaultFileTemplateLoader(baseDir="/Users/mdani/Data_MD/Developer_MD/Workspace/Tools/GH-Platform/STS.app/Contents/MacOS", canonicalBasePath="/Users/mdani/Data_MD/Developer_MD/Workspace/Tools/GH-Platform/STS.app/Contents/MacOS/"). Warning: The "template_loader" FreeMarker setting wasn't set (Configuration.setTemplateLoader), and using the default value is most certainly not intended and dangerous, and can be the cause of this error. at freemarker.template.Configuration.getTemplate(Configuration.java:2701) at freemarker.template.Configuration.getTemplate(Configuration.java:2503)

Simplified class:

    @Loggable
@Bean(name="fmAdvanceConfigFactoryBean")    
public FreeMarkerConfigurer getFreemarkerConfig() throws IOException, TemplateException  {
    Properties settings = new Properties(); 
    settings.setProperty("auto_import", "/spring.ftl as spring");
    FreeMarkerConfigurer result = new FreeMarkerConfigurer();
    result.setTemplateLoaderPaths("/WEB-INF/views","classpath:/");
    result.setFreemarkerSettings(settings);
    return result;
}

New Error:

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/GHPWebApp] threw exception [Request processing failed; nested exception is freemarker.core.InvalidReferenceException: The following has evaluated to null or missing: ==> springMacroRequestContext [in template "spring.ftl" at line 89, column 134]

---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing. (These only cover the last step of the expression; to cover the whole expression,

use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??

---- FTL stack trace ("~" means nesting-related): - Failed at: ${springMacroRequestContext.getContex... [in template "spring.ftl" in macro "url" at line 89, column 132] - Reached through: @spring.url "/imports/app/vendor/boot... [in template "config/pages/default-page.ftl" at line 4, column 54] ----] with root cause FreeMarker template error: The following has evaluated to null or missing: ==> springMacroRequestContext [in template "spring.ftl" at line 89, column 134]

---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing. (These only cover the last step of the expression; to cover the whole expression,

use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??

---- FTL stack trace ("~" means nesting-related): - Failed at: ${springMacroRequestContext.getContex... [in template "spring.ftl" in macro "url" at line 89, column 132]

- Reached through: @spring.url "/imports/app/vendor/boot... [in template "config/pages/default-page.ftl" at line 4, column 54]

Java stack trace (for programmers): ---- freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...] at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) at freemarker.core.UnexpectedTypeException.newDesciptionBuilder(UnexpectedTypeException.java:85) at freemarker.core.UnexpectedTypeException.(UnexpectedTypeException.java:48) at freemarker.core.NonHashException.(NonHashException.java:49)

Upvotes: 1

Views: 2224

Answers (1)

ddekany
ddekany

Reputation: 31132

I guess the spring variable is missing because your template doesn't start with <#import "/spring.ftl" as spring>, nor you have configured an auto-import for that. The last is the more convenient way. Something like Properties settings = new Properties(); settings.setProperty("auto_import", "/spring.ftl as spring"); configurer.setFreemarkerSettings(settings);.

(BTW, upgrade FreeMarker to the latest 2.x.x... 2.3.23 is old.)

Upvotes: 2

Related Questions