I get a file not found exception while loading a freemarker template even though the template is actually present in the path.
Update: This is running as a webservice. It will return an xml to the client based on a search query. The template loads successfully when i call it from another java program(from static main). But the when the client requests for the xml, FileNotFoundException occurs.
OS: Windows 7 Absolute path of file: C:/Users/Jay/workspace/WebService/templates/
Here is my code:
private String templatizeQuestion(QuestionResponse qr) throws Exception { SimpleHash context = new SimpleHash(); Configuration config = new Configuration(); StringWriter out = new StringWriter(); Template _template = null; if(condition1) { _template = config.getTemplate("/templates/fibplain.xml"); } else if(condition2) { _template = config.getTemplate("/templates/mcq.xml"); } context.put("questionResponse", qr); _template.process(context, out); return out.toString(); }
Full Error Stack:
java.io.FileNotFoundException: Template /templates/fibplain.xml not found. at freemarker.template.Configuration.getTemplate(Configuration.java:495) at freemarker.template.Configuration.getTemplate(Configuration.java:458) at com.hm.newAge.services.Curriculum.templatizeQuestion(Curriculum.java:251) at com.hm.newAge.services.Curriculum.processQuestion(Curriculum.java:228) at com.hm.newAge.services.Curriculum.processQuestionList(Curriculum.java:210) at com.hm.newAge.services.Curriculum.getTest(Curriculum.java:122) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.axis2.rpc.receivers.RPCUtil.invokeServiceClass(RPCUtil.java:212) at org.apache.axis2.rpc.receivers.RPCMessageReceiver.invokeBusinessLogic(RPCMessageReceiver.java:117) at org.apache.axis2.receivers.AbstractInOutMessageReceiver.invokeBusinessLogic(AbstractInOutMessageReceiver.java:40) at org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:114) at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:181) at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172) at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:146) at javax.servlet.http.HttpServlet.service(HttpServlet.java:637) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Unknown Source)
Advertisement
Answer
FreeMarker template paths are resolved by a TemplateLoader
object, which you should specify in the Configuration
object. The path that you specify as the template path is interpreted by the TemplateLoader
, and is usually relative to some kind of base directory (even if it starts with /
), that’s also called the template root directory for this reason. In your example, you haven’t specified any TemplateLoader
, so you are using the default TemplateLoader
, which is only there for backward-compatibility, and is nearly useless (and also dangerous). So, do something like this:
config.setDirectoryForTemplateLoading(new File( "C:/Users/Jay/workspace/WebService/templates"));
and then:
config.getTemplate("fibplain.xml");
Note that the /template
prefix is not there now, as the template path is relative to C:/Users/Jay/workspace/WebService/templates
. (This also means that the template can’t back out of it with ../
-s, which can be important for security.)
Instead of loading from a real directory, you can also load templates from a SerlvetContext
, from the “class path”, etc. It all depends on what TemplateLoader
you are choosing.
See also: http://freemarker.org/docs/pgui_config_templateloading.html
Update: If you get FileNotFoundException
instead of TemplateNotFoundException
, it’s time to upgrade FreeMarker to at least 2.3.22. It also gives better error messages, like if you do the typical mistake of using the default TemplateLoader
, it tells you that right in the error message. Less wasted developer time.