检测 FreeMarker 中的未定义变量
Detect Undefined Variables in FreeMarker
我正在使用 FreeMarker 构建基于模板的代码生成器。由于用户可以用任何语言生成代码,因此在数据模型中提供特定于语言的设置(例如包)是不合适的。但是,如果它们在 FreeMarker 模板中定义,则必须定义它们(除非它们是可选的)。
此代码利用 FreeMarker 抛出的异常来查找缺失值。然后它用一个临时值填充它们,以便可以找到其他缺失值。
当值在根数据模型中时,这很好用(除了我似乎无法抑制 FreeMarker 的错误消息)。然而,一旦其中一个缺失的变量处于更深层次,似乎有必要解析整个模板来找出问题所在。
这样做的原因是我可以检测缺失值并即时提示用户。如果他们正在生成 java,它可能会提示安装包。 C++?也许 pragma 指令。
无论如何,有没有人知道如何更有效地做到这一点?
工作代码和模板如下。
来源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>
}
我认为这不应该通过捕获 InvalidReferenceException
异常来完成,而应该通过使用特殊的数据模型来完成。数据模型本身应该提示缺少的变量。因此,您始终知道应该将用户提供的值添加到数据模型的何处,而无需处理模板本身。
我正在使用 FreeMarker 构建基于模板的代码生成器。由于用户可以用任何语言生成代码,因此在数据模型中提供特定于语言的设置(例如包)是不合适的。但是,如果它们在 FreeMarker 模板中定义,则必须定义它们(除非它们是可选的)。
此代码利用 FreeMarker 抛出的异常来查找缺失值。然后它用一个临时值填充它们,以便可以找到其他缺失值。
当值在根数据模型中时,这很好用(除了我似乎无法抑制 FreeMarker 的错误消息)。然而,一旦其中一个缺失的变量处于更深层次,似乎有必要解析整个模板来找出问题所在。
这样做的原因是我可以检测缺失值并即时提示用户。如果他们正在生成 java,它可能会提示安装包。 C++?也许 pragma 指令。
无论如何,有没有人知道如何更有效地做到这一点?
工作代码和模板如下。
来源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>
}
我认为这不应该通过捕获 InvalidReferenceException
异常来完成,而应该通过使用特殊的数据模型来完成。数据模型本身应该提示缺少的变量。因此,您始终知道应该将用户提供的值添加到数据模型的何处,而无需处理模板本身。