【问题标题】:Detect Undefined Variables in FreeMarker在 FreeMarker 中检测未定义的变量
【发布时间】:2016-08-25 08:05:05
【问题描述】:

我正在使用 FreeMarker 构建基于模板的代码生成器。由于用户可以生成任何语言的代码,因此在数据模型中提供特定于语言的设置(例如包)是不合适的。但是,如果它们在 FreeMarker 模板中定义,则必须定义它们(除非它们是可选的)。

此代码利用 FreeMarker 抛出的异常来查找缺失值。然后它用一个临时值填充它们,以便可以找到其他缺失值。

当值在根数据模型中时,这很有效(除了我似乎无法抑制 FreeMarker 的错误消息)。然而,一旦缺失的变量之一处于更深层次,似乎有必要解析整个模板以找出问题所在。

这样做的原因是我可以检测缺失值并即时提示用户。如果他们正在生成 java,它可能会提示打包。 C++?也许是编译指示。

无论如何,有人知道如何更有效地做到这一点吗?

工作代码和模板如下。

来源FMCodeGenTest.java

package codegen;

import freemarker.cache.*;
import freemarker.core.ParseException;
import freemarker.template.*;
import java.io.*;
import java.util.*;

public class FMCodeGenTest {
    private Configuration mConfig = null;
    private HashMap mDataModel = null;
    private Template mTemplate = null;


    public void init() {
        mConfig = new Configuration(Configuration.VERSION_2_3_22);

        try {
            mConfig.setDirectoryForTemplateLoading(new File("./templates"));
            mConfig.setDefaultEncoding("UTF-8");
            mConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        } catch (IOException ie) {
            System.out.println("Error reading templates.");
        }    
    }

    public void buildDataModel() {
        mDataModel = new HashMap();
        mDataModel.put("user", "Foo");

        ArrayList vars = new ArrayList();
        mDataModel.put("vars", vars);

        HashMap var = new HashMap();
        vars.add(var);
        var.put("name", "apple");
        var.put("type", "String");
    }

    public void getTemplate() {
        try {
            mTemplate = mConfig.getTemplate("java_error.ftl");

        } catch (MalformedTemplateNameException ex) {
            System.out.println("Malformed Template Name : " + ex.getMessage());

        } catch (ParseException ex) {
            System.out.println("Parse Error : " + ex.getMessage());

        } catch (IOException ex) {
            System.out.println("IO Exception : " + ex.getMessage());
        }

    }

    public void detectUndefinedVariables() {
        boolean hasBadVars = false;

        do {
            hasBadVars = false;

            try {
                mTemplate.process(mDataModel, new NullWriter());

            } catch (TemplateException ex) {
                hasBadVars = true;

                mDataModel.put(ex.getBlamedExpressionString(), "<temporary value>");

            } catch (IOException ex) {
                System.out.println("IO Exception : " + ex.getMessage());
            }
        } while (hasBadVars);
    }


    public void generateCode() {
        /* Merge data-model with template */
        Writer out = new OutputStreamWriter(System.out);
        try {
            mTemplate.process(mDataModel, out);

        } catch (TemplateException ex) {
            System.out.println("Template Exception : " + ex.getMessage());

        } catch (IOException ex) {
            System.out.println("IO Exception : " + ex.getMessage());
        }
    }

    static public void main(String [] args) {
        FMCodeGenTest test = new FMCodeGenTest();

        test.init();

        test.buildDataModel();

        test.getTemplate();

        test.detectUndefinedVariables();

        test.generateCode();
    }
}

模板java_error.ftl:

package ${package};

/**
 *
 * @author ${user}
 */
public class ${name} {
    <#list vars as var>
    private ${var.type} _${var.name};
    nontrivial ${var.notthere};
    </#list>
}

【问题讨论】:

  • 从“我似乎无法抑制 FreeMarker 的错误消息”开始,我想您指的是日志消息。然后使用mConfig.setLogTemplateExceptions(false)。 (另外,如果您在控制台上看到了消息,那么您需要正确设置日志记录。)
  • @ddekany 啊,谢谢。我错过了 - 一定会尝试的。

标签: java freemarker


【解决方案1】:

我认为这不应该通过捕获InvalidReferenceException 异常来完成,而是通过使用特殊的数据模型来完成。数据模型本身应该提示输入缺失的变量。因此,您始终知道应该将用户提供的值添加到数据模型的哪个位置,而无需处理模板本身。

【讨论】:

  • 我不确定我是否理解此建议。这个想法是从单个数据模型生成代码。我将如何(从模板)向用户传达有要填充的语言特定变量?
  • 在你说你想“即时提示用户”的问题中。你可以在TemplateHashModel.get 中执行此操作,只要它是关于返回null。因为那是(返回null)导致您想要在原始问题中捕获和分析的InvalidReferenceException-s 的原因。请注意,由于您可以防止错误情况本身,因此您不必在发现丢失的变量后重新运行模板。
  • 谢谢。通过将我的数据模型放在 TemplateHashModel 中(如您所建议的),我能够在返回 null 时注入一些用户交互(例如,当为数据模型没有值)。
猜你喜欢
  • 1970-01-01
  • 2011-11-14
  • 2012-03-24
  • 1970-01-01
  • 2013-01-13
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 2018-10-03
相关资源
最近更新 更多