Loading velocity template inside a jar file

39,467

Solution 1

If you want to use resources from classpath, you should use resource loader for classpath:

ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); 
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());

Solution 2

Final code, developed using the ideas presented in both answers above:

VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());

ve.init();

final String templatePath = "templates/" + templateName + ".vm";
InputStream input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
if (input == null) {
    throw new IOException("Template file doesn't exist");
}

InputStreamReader reader = new InputStreamReader(input);

VelocityContext context = new VelocityContext();

if (properties != null) {
    stringfyNulls(properties);
    for (Map.Entry<String, Object> property : properties.entrySet()) {
        context.put(property.getKey(), property.getValue());
    }
}

Template template = ve.getTemplate(templatePath, "UTF-8");
String outFileName = File.createTempFile("report", ".html").getAbsolutePath();
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outFileName)));

if (!ve.evaluate(context, writer, templatePath, reader)) {
    throw new Exception("Failed to convert the template into html.");
}

template.merge(context, writer);

writer.flush();
writer.close();

Solution 3

Unless JAR is exploded, you can't read the resource in JAR as file. Use an input stream.

See following code snippets,

    InputStream input = classLoader.getResourceAsStream(fileName);
    if (input == null) {
        throw new ConfigurationException("Template file " +
                fileName + " doesn't exist");           
    }

    InputStreamReader reader = new InputStreamReader(input);            
        Writer writer = null;

        try {
            writer = new OutputStreamWriter(output);        

            // Merge template
            if (!engine.evaluate(context, writer, fileName, reader)) 
                ......
Share:
39,467
Rafael
Author by

Rafael

Updated on July 09, 2022

Comments

  • Rafael
    Rafael almost 2 years

    I have a project where I want to load a velocity template to complete it with parameters. The whole application is packaged as a jar file. What I initially thought of doing was this:

    VelocityEngine ve = new VelocityEngine();
    
       URL url = this.getClass().getResource("/templates/");
    
       File file = new File(url.getFile());
    
       ve = new VelocityEngine();
       ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
       ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath());
       ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
    
       ve.init();
    
       VelocityContext context = new VelocityContext();
    
       if (properties != null) {
        stringfyNulls(properties);
        for (Map.Entry<String, Object> property : properties.entrySet()) {
         context.put(property.getKey(), property.getValue());
        }
       }
    
       final String templatePath = templateName + ".vm";
       Template template = ve.getTemplate(templatePath, "UTF-8");
       String outFileName = File.createTempFile("report", ".html").getAbsolutePath();
       BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outFileName)));
    
       template.merge(context, writer);
    
       writer.flush();
       writer.close();
    

    And this works fine when I run it in eclipse. However, once I package the program and try to run it using the command line I get an error because the file could not be found.

    I imagine the problem is in this line:

    ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath());
    

    Because in a jar the absolute file does not exist, since it's inside a zip, but I couldn't yet find a better way to do it.

    Anyone has any ideas?