将构造函数导出到FreeMarker数据模型中

时间:2015-05-22 17:35:50

标签: java freemarker

有没有办法将特定的类构造函数导出到FreeMarker数据模型中?

ObjectConstructor提供了访问任何可访问构造函数的权力:

爪哇:

myDataModel.put("objectConstructor", new ObjectConstructor()); 

模板:

<#assign aList = objectConstructor("java.util.ArrayList", 100)>

但我不想这样做;如果我有一个包含两个构造函数FooFoo(int x)的类Foo(String name, int x),我想以某种方式将对象导出到数据模型中Foo,这样我就可以在模板中执行此操作:

<#assign myfoo1 = Foo(1) >
<#assign myfoo2 = Foo("Buffalo Bill", 2) >

我可以使用TemplateMethodModelEx手动执行此操作,但它需要我实现exec(List arguments)并找出如何将参数拉出并将它们推送到我的Foo类构造函数中。

我想要的是一个ClassConstructor对象,它接受相关类的Class<T>参数,并实现TemplateMethodModelEx并自动执行转换,就像FreeMarker自动处理的一样Java对象方法调用,我可以用Java做到这一点:

myDataModel.put("Foo", new ClassConstructor(Foo.class));

有办法做到这一点吗?

1 个答案:

答案 0 :(得分:1)

从FTL调用Java方法和构造函数是BeansWrapper的业务,它也是DefaultObjectWrapper和大多数自定义ObjectWrapper的超类 - 您可以找到它们。所以,ObjectWrapper.newInstance(Class clazz, List/*<TemplateModel>*/ arguments)可以为你做一些棘手的事情。其他的都是一些微不足道的管道(我在这里有点看中了ObjectWrapper - 这是可选的):

package freemarker.adhoc;

import java.util.List;

import freemarker.core.Environment;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;

/**
 * Creates an FTL method that calls the constructor of the given class. Supports overloading and varargs. 
 */
public class ConstructorTemplateModel implements TemplateMethodModelEx {

    private final Class constructorClass;
    private final BeansWrapper objectWrapper;

    /**
     * @param objectWrapper
     *            The same {@link ObjectWrapper} used in the {@link Configuration}, or {@code null} if we should
     *            find the current {@link ObjectWrapper} for each constructor call (slower).
     */
    public ConstructorTemplateModel(Class<?> constructorClass, BeansWrapper objectWrapper) {
        this.constructorClass = constructorClass;
        this.objectWrapper = objectWrapper;
    }

    @Override
    public Object exec(List/*<TemplateModel>*/ arguments) throws TemplateModelException {
        BeansWrapper objectWrapper = this.objectWrapper;
        if (objectWrapper == null) {
            objectWrapper = getCurrentBeansWrapper();
        }

        return objectWrapper.newInstance(constructorClass, arguments);
    }

    private BeansWrapper getCurrentBeansWrapper() {
        Environment env = Environment.getCurrentEnvironment();
        if (env == null) {
            throw new IllegalStateException("No ongoing template processing");
        }

        ObjectWrapper objectWrapper = env.getObjectWrapper();
        if (!(objectWrapper instanceof BeansWrapper)) {
            throw new IllegalStateException("The object wrapper must be a BeansWrapper. Object wrapper class: "
                    + objectWrapper.getClass().getName());
        }

        return (BeansWrapper) objectWrapper;
    }

}