FileNotFoundException when loading freemarker template in java
Asked Answered
B

5

14

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)
Backus answered 7/2, 2013 at 11:5 Comment(2)
what is the absolute path of file? which OS?Knawel
Please check my update in the question.Backus
C
29

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.

Cropeared answered 7/2, 2013 at 21:53 Comment(7)
I solved the problem i was facing. When i was running the app as an axis2 webservice from eclipse, it considered the eclipse installation folder as the template root folder instead of the project root folder. So that created all the confusion. But what u say makes sense. Is there a way to change the root directory of the application at runtime or somewhere in the project settings?Backus
As I said, you set the template root directory by setting the TemplateLoader in the Configuration, because it's the TemplateLoader that defines the template root. setDirectoryForTemplateLoading is just a convenience method, the generic form is confg.setTemplateLoader(new WhateverTemplateLoader(...)). You should set it wherever you set up the Configuration object. Generally, you do that only once in the application life-cycle, then all threads share the same Configuration object.Cropeared
hey thanks dude. I tried out the config.setDirectoryForTemplateLoading and it worked fine when I ran the webservice. :)Backus
#3019924 worked for me.Implosive
Thanks. I was losing my mind because i could vim the file, but i was getting a file not found exception... This fixed it for me!Henrieta
@Cropeared I was using in the same way by setting directory(My template folder is inside resource folder). And it is working in local testing, but when we are building it and running as jar, ResourceUtils.getFile(templatePath) throws exception like this:- java.io.FileNotFoundException: class path resource [templates] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:projectPath/build/libs/some.jar!/BOOT-INF/classes!/templatesBarris
@Barris If it's inside src/main/resources, then you should use a setClassForTemplateLoading or equivalent. As of the error message, ResourceUtils.getFile(templatePath) is not part of FreeMarker, so I'm not sure how/why you reach that. (Maybe Spring set up some Spring-specific template loader, but I don't even know if you hit that error during template loading.)Cropeared
A
5

You can solve this problem like that.

public class HelloWorldFreeMarkerStyle {
    public static void main(String[] args) {

         Configuration configuration = new Configuration();

         configuration.setClassForTemplateLoading(HelloWorldFreeMarkerStyle.class, "/");



        FileTemplateLoader templateLoader = new FileTemplateLoader(new File("resources"));
        configuration.setTemplateLoader(templateLoader);

        Template helloTemp= configuration.getTemplate("hello.ftl");
        StringWriter writer = new StringWriter();
        Map<String,Object> helloMap = new HashMap<String,Object>();
        helloMap.put("name","gokhan");

        helloTemp.process(helloMap,writer);

        System.out.println(writer);


    }   
}
Algorism answered 26/6, 2015 at 14:33 Comment(1)
Why does giving the path separately in FileTemplateLoader templateLoader work, however giving the path in configuration.setClassForTemplateLoading doesn't?Ola
H
1

Actually you're expected to specify absolute path (not relative) for dir where template is going to be place, see FreeMaker.Configuration:

setDirectoryForTemplateLoading(java.io.File dir)
Sets the file system directory from which to load templates.    
Note that FreeMarker can load templates from non-file-system sources too. See setTemplateLoader(TemplateLoader) from more details.

For instance, this is how to get template from src/test/resources/freemarker:

private String final PATH = "src/test/resources/freemarker"
// getting singleton of Configuration
configuration.setDirectoryForTemplateLoading(new File(PATH))
// surrounded by try/catch
Hazlip answered 9/9, 2019 at 11:18 Comment(0)
M
0

The Java VM is not able to find you file /templates/fibplain.xml in the specified location. This is an absolute path and it is highly likely that you are confused with relative path. To get this corrected use the complete (i.e absolute) path properly like /home/jaykumar/templates/fibplan.xml($TEMPLATE_HOME/fibplan.xml). Other possibility would be, if you do have such location as /templates/, you might not have placed fibplain.xml in the location. To me only these two are the most plausible reasons. I assumed it is one of the linux distribution because of the separator is /

Maurreen answered 7/2, 2013 at 11:16 Comment(1)
I had the problem u stated earlier. I resolved it. I have detailed the new problem in my question with an update. please comment ur viewsBackus
E
0

this work like a Charm ,

package tech.service.common;

import freemarker.cache.FileTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Service
public class MailingService {


    @Autowired
    private JavaMailSender sender;


    public MailResponseDto sendEmail(String mailTo,String Subject) {
        MailResponseDto response = new MailResponseDto();
        MimeMessage message = sender.createMimeMessage();
        Configuration config = new Configuration(new Version(2, 3, 0));

        try {
            // set mediaType
            MimeMessageHelper helper = new MimeMessageHelper(message, MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
                    StandardCharsets.UTF_8.name());
            TemplateLoader templateLoader = new FileTemplateLoader(new File("src/main/resources/template"));
            config.setTemplateLoader(templateLoader);
            // add attachment
            helper.addAttachment("logo.png", new File("src/main/resources/static/images/spring.png"));
            Template t = config.getTemplate("email_template_password.ftl");
            Map<String, Object> model = new HashMap<>();
            model.put("Name", "ELAMMARI Soufiane");
            model.put("location", "Casablanca,Morocco");
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(t, model);

            helper.setTo("[email protected]");
            helper.setText(html, true);
            helper.setSubject(Subject);
            sender.send(message);

            response.setMessage("mail send to : " + mailTo);
            response.setStatus(Boolean.TRUE);

        } catch (MessagingException | IOException | TemplateException e) {
            response.setMessage("Mail Sending failure : "+e.getMessage());
            response.setStatus(Boolean.FALSE);
        }

        return response;
    }
}
Extramarital answered 15/6, 2019 at 21:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.