一些类

  • freemarker.template.ObjectWrapper

    将 Java 对象映射到 FTL 的 TemplateModel 中,这决定了哪些 Java 对象可以被 FTL 命令访问,实现了 FTL 的安全沙箱机制。

    实现类和子接口

  • freemarker.ext.servlet.FreemarkerServlet#process

    处理 http 请求的入口

  • freemarker.template.TemplateModel

    FTL 数据类型的通用接口,所有 Java 对象都会映射到这个接口的实现类中,FTL 只会处理 实现该接口的 FTL 数据类型

  • freemarker.template.utility.Execute#exec

public Object exec (List arguments) throws TemplateModelException {
    String aExecute;
    StringBuffer    aOutputBuffer = new StringBuffer();
 
    if( arguments.size() < 1 ) {
        throw new TemplateModelException( "Need an argument to execute" );
    }
 
    aExecute = (String)(arguments.get(0));
 
    try {
        Process exec = Runtime.getRuntime().exec( aExecute );
        ...

使用 new 创建对象

目标对象需要实现 TemplateModel 接口,不能是 BeanModel 的子类,不能是 JythonModel 子类

public ConstructorFunction(String classname, Environment env, Template template) throws TemplateException {
    this.env = env;
    cl = env.getNewBuiltinClassResolver().resolve(classname, env, template);
    if (!TemplateModel.class.isAssignableFrom(cl)) {
        throw new _MiscTemplateException(NewBI.this, env, new Object[] {
                "Class ", cl.getName(), " does not implement freemarker.template.TemplateModel" });
    }
    if (BEAN_MODEL_CLASS.isAssignableFrom(cl)) {
        throw new _MiscTemplateException(NewBI.this, env, new Object[] {
                "Bean Models cannot be instantiated using the ?", key, " built-in" });
    }
    if (JYTHON_MODEL_CLASS != null && JYTHON_MODEL_CLASS.isAssignableFrom(cl)) {
        throw new _MiscTemplateException(NewBI.this, env, new Object[] {
                "Jython Models cannot be instantiated using the ?", key, " built-in" });
    }
}

对象包装

对象包装器是实现了 freemarker.template.ObjectWrapper 接口的类。它的目标是实现 Java 对象和 FTL 类型系统之间的映射。换句话说,它指定了模板如何在数据模型(包含从模板 中调用的 Java 方法的返回值)中发现 Java 对象。对象包装器作为插件放入 Configuration 中, 可以使用 object_wrapper 属性设置 (或者使用 Configuration.setObjectWrapper)。

调用对象包装器的 wrap 方法将一个 Java 类映射成 FTL 类型,最常用的是 DefaultObjectWrapper:

public TemplateModel wrap(Object obj) throws TemplateModelException {
    if (obj == null) {
        return super.wrap(null);
    }
    if (obj instanceof TemplateModel) {
        return (TemplateModel) obj;
    }
    if (obj instanceof String) {
        return new SimpleScalar((String) obj);
    }
    if (obj instanceof Number) {
        return new SimpleNumber((Number) obj);
    }
    if (obj instanceof java.util.Date) {
        if(obj instanceof java.sql.Date) {
            return new SimpleDate((java.sql.Date) obj);
        }
        if(obj instanceof java.sql.Time) {
            return new SimpleDate((java.sql.Time) obj);
        }
        if(obj instanceof java.sql.Timestamp) {
            return new SimpleDate((java.sql.Timestamp) obj);
        }
        return new SimpleDate((java.util.Date) obj, getDefaultDateType());
    }
    final Class objClass = obj.getClass();
    if (objClass.isArray()) {
        if (useAdaptersForContainers) {
            return DefaultArrayAdapter.adapt(obj, this);
        } else {
            obj = convertArray(obj);
            // Falls through (a strange legacy...)
        }
    }
    if (obj instanceof Collection) {
        if (useAdaptersForContainers) {
            if (obj instanceof List) {
                return DefaultListAdapter.adapt((List) obj, this);
            } else {
                return forceLegacyNonListCollections
                        ? (TemplateModel) new SimpleSequence((Collection) obj, this)
                        : (TemplateModel) DefaultNonListCollectionAdapter.adapt((Collection) obj, this);
            }
        } else {
            return new SimpleSequence((Collection) obj, this);
        }
    }
    if (obj instanceof Map) {
        return useAdaptersForContainers
                ? (TemplateModel) DefaultMapAdapter.adapt((Map) obj, this)
                : (TemplateModel) new SimpleHash((Map) obj, this);
    }
    if (obj instanceof Boolean) {
        return obj.equals(Boolean.TRUE) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
    }
    if (obj instanceof Iterator) {
        return useAdaptersForContainers
                ? (TemplateModel) DefaultIteratorAdapter.adapt((Iterator) obj, this)
                : (TemplateModel) new SimpleCollection((Iterator) obj, this);
    }
    return handleUnknownType(obj);
}