Freemarker 中的继承/instanceof 检查
Inheritance / instanceof checks in Freemarker
我的用例是为用户提供在模板引擎的帮助下创建报告的可能性。因此,我提取了数据模型的相关部分并将 Freemarker 作为模板引擎集成。
到目前为止效果很好,但现在我的数据模型包含某些位置的继承 - 但 Freemarker 似乎不支持 instanceof 操作?如何处理这个问题?模型中是否还有其他支持继承的模板引擎?
虚构的例子:
我有 2 个 classes "Car" 和扩展 "Vehicle" 的 "Bike"。该模型包含一个 class "vehicle fleet",其中包含一个车辆列表。用户希望(在模板的帮助下)遍历列表并在汽车的情况下写入属性 "countSeats",在自行车的情况下写入属性 "frame size"。如何使用 Freemarker 实现这一点?可以在任何模板引擎中完成吗?
非常感谢!
// 编辑:不幸的是,由于车辆的顺序(在上面的示例中)在列表是必不可少的。
没有为此内置任何内容,但也不一定是。您可以编写自己的 TemplateMethodModelEx
,或将简单的 Java 辅助对象放入数据模型中以执行几乎所有操作。或者,您可以将相关的 类 放入数据模型中,例如 root.put("Car", Car.class)
等,然后像这样使用 Class
的 Java API : <#if Car.isInstance(someObject)>
使用 TemplateMethodModelEx
的解决方案。
Class:
public class InstanceOfMethod implements TemplateMethodModelEx {
@Override
public Object exec(List list) throws TemplateModelException
{
if (list.size() != 2) {
throw new TemplateModelException("Wrong arguments for method 'instanceOf'. Method has two required parameters: object and class");
} else {
Object object = ((WrapperTemplateModel) list.get(0)).getWrappedObject();
Object p2 = ((WrapperTemplateModel) list.get(1)).getWrappedObject();
if (!(p2 instanceof Class)) {
throw new TemplateModelException("Wrong type of the second parameter. It should be Class. Found: " + p2.getClass());
} else {
Class c = (Class) p2;
return c.isAssignableFrom(object.getClass());
}
}
}
}
将 class 的实例和所有必需的 classes 放入模板的输入参数中:
parameters.put("instanceOf", new InstanceOfMethod());
parameters.put("Car", Car.class);
...
或者您可以将方法添加到共享变量:http://freemarker.org/docs/pgui_config_sharedvariables.html
所以你可以在FTL中使用方法如下:
<#if instanceOf(object, Car)>
...
</#if>
更丑陋的解决方案
<#if yourObject.class.simpleName == "Simple class name like String">
something
</#if>
<#if yourObject.class.simpleName == "other simple class name">
do something else
</#if> `
我发现这比注册所有 classes 更容易,您可能会再次在 instanceof 中尝试这样做:
public class InstanceOfMethod implements TemplateMethodModelEx {
@Override
public Object exec(List arguments) throws TemplateModelException {
if (arguments.size() != 2) {
throw new TemplateModelException("Wrong arguments");
}
Object bean = DeepUnwrap.unwrap((TemplateModel) arguments.get(0));
String className = ((TemplateModel) arguments.get(1)).toString();
try {
Class clazz = Class.forName(className);
return clazz.isInstance(bean);
}
catch (ClassNotFoundException ex) {
throw new TemplateModelException("Could not find the class '" + className + "'", ex);
}
}
}
然后您可以只使用带有 class 可用于 classloader 的任何 class FQN 的字符串:
<#if instanceOf(object, "mypackage.MyClass")>
...
</#if>
我的用例是为用户提供在模板引擎的帮助下创建报告的可能性。因此,我提取了数据模型的相关部分并将 Freemarker 作为模板引擎集成。 到目前为止效果很好,但现在我的数据模型包含某些位置的继承 - 但 Freemarker 似乎不支持 instanceof 操作?如何处理这个问题?模型中是否还有其他支持继承的模板引擎?
虚构的例子:
我有 2 个 classes "Car" 和扩展 "Vehicle" 的 "Bike"。该模型包含一个 class "vehicle fleet",其中包含一个车辆列表。用户希望(在模板的帮助下)遍历列表并在汽车的情况下写入属性 "countSeats",在自行车的情况下写入属性 "frame size"。如何使用 Freemarker 实现这一点?可以在任何模板引擎中完成吗?
非常感谢!
// 编辑:不幸的是,由于车辆的顺序(在上面的示例中)在列表是必不可少的。
没有为此内置任何内容,但也不一定是。您可以编写自己的 TemplateMethodModelEx
,或将简单的 Java 辅助对象放入数据模型中以执行几乎所有操作。或者,您可以将相关的 类 放入数据模型中,例如 root.put("Car", Car.class)
等,然后像这样使用 Class
的 Java API : <#if Car.isInstance(someObject)>
使用 TemplateMethodModelEx
的解决方案。
Class:
public class InstanceOfMethod implements TemplateMethodModelEx {
@Override
public Object exec(List list) throws TemplateModelException
{
if (list.size() != 2) {
throw new TemplateModelException("Wrong arguments for method 'instanceOf'. Method has two required parameters: object and class");
} else {
Object object = ((WrapperTemplateModel) list.get(0)).getWrappedObject();
Object p2 = ((WrapperTemplateModel) list.get(1)).getWrappedObject();
if (!(p2 instanceof Class)) {
throw new TemplateModelException("Wrong type of the second parameter. It should be Class. Found: " + p2.getClass());
} else {
Class c = (Class) p2;
return c.isAssignableFrom(object.getClass());
}
}
}
}
将 class 的实例和所有必需的 classes 放入模板的输入参数中:
parameters.put("instanceOf", new InstanceOfMethod());
parameters.put("Car", Car.class);
...
或者您可以将方法添加到共享变量:http://freemarker.org/docs/pgui_config_sharedvariables.html
所以你可以在FTL中使用方法如下:
<#if instanceOf(object, Car)>
...
</#if>
更丑陋的解决方案
<#if yourObject.class.simpleName == "Simple class name like String">
something
</#if>
<#if yourObject.class.simpleName == "other simple class name">
do something else
</#if> `
我发现这比注册所有 classes 更容易,您可能会再次在 instanceof 中尝试这样做:
public class InstanceOfMethod implements TemplateMethodModelEx {
@Override
public Object exec(List arguments) throws TemplateModelException {
if (arguments.size() != 2) {
throw new TemplateModelException("Wrong arguments");
}
Object bean = DeepUnwrap.unwrap((TemplateModel) arguments.get(0));
String className = ((TemplateModel) arguments.get(1)).toString();
try {
Class clazz = Class.forName(className);
return clazz.isInstance(bean);
}
catch (ClassNotFoundException ex) {
throw new TemplateModelException("Could not find the class '" + className + "'", ex);
}
}
}
然后您可以只使用带有 class 可用于 classloader 的任何 class FQN 的字符串:
<#if instanceOf(object, "mypackage.MyClass")>
...
</#if>