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

exporting constructors into the FreeMarker data model

有什么方法可以将 specific class 构造函数导出到 FreeMarker 数据模型中吗?

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

Java:

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

模板:

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

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

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

我可以使用 TemplateMethodModelEx 手动执行此操作,但它需要我实现 exec(List arguments) 并弄清楚如何提取参数并将它们推入我的 Foo class构造函数。

我想要的是一个 ClassConstructor 对象,它接受有问题的 class 的 Class<T> 参数,并实现 TemplateMethodModelEx 并自动进行转换,与 FreeMarker 自动处理 Java 对象方法调用的方式相同,我可以在 Java:

中执行此操作
myDataModel.put("Foo", new ClassConstructor(Foo.class));

有办法吗?

从 FTL 调用 Java 方法和构造函数是 BeansWrapper 的业务,它也是 DefaultObjectWrapper 和您发现的大多数自定义 ObjectWrapper-s 的超类在那里。因此,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;
    }

}