Freemarker中的继承/ instanceof检查

3
我的用例是通过模板引擎为用户提供创建报告的可能性。因此,我提取了数据模型的相关部分,并集成了Freemarker作为模板引擎。到目前为止,它运行良好,但现在我的数据模型在某些位置包含继承 - 但是似乎Freemarker不支持instanceof操作?如何解决这个问题?是否有其他支持模型中继承的模板引擎呢?
虚构的例子:
我有两个类“Car”和“Bike”,它们都扩展自“Vehicle”。并且模型包含一个名为“车队”的类,其中包含车辆列表。用户希望(借助模板)遍历该列表,并在汽车属性“countSeats”和摩托车属性“frame size”的情况下编写。如何使用Freemarker实现此目标?是否可以在任何模板引擎中完成此操作?
非常感谢!
//编辑:不幸的是,由于车辆列表中的顺序很重要,在具体对象中无法将超类的列表拆分为几个列表。

FreeMarker是否支持在列表中的对象上调用任意Java方法? 如果支持,您可以使用Object.getClass();虽然有些丑陋,但它可以工作,希望有更好的方法。 - Kasper van den Berg
我从未使用过FreeMarker,但您认为是否可以使用访问者模式来替代instanceof的需要? - Dioxin
@Kasper:它确实支持调用任意的Java方法。 - ddekany
4个回答

4

更丑陋的解决方案

            <#if yourObject.class.simpleName == "Simple class name like String">
                something
            </#if>                     

            <#if yourObject.class.simpleName == "other simple class name">
                do something else
            </#if>  `

3
这方面没有内置功能,但也不需要内置。您可以编写自己的TemplateMethodModelEx,或将纯Java助手对象放入数据模型中以执行几乎任何操作。或者,您可以将相关的类放入数据模型中,例如root.put("Car", Car.class)等,然后像这样使用Class的Java API:<#if Car.isInstance(someObject)>

非常感谢。但是恐怕我没有理解您的建议。我理解了第二个建议,即将Car.class放入模型中 - 这样可以进行instanceof检查,但我还需要对实例进行强制转换,这在此选项下是不可能的? 第一个建议是关于编写自己的TemplateMethodModelEx - 您更详细地指的是什么?我查看了源代码,但没有理解您的建议的想法。 - Balrog
什么是类型转换?FTL是动态类型的,您不需要进行类型转换。(至于TemplateMethodModelEx,从JavaDoc中应该很明显如何实现它,然后如果将其放入数据模型或Configuration级别的共享变量中,则可以在模板中使用它,例如myMethod(foo, bar)。) - ddekany

3

使用TemplateMethodModelEx的解决方案。

类:

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());
            }
        }
    }
}

将该类的实例以及所有必需的类添加到模板的输入参数中:
parameters.put("instanceOf", new InstanceOfMethod());
parameters.put("Car", Car.class);
...

或者您可以向共享变量添加方法:http://freemarker.org/docs/pgui_config_sharedvariables.html

因此,您可以在FTL中按照以下方式使用该方法:

<#if instanceOf(object, Car)>
       ...
</#if>

1

我发现这比在 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);
        }
    }
    
}

你可以直接使用一个字符串,其中包含类加载器可用的任何类的完全限定名(FQN)。
<#if instanceOf(object, "mypackage.MyClass")>
...
</#if>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接