有没有办法将特定的类构造函数导出到FreeMarker数据模型中?
ObjectConstructor
提供了访问任何可访问构造函数的权力:
爪哇:
myDataModel.put("objectConstructor", new ObjectConstructor());
模板:
<#assign aList = objectConstructor("java.util.ArrayList", 100)>
但我不想这样做;如果我有一个包含两个构造函数Foo
和Foo(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));
有办法做到这一点吗?
答案 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;
}
}