将构造函数导出到 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;
}
}
有什么方法可以将 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;
}
}