perwendel / spark-template-engines

Repository for different Template engine implementations.
Apache License 2.0
134 stars 101 forks source link

Problem with / and \ for templates on Windows/Linux #71

Open araguacaima opened 6 years ago

araguacaima commented 6 years ago

Hi Per Wendel

I found some inappropriate behavior in the "SparkClasspathTemplateLoader" class when trying to load a template in Windows vs Linux / Unix OS.

Apparently the slash and backslash are not being properly translated according to the OS.

If a template tries to extend from a layout that is in a different folder to where that template is, or if the developer imports some resource that starts with / or \ it happens that the appropriate file is not found, due the templateRoot attribute will be has forced to be stored ending with File.separator. This situation means that you can sometimes try to load a resource such as: /folder//resource or \folder\/resource

In windows 10 that type of path seem to be solved without problems, but in Linux not always. In my particular case it fail in the distribution offered by Heroku, namely:

DISTRIB_ID = Ubuntu DISTRIB_RELEASE = 16.04 DISTRIB_DESCRIPTION = "Ubuntu 16.04.4 LTS" NAME = "Ubuntu" VERSION = "16.04.4 LTS (Xenial Xerus)" ID_LIKE = debian VERSION_ID = "16.04"

To solve that issue in my code (In windows everything works OK, but fails when I deploy code in herolu), I made a copy of SparkClasspathTemplateLoader with the following adaptations:

package my.code;

import de.neuland.jade4j.template.ClasspathTemplateLoader;
import org.apache.commons.lang3.SystemUtils;

import java.io.File;
import java.io.IOException;
import java.io.Reader;

public class SparkClasspathTemplateLoader extends ClasspathTemplateLoader {

    private String templateRoot;

    public SparkClasspathTemplateLoader(String templateRoot) {
        if (templateRoot.endsWith(File.separator)) {
            templateRoot = templateRoot.substring(0, templateRoot.length() - 1);
        }
        if (SystemUtils.IS_OS_WINDOWS) {
            templateRoot = templateRoot.replaceAll("/", File.separator + File.separator);
        } else {
            templateRoot = templateRoot.replaceAll("\\\\", File.separator);
        }
        this.templateRoot = templateRoot;
    }

    public Reader getReader(String name) throws IOException {
        Reader reader = null;
        if (!name.startsWith(File.separator)) {
            name = File.separator + name;
        }
        if (SystemUtils.IS_OS_WINDOWS) {
            name = name.replaceAll("/", File.separator + File.separator);
        } else {
            name = name.replaceAll("\\\\", File.separator);
        }
        String name1 = templateRoot + name;
        try {
            reader = super.getReader(name1);
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return reader;
    }
}

I'm using Apache Lang3 for ease and because I'm already using it in my project, but obviously you can reach the same end using System.getProperty("os.name") or something similar (so you do not have to use third-party libraries)