Search in sources :

Example 1 with ObjectWrapper

use of freemarker.template.ObjectWrapper in project spring-framework by spring-projects.

the class FreeMarkerView method getObjectWrapper.

/**
 * Get the configured FreeMarker {@link ObjectWrapper}, or the
 * {@linkplain ObjectWrapper#DEFAULT_WRAPPER default wrapper} if none specified.
 * @see freemarker.template.Configuration#getObjectWrapper()
 */
protected ObjectWrapper getObjectWrapper() {
    ObjectWrapper ow = obtainConfiguration().getObjectWrapper();
    Version version = Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS;
    return (ow != null ? ow : new DefaultObjectWrapperBuilder(version).build());
}
Also used : Version(freemarker.template.Version) ObjectWrapper(freemarker.template.ObjectWrapper) DefaultObjectWrapperBuilder(freemarker.template.DefaultObjectWrapperBuilder)

Example 2 with ObjectWrapper

use of freemarker.template.ObjectWrapper in project PublicCMS-preview by sanluan.

the class TemplateDirectiveHandler method reduce.

private Map<String, TemplateModel> reduce() throws TemplateModelException {
    Map<String, TemplateModel> reduceMap = new LinkedHashMap<>();
    ObjectWrapper objectWrapper = environment.getObjectWrapper();
    Namespace namespace = environment.getCurrentNamespace();
    Iterator<Entry<String, Object>> iterator = map.entrySet().iterator();
    for (int i = 0; iterator.hasNext(); i++) {
        Entry<String, Object> entry = iterator.next();
        if (i < loopVars.length) {
            loopVars[i] = objectWrapper.wrap(entry.getValue());
        } else {
            String key = entry.getKey();
            reduceMap.put(key, namespace.get(key));
            namespace.put(key, objectWrapper.wrap(entry.getValue()));
        }
    }
    return reduceMap;
}
Also used : Entry(java.util.Map.Entry) ObjectWrapper(freemarker.template.ObjectWrapper) TemplateModel(freemarker.template.TemplateModel) Namespace(freemarker.core.Environment.Namespace) LinkedHashMap(java.util.LinkedHashMap)

Example 3 with ObjectWrapper

use of freemarker.template.ObjectWrapper in project freemarker by apache.

the class Configurable method setSetting.

/**
 * Sets a FreeMarker setting by a name and string value. If you can configure FreeMarker directly with Java (or
 * other programming language), you should use the dedicated setter methods instead (like
 * {@link #setObjectWrapper(ObjectWrapper)}. This meant to be used only when you get settings from somewhere
 * as {@link String}-{@link String} name-value pairs (typically, as a {@link Properties} object). Below you find an
 * overview of the settings available.
 *
 * <p>Note: As of FreeMarker 2.3.23, setting names can be written in camel case too. For example, instead of
 * {@code date_format} you can also use {@code dateFormat}. It's likely that camel case will become to the
 * recommended convention in the future.
 *
 * <p>The list of settings commonly supported in all {@link Configurable} subclasses:
 * <ul>
 *   <li><p>{@code "locale"}:
 *       See {@link #setLocale(Locale)}.
 *       <br>String value: local codes with the usual format in Java, such as {@code "en_US"}, or since 2.3.26,
 *       "JVM default" (ignoring case) to use the default locale of the Java environment.
 *
 *   <li><p>{@code "classic_compatible"}:
 *       See {@link #setClassicCompatible(boolean)} and {@link Configurable#setClassicCompatibleAsInt(int)}.
 *       <br>String value: {@code "true"}, {@code "false"}, also since 2.3.20 {@code 0} or {@code 1} or {@code 2}.
 *       (Also accepts {@code "yes"}, {@code "no"}, {@code "t"}, {@code "f"}, {@code "y"}, {@code "n"}.)
 *       Case insensitive.
 *
 *   <li><p>{@code "custom_number_formats"}: See {@link #setCustomNumberFormats(Map)}.
 *   <br>String value: Interpreted as an <a href="#fm_obe">object builder expression</a>.
 *   <br>Example: <code>{ "hex": com.example.HexTemplateNumberFormatFactory,
 *   "gps": com.example.GPSTemplateNumberFormatFactory }</code>
 *
 *   <li><p>{@code "custom_date_formats"}: See {@link #setCustomDateFormats(Map)}.
 *   <br>String value: Interpreted as an <a href="#fm_obe">object builder expression</a>.
 *   <br>Example: <code>{ "trade": com.example.TradeTemplateDateFormatFactory,
 *   "log": com.example.LogTemplateDateFormatFactory }</code>
 *
 *   <li><p>{@code "template_exception_handler"}:
 *       See {@link #setTemplateExceptionHandler(TemplateExceptionHandler)}.
 *       <br>String value: If the value contains dot, then it's interpreted as an <a href="#fm_obe">object builder
 *       expression</a>.
 *       If the value does not contain dot, then it must be one of these predefined values (case insensitive):
 *       {@code "rethrow"} (means {@link TemplateExceptionHandler#RETHROW_HANDLER}),
 *       {@code "debug"} (means {@link TemplateExceptionHandler#DEBUG_HANDLER}),
 *       {@code "html_debug"} (means {@link TemplateExceptionHandler#HTML_DEBUG_HANDLER}),
 *       {@code "ignore"} (means {@link TemplateExceptionHandler#IGNORE_HANDLER}), or
 *       {@code "default"} (only allowed for {@link Configuration} instances) for the default value.
 *
 *   <li><p>{@code "attempt_exception_reporter"}:
 *       See {@link #setAttemptExceptionReporter(AttemptExceptionReporter)}.
 *       <br>String value: If the value contains dot, then it's interpreted as an <a href="#fm_obe">object builder
 *       expression</a>.
 *       If the value does not contain dot, then it must be one of these predefined values (case insensitive):
 *       {@code "log_error"} (means {@link AttemptExceptionReporter#LOG_ERROR_REPORTER}),
 *       {@code "log_warn"} (means {@link AttemptExceptionReporter#LOG_WARN_REPORTER}), or
 *       {@code "default"} (only allowed for {@link Configuration} instances) for the default value.
 *
 *   <li><p>{@code "arithmetic_engine"}:
 *       See {@link #setArithmeticEngine(ArithmeticEngine)}.
 *       <br>String value: If the value contains dot, then it's interpreted as an <a href="#fm_obe">object builder
 *       expression</a>.
 *       If the value does not contain dot,
 *       then it must be one of these special values (case insensitive):
 *       {@code "bigdecimal"}, {@code "conservative"}.
 *
 *   <li><p>{@code "object_wrapper"}:
 *       See {@link #setObjectWrapper(ObjectWrapper)}.
 *       <br>String value: If the value contains dot, then it's interpreted as an <a href="#fm_obe">object builder
 *       expression</a>, with the addition that {@link BeansWrapper}, {@link DefaultObjectWrapper} and
 *       {@link SimpleObjectWrapper} can be referred without package name. For example, these strings are valid
 *       values: {@code "DefaultObjectWrapper(2.3.21, forceLegacyNonListCollections=false, iterableSupport=true)"},
 *       {@code "BeansWrapper(2.3.21, simpleMapWrapper=true)"}.
 *       <br>If the value does not contain dot, then it must be one of these special values (case insensitive):
 *       {@code "default"} means the default of {@link Configuration} (the default depends on the
 *       {@code Configuration#Configuration(Version) incompatible_improvements}, but a bug existed in 2.3.21 where
 *       that was ignored),
 *       {@code "default_2_3_0"} (means the deprecated {@link ObjectWrapper#DEFAULT_WRAPPER})
 *       {@code "simple"} (means the deprecated {@link ObjectWrapper#SIMPLE_WRAPPER}),
 *       {@code "beans"} (means the deprecated {@link BeansWrapper#BEANS_WRAPPER}
 *       or {@link BeansWrapperBuilder#build()}),
 *       {@code "jython"} (means {@link freemarker.ext.jython.JythonWrapper#DEFAULT_WRAPPER})
 *
 *   <li><p>{@code "number_format"}: See {@link #setNumberFormat(String)}.
 *
 *   <li><p>{@code "boolean_format"}: See {@link #setBooleanFormat(String)} .
 *
 *   <li><p>{@code "date_format", "time_format", "datetime_format"}:
 *       See {@link #setDateFormat(String)}, {@link #setTimeFormat(String)}, {@link #setDateTimeFormat(String)}.
 *
 *   <li><p>{@code "time_zone"}:
 *       See {@link #setTimeZone(TimeZone)}.
 *       <br>String value: With the format as {@link TimeZone#getTimeZone} defines it. Also, since 2.3.21
 *       {@code "JVM default"} can be used that will be replaced with the actual JVM default time zone when
 *       {@link #setSetting(String, String)} is called.
 *       For example {@code "GMT-8:00"} or {@code "America/Los_Angeles"}
 *       <br>If you set this setting, consider setting {@code sql_date_and_time_time_zone}
 *       too (see below)!
 *
 *   <li><p>{@code sql_date_and_time_time_zone}:
 *       See {@link #setSQLDateAndTimeTimeZone(TimeZone)}.
 *       Since 2.3.21.
 *       <br>String value: With the format as {@link TimeZone#getTimeZone} defines it. Also, {@code "JVM default"}
 *       can be used that will be replaced with the actual JVM default time zone when
 *       {@link #setSetting(String, String)} is called. Also {@code "null"} can be used, which has the same effect
 *       as {@link #setSQLDateAndTimeTimeZone(TimeZone) setSQLDateAndTimeTimeZone(null)}.
 *
 *   <li><p>{@code "output_encoding"}:
 *       See {@link #setOutputEncoding(String)}.
 *
 *   <li><p>{@code "url_escaping_charset"}:
 *       See {@link #setURLEscapingCharset(String)}.
 *
 *   <li><p>{@code "auto_flush"}:
 *       See {@link #setAutoFlush(boolean)}.
 *       Since 2.3.17.
 *       <br>String value: {@code "true"}, {@code "false"}, {@code "y"},  etc.
 *
 *   <li><p>{@code "auto_import"}:
 *       See {@link Configuration#setAutoImports(Map)}
 *       <br>String value is something like:
 *       <br>{@code /lib/form.ftl as f, /lib/widget as w, "/lib/odd name.ftl" as odd}
 *
 *   <li><p>{@code "auto_include"}: Sets the list of auto-includes.
 *       See {@link Configuration#setAutoIncludes(List)}
 *       <br>String value is something like:
 *       <br>{@code /include/common.ftl, "/include/evil name.ftl"}
 *
 *   <li><p>{@code "lazy_auto_imports"}:
 *       See {@link Configuration#setLazyAutoImports(Boolean)}.
 *       <br>String value: {@code "true"}, {@code "false"} (also the equivalents: {@code "yes"}, {@code "no"},
 *       {@code "t"}, {@code "f"}, {@code "y"}, {@code "n"}), case insensitive. Also can be {@code "null"}.
 *
 *   <li><p>{@code "lazy_imports"}:
 *       See {@link Configuration#setLazyImports(boolean)}.
 *       <br>String value: {@code "true"}, {@code "false"} (also the equivalents: {@code "yes"}, {@code "no"},
 *       {@code "t"}, {@code "f"}, {@code "y"}, {@code "n"}), case insensitive.
 *
 *   <li><p>{@code "new_builtin_class_resolver"}:
 *       See {@link #setNewBuiltinClassResolver(TemplateClassResolver)}.
 *       Since 2.3.17.
 *       The value must be one of these (ignore the quotation marks):
 *       <ol>
 *         <li><p>{@code "unrestricted"}:
 *             Use {@link TemplateClassResolver#UNRESTRICTED_RESOLVER}
 *         <li><p>{@code "safer"}:
 *             Use {@link TemplateClassResolver#SAFER_RESOLVER}
 *         <li><p>{@code "allows_nothing"} (or {@code "allowsNothing"}):
 *             Use {@link TemplateClassResolver#ALLOWS_NOTHING_RESOLVER}
 *         <li><p>Something that contains colon will use
 *             {@link OptInTemplateClassResolver} and is expected to
 *             store comma separated values (possibly quoted) segmented
 *             with {@code "allowed_classes:"} (or {@code "allowedClasses:"}) and/or
 *             {@code "trusted_templates:"} (or {@code "trustedTemplates:"}). Examples of valid values:
 *
 *             <table style="width: auto; border-collapse: collapse" border="1"
 *                  summary="trusted_template value examples">
 *               <tr>
 *                 <th>Setting value
 *                 <th>Meaning
 *               <tr>
 *                 <td>
 *                   {@code allowed_classes: com.example.C1, com.example.C2,
 *                   trusted_templates: lib/*, safe.ftl}
 *                 <td>
 *                   Only allow instantiating the {@code com.example.C1} and
 *                   {@code com.example.C2} classes. But, allow templates
 *                   within the {@code lib/} directory (like
 *                   {@code lib/foo/bar.ftl}) and template {@code safe.ftl}
 *                   (that does not match {@code foo/safe.ftl}, only
 *                   exactly {@code safe.ftl}) to instantiate anything
 *                   that {@link TemplateClassResolver#SAFER_RESOLVER} allows.
 *               <tr>
 *                 <td>
 *                   {@code allowed_classes: com.example.C1, com.example.C2}
 *                 <td>Only allow instantiating the {@code com.example.C1} and
 *                   {@code com.example.C2} classes. There are no
 *                   trusted templates.
 *               <tr>
 *                 <td>
 *                         {@code trusted_templates: lib/*, safe.ftl}
 *                 <td>
 *                   Do not allow instantiating any classes, except in
 *                   templates inside {@code lib/} or in template
 *                   {@code safe.ftl}.
 *             </table>
 *
 *             <p>For more details see {@link OptInTemplateClassResolver}.
 *
 *         <li><p>Otherwise if the value contains dot, it's interpreted as an <a href="#fm_obe">object builder
 *             expression</a>.
 *       </ol>
 *
 *   <li><p>{@code "show_error_tips"}:
 *       See {@link #setShowErrorTips(boolean)}.
 *       Since 2.3.21.
 *       <br>String value: {@code "true"}, {@code "false"}, {@code "y"},  etc.
 *
 *   <li><p>{@code api_builtin_enabled}:
 *       See {@link #setAPIBuiltinEnabled(boolean)}.
 *       Since 2.3.22.
 *       <br>String value: {@code "true"}, {@code "false"}, {@code "y"},  etc.
 *
 * </ul>
 *
 * <p>{@link Configuration} (a subclass of {@link Configurable}) also understands these:</p>
 * <ul>
 *   <li><p>{@code "auto_escaping"}:
 *       See {@link Configuration#setAutoEscapingPolicy(int)}
 *       <br>String value: {@code "enable_if_default"} or {@code "enableIfDefault"} for
 *       {@link Configuration#ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY},
 *       {@code "enable_if_supported"} or {@code "enableIfSupported"} for
 *       {@link Configuration#ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY}
 *       {@code "disable"} for {@link Configuration#DISABLE_AUTO_ESCAPING_POLICY}.
 *
 *   <li><p>{@code "default_encoding"}:
 *       See {@link Configuration#setDefaultEncoding(String)}; since 2.3.26 also accepts value "JVM default"
 *       (not case sensitive) to set the Java environment default value.
 *       <br>As the default value is the system default, which can change
 *       from one server to another, <b>you should always set this!</b>
 *
 *   <li><p>{@code "localized_lookup"}:
 *       See {@link Configuration#setLocalizedLookup}.
 *       <br>String value: {@code "true"}, {@code "false"} (also the equivalents: {@code "yes"}, {@code "no"},
 *       {@code "t"}, {@code "f"}, {@code "y"}, {@code "n"}).
 *       Case insensitive.
 *
 *   <li><p>{@code "output_format"}:
 *       See {@link Configuration#setOutputFormat(OutputFormat)}.
 *       <br>String value: {@code "default"} (case insensitive) for the default, or an
 *       <a href="#fm_obe">object builder expression</a> that gives an {@link OutputFormat}, for example
 *       {@code HTMLOutputFormat} or {@code XMLOutputFormat}.
 *
 *   <li><p>{@code "registered_custom_output_formats"}:
 *       See {@link Configuration#setRegisteredCustomOutputFormats(Collection)}.
 *       <br>String value: an <a href="#fm_obe">object builder expression</a> that gives a {@link List} of
 *       {@link OutputFormat}-s.
 *       Example: {@code [com.example.MyOutputFormat(), com.example.MyOtherOutputFormat()]}
 *
 *   <li><p>{@code "strict_syntax"}:
 *       See {@link Configuration#setStrictSyntaxMode}. Deprecated.
 *       <br>String value: {@code "true"}, {@code "false"}, {@code yes}, etc.
 *
 *   <li><p>{@code "whitespace_stripping"}:
 *       See {@link Configuration#setWhitespaceStripping}.
 *       <br>String value: {@code "true"}, {@code "false"}, {@code yes}, etc.
 *
 *   <li><p>{@code "cache_storage"}:
 *       See {@link Configuration#setCacheStorage}.
 *       <br>String value: If the value contains dot, then it's interpreted as an <a href="#fm_obe">object builder
 *       expression</a>.
 *       If the value does not contain dot,
 *       then a {@link freemarker.cache.MruCacheStorage} will be used with the
 *       maximum strong and soft sizes specified with the setting value. Examples
 *       of valid setting values:
 *
 *       <table style="width: auto; border-collapse: collapse" border="1" summary="cache_storage value examples">
 *         <tr><th>Setting value<th>max. strong size<th>max. soft size
 *         <tr><td>{@code "strong:50, soft:500"}<td>50<td>500
 *         <tr><td>{@code "strong:100, soft"}<td>100<td>{@code Integer.MAX_VALUE}
 *         <tr><td>{@code "strong:100"}<td>100<td>0
 *         <tr><td>{@code "soft:100"}<td>0<td>100
 *         <tr><td>{@code "strong"}<td>{@code Integer.MAX_VALUE}<td>0
 *         <tr><td>{@code "soft"}<td>0<td>{@code Integer.MAX_VALUE}
 *       </table>
 *
 *       <p>The value is not case sensitive. The order of <tt>soft</tt> and <tt>strong</tt>
 *       entries is not significant.
 *
 *   <li><p>{@code "template_update_delay"}:
 *       Template update delay in <b>seconds</b> (not in milliseconds) if no unit is specified; see
 *       {@link Configuration#setTemplateUpdateDelayMilliseconds(long)} for more.
 *       <br>String value: Valid positive integer, optionally followed by a time unit (recommended). The default
 *       unit is seconds. It's strongly recommended to specify the unit for clarity, like in "500 ms" or "30 s".
 *       Supported units are: "s" (seconds), "ms" (milliseconds), "m" (minutes), "h" (hours). The whitespace between
 *       the unit and the number is optional. Units are only supported since 2.3.23.
 *
 *   <li><p>{@code "tag_syntax"}:
 *       See {@link Configuration#setTagSyntax(int)}.
 *       <br>String value: Must be one of
 *       {@code "auto_detect"}, {@code "angle_bracket"}, and {@code "square_bracket"} (like {@code [#if x]}).
 *       <br>Note that setting the {@code "tagSyntax"} to {@code "square_bracket"} does <em>not</em> change
 *       <code>${x}</code> to {@code [=...]}; that's <em>interpolation</em> syntax, so use the
 *       {@code "interpolation_syntax"} setting for that, not this setting.
 *
 *   <li><p>{@code "interpolation_syntax"} (since 2.3.28):
 *       See {@link Configuration#setInterpolationSyntax(int)}.
 *       <br>String value: Must be one of
 *       {@code "legacy"}, {@code "dollar"}, and {@code "square_bracket"} (like {@code [=x]}).
 *       <br>Note that setting the {@code "interpolation_syntax"} to {@code "square_bracket"} does <em>not</em>
 *       change {@code <#if x>} to {@code [#if x]}; that's <em>tag</em> syntax, so use the
 *       {@code "tag_syntax"} setting for that, not this setting.
 *
 *   <li><p>{@code "naming_convention"}:
 *       See {@link Configuration#setNamingConvention(int)}.
 *       <br>String value: Must be one of
 *       {@code "auto_detect"}, {@code "legacy"}, and {@code "camel_case"}.
 *
 *   <li><p>{@code "incompatible_improvements"}:
 *       See {@link Configuration#setIncompatibleImprovements(Version)}.
 *       <br>String value: version number like {@code 2.3.20}.
 *
 *   <li><p>{@code "incompatible_enhancements"}:
 *       See: {@link Configuration#setIncompatibleEnhancements(String)}.
 *       This setting name is deprecated, use {@code "incompatible_improvements"} instead.
 *
 *   <li><p>{@code "recognize_standard_file_extensions"}:
 *       See {@link Configuration#setRecognizeStandardFileExtensions(boolean)}.
 *       <br>String value: {@code "default"} (case insensitive) for the default, or {@code "true"}, {@code "false"},
 *       {@code yes}, etc.
 *
 *   <li><p>{@code "template_configurations"}:
 *       See: {@link Configuration#setTemplateConfigurations(freemarker.cache.TemplateConfigurationFactory)}.
 *       <br>String value: Interpreted as an <a href="#fm_obe">object builder expression</a>,
 *       can be {@code null}.
 *
 *   <li><p>{@code "template_loader"}:
 *       See: {@link Configuration#setTemplateLoader(TemplateLoader)}.
 *       <br>String value: {@code "default"} (case insensitive) for the default, or else interpreted as an
 *       <a href="#fm_obe">object builder expression</a>. {@code "null"} is also allowed since 2.3.26.
 *
 *   <li><p>{@code "template_lookup_strategy"}:
 *       See: {@link Configuration#setTemplateLookupStrategy(freemarker.cache.TemplateLookupStrategy)}.
 *       <br>String value: {@code "default"} (case insensitive) for the default, or else interpreted as an
 *       <a href="#fm_obe">object builder expression</a>.
 *
 *   <li><p>{@code "template_name_format"}:
 *       See: {@link Configuration#setTemplateNameFormat(freemarker.cache.TemplateNameFormat)}.
 *       <br>String value: {@code "default"} (case insensitive) for the default, {@code "default_2_3_0"}
 *       for {@link freemarker.cache.TemplateNameFormat#DEFAULT_2_3_0}, {@code "default_2_4_0"} for
 *       {@link freemarker.cache.TemplateNameFormat#DEFAULT_2_4_0}.
 * </ul>
 *
 * <p><a name="fm_obe"></a>Regarding <em>object builder expressions</em> (used by the setting values where it was
 * indicated):
 * <ul>
 *   <li><p>Before FreeMarker 2.3.21 it had to be a fully qualified class name, and nothing else.</li>
 *   <li><p>Since 2.3.21, the generic syntax is:
 *       <tt><i>className</i>(<i>constrArg1</i>, <i>constrArg2</i>, ... <i>constrArgN</i>,
 *       <i>propName1</i>=<i>propValue1</i>, <i>propName2</i>=<i>propValue2</i>, ...
 *       <i>propNameN</i>=<i>propValueN</i>)</tt>,
 *       where
 *       <tt><i>className</i></tt> is the fully qualified class name of the instance to create (except if we have
 *       builder class or <tt>INSTANCE</tt> field around, but see that later),
 *       <tt><i>constrArg</i></tt>-s are the values of constructor arguments,
 *       and <tt><i>propName</i>=<i>propValue</i></tt>-s set JavaBean properties (like <tt>x=1</tt> means
 *       <tt>setX(1)</tt>) on the created instance. You can have any number of constructor arguments and property
 *       setters, including 0. Constructor arguments must precede any property setters.
 *   </li>
 *   <li>
 *     Example: <tt>com.example.MyObjectWrapper(1, 2, exposeFields=true, cacheSize=5000)</tt> is nearly
 *     equivalent with this Java code:
 *     <tt>obj = new com.example.MyObjectWrapper(1, 2); obj.setExposeFields(true); obj.setCacheSize(5000);</tt>
 *   </li>
 *   <li>
 *      <p>If you have no constructor arguments and property setters, and the <tt><i>className</i></tt> class has
 *      a public static {@code INSTANCE} field, the value of that filed will be the value of the expression, and
 *      the constructor won't be called. Note that if you use the backward compatible
 *      syntax, where these's no parenthesis after the class name, then it will not look for {@code INSTANCE}.
 *   </li>
 *   <li>
 *      <p>If there exists a class named <tt><i>className</i>Builder</tt>, then that class will be instantiated
 *      instead with the given constructor arguments, and the JavaBean properties of that builder instance will be
 *      set. After that, the public <tt>build()</tt> method of the instance will be called, whose return value
 *      will be the value of the whole expression. (The builder class and the <tt>build()</tt> method is simply
 *      found by name, there's no special interface to implement.) Note that if you use the backward compatible
 *      syntax, where these's no parenthesis after the class name, then it will not look for builder class. Note
 *      that if you have a builder class, you don't actually need a <tt><i>className</i></tt> class (since 2.3.24);
 *      after all, <tt><i>className</i>Builder.build()</tt> can return any kind of object.
 *   </li>
 *   <li>
 *      <p>Currently, the values of arguments and properties can only be one of these:
 *      <ul>
 *        <li>A numerical literal, like {@code 123} or {@code -1.5}. The value will be automatically converted to
 *        the type of the target (just like in FTL). However, a target type is only available if the number will
 *        be a parameter to a method or constructor, not when it's a value (or key) in a {@code List} or
 *        {@code Map} literal. Thus in the last case the type of number will be like in Java language, like
 *        {@code 1} is an {@code int}, and {@code 1.0} is a {@code double}, and {@code 1.0f} is a {@code float},
 *        etc. In all cases, the standard Java type postfixes can be used ("f", "d", "l"), plus "bd" for
 *        {@code BigDecimal} and "bi" for {@code BigInteger}.</li>
 *        <li>A boolean literal: {@code true} or {@code false}
 *        <li>The null literal: {@code null}
 *        <li>A string literal with FTL syntax, except that  it can't contain <tt>${...}</tt>-s and
 *            <tt>#{...}</tt>-s. Examples: {@code "Line 1\nLine 2"} or {@code r"C:\temp"}.
 *        <li>A list literal (since 2.3.24) with FTL-like syntax, for example {@code [ 'foo', 2, true ]}.
 *            If the parameter is expected to be array, the list will be automatically converted to array.
 *            The list items can be any kind of expression, like even object builder expressions.
 *        <li>A map literal (since 2.3.24) with FTL-like syntax, for example <code>{ 'foo': 2, 'bar': true }</code>.
 *            The keys and values can be any kind of expression, like even object builder expressions.
 *            The resulting Java object will be a {@link Map} that keeps the item order ({@link LinkedHashMap} as
 *            of this writing).
 *        <li>A reference to a public static filed, like {@code Configuration.AUTO_DETECT_TAG_SYNTAX} or
 *            {@code com.example.MyClass.MY_CONSTANT}.
 *        <li>An object builder expression. That is, object builder expressions can be nested into each other.
 *      </ul>
 *   </li>
 *   <li>
 *     The same kind of expression as for parameters can also be used as top-level expressions (though it's
 *     rarely useful, apart from using {@code null}).
 *   </li>
 *   <li>
 *     <p>The top-level object builder expressions may omit {@code ()}. In that case, for backward compatibility,
 *     the {@code INSTANCE} field and the builder class is not searched, so the instance will be always
 *     created with its parameterless constructor. (This behavior will possibly change in 2.4.) The {@code ()}
 *     can't be omitted for nested expressions.
 *   </li>
 *   <li>
 *     <p>The following classes can be referred to with simple (unqualified) name instead of fully qualified name:
 *     {@link DefaultObjectWrapper}, {@link BeansWrapper}, {@link SimpleObjectWrapper}, {@link Locale},
 *     {@link TemplateConfiguration}, {@link PathGlobMatcher}, {@link FileNameGlobMatcher}, {@link PathRegexMatcher},
 *     {@link AndMatcher}, {@link OrMatcher}, {@link NotMatcher}, {@link ConditionalTemplateConfigurationFactory},
 *     {@link MergingTemplateConfigurationFactory}, {@link FirstMatchTemplateConfigurationFactory},
 *     {@link HTMLOutputFormat}, {@link XMLOutputFormat}, {@link RTFOutputFormat}, {@link PlainTextOutputFormat},
 *     {@link UndefinedOutputFormat}, {@link Configuration}.
 *   </li>
 *   <li>
 *     <p>{@link TimeZone} objects can be created like {@code TimeZone("UTC")}, despite that there's no a such
 *     constructor (since 2.3.24).
 *   </li>
 *   <li>
 *     <p>The classes and methods that the expression meant to access must be all public.
 *   </li>
 * </ul>
 *
 * @param name the name of the setting.
 * @param value the string that describes the new value of the setting.
 *
 * @throws UnknownSettingException if the name is wrong.
 * @throws TemplateException if the new value of the setting can't be set for any other reasons.
 */
public void setSetting(String name, String value) throws TemplateException {
    boolean unknown = false;
    try {
        if (LOCALE_KEY.equals(name)) {
            if (JVM_DEFAULT.equalsIgnoreCase(value)) {
                setLocale(Locale.getDefault());
            } else {
                setLocale(StringUtil.deduceLocale(value));
            }
        } else if (NUMBER_FORMAT_KEY_SNAKE_CASE.equals(name) || NUMBER_FORMAT_KEY_CAMEL_CASE.equals(name)) {
            setNumberFormat(value);
        } else if (CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE.equals(name) || CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE.equals(name)) {
            Map map = (Map) _ObjectBuilderSettingEvaluator.eval(value, Map.class, false, _SettingEvaluationEnvironment.getCurrent());
            _CoreAPI.checkSettingValueItemsType("Map keys", String.class, map.keySet());
            _CoreAPI.checkSettingValueItemsType("Map values", TemplateNumberFormatFactory.class, map.values());
            setCustomNumberFormats(map);
        } else if (TIME_FORMAT_KEY_SNAKE_CASE.equals(name) || TIME_FORMAT_KEY_CAMEL_CASE.equals(name)) {
            setTimeFormat(value);
        } else if (DATE_FORMAT_KEY_SNAKE_CASE.equals(name) || DATE_FORMAT_KEY_CAMEL_CASE.equals(name)) {
            setDateFormat(value);
        } else if (DATETIME_FORMAT_KEY_SNAKE_CASE.equals(name) || DATETIME_FORMAT_KEY_CAMEL_CASE.equals(name)) {
            setDateTimeFormat(value);
        } else if (CUSTOM_DATE_FORMATS_KEY_SNAKE_CASE.equals(name) || CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE.equals(name)) {
            Map map = (Map) _ObjectBuilderSettingEvaluator.eval(value, Map.class, false, _SettingEvaluationEnvironment.getCurrent());
            _CoreAPI.checkSettingValueItemsType("Map keys", String.class, map.keySet());
            _CoreAPI.checkSettingValueItemsType("Map values", TemplateDateFormatFactory.class, map.values());
            setCustomDateFormats(map);
        } else if (TIME_ZONE_KEY_SNAKE_CASE.equals(name) || TIME_ZONE_KEY_CAMEL_CASE.equals(name)) {
            setTimeZone(parseTimeZoneSettingValue(value));
        } else if (SQL_DATE_AND_TIME_TIME_ZONE_KEY_SNAKE_CASE.equals(name) || SQL_DATE_AND_TIME_TIME_ZONE_KEY_CAMEL_CASE.equals(name)) {
            setSQLDateAndTimeTimeZone(value.equals("null") ? null : parseTimeZoneSettingValue(value));
        } else if (CLASSIC_COMPATIBLE_KEY_SNAKE_CASE.equals(name) || CLASSIC_COMPATIBLE_KEY_CAMEL_CASE.equals(name)) {
            char firstChar;
            if (value != null && value.length() > 0) {
                firstChar = value.charAt(0);
            } else {
                firstChar = 0;
            }
            if (Character.isDigit(firstChar) || firstChar == '+' || firstChar == '-') {
                setClassicCompatibleAsInt(Integer.parseInt(value));
            } else {
                setClassicCompatible(value != null ? StringUtil.getYesNo(value) : false);
            }
        } else if (TEMPLATE_EXCEPTION_HANDLER_KEY_SNAKE_CASE.equals(name) || TEMPLATE_EXCEPTION_HANDLER_KEY_CAMEL_CASE.equals(name)) {
            if (value.indexOf('.') == -1) {
                if ("debug".equalsIgnoreCase(value)) {
                    setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
                } else if ("html_debug".equalsIgnoreCase(value) || "htmlDebug".equals(value)) {
                    setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
                } else if ("ignore".equalsIgnoreCase(value)) {
                    setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
                } else if ("rethrow".equalsIgnoreCase(value)) {
                    setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
                } else if (DEFAULT.equalsIgnoreCase(value) && this instanceof Configuration) {
                    ((Configuration) this).unsetTemplateExceptionHandler();
                } else {
                    throw invalidSettingValueException(name, value);
                }
            } else {
                setTemplateExceptionHandler((TemplateExceptionHandler) _ObjectBuilderSettingEvaluator.eval(value, TemplateExceptionHandler.class, false, _SettingEvaluationEnvironment.getCurrent()));
            }
        } else if (ATTEMPT_EXCEPTION_REPORTER_KEY_SNAKE_CASE.equals(name) || ATTEMPT_EXCEPTION_REPORTER_KEY_CAMEL_CASE.equals(name)) {
            if (value.indexOf('.') == -1) {
                if ("log_error".equalsIgnoreCase(value) || "logError".equals(value)) {
                    setAttemptExceptionReporter(AttemptExceptionReporter.LOG_ERROR_REPORTER);
                } else if ("log_warn".equalsIgnoreCase(value) || "logWarn".equals(value)) {
                    setAttemptExceptionReporter(AttemptExceptionReporter.LOG_WARN_REPORTER);
                } else if (DEFAULT.equalsIgnoreCase(value) && this instanceof Configuration) {
                    ((Configuration) this).unsetAttemptExceptionReporter();
                } else {
                    throw invalidSettingValueException(name, value);
                }
            } else {
                setAttemptExceptionReporter((AttemptExceptionReporter) _ObjectBuilderSettingEvaluator.eval(value, AttemptExceptionReporter.class, false, _SettingEvaluationEnvironment.getCurrent()));
            }
        } else if (ARITHMETIC_ENGINE_KEY_SNAKE_CASE.equals(name) || ARITHMETIC_ENGINE_KEY_CAMEL_CASE.equals(name)) {
            if (value.indexOf('.') == -1) {
                if ("bigdecimal".equalsIgnoreCase(value)) {
                    setArithmeticEngine(ArithmeticEngine.BIGDECIMAL_ENGINE);
                } else if ("conservative".equalsIgnoreCase(value)) {
                    setArithmeticEngine(ArithmeticEngine.CONSERVATIVE_ENGINE);
                } else {
                    throw invalidSettingValueException(name, value);
                }
            } else {
                setArithmeticEngine((ArithmeticEngine) _ObjectBuilderSettingEvaluator.eval(value, ArithmeticEngine.class, false, _SettingEvaluationEnvironment.getCurrent()));
            }
        } else if (OBJECT_WRAPPER_KEY_SNAKE_CASE.equals(name) || OBJECT_WRAPPER_KEY_CAMEL_CASE.equals(name)) {
            if (DEFAULT.equalsIgnoreCase(value)) {
                if (this instanceof Configuration) {
                    ((Configuration) this).unsetObjectWrapper();
                } else {
                    setObjectWrapper(Configuration.getDefaultObjectWrapper(Configuration.VERSION_2_3_0));
                }
            } else if (DEFAULT_2_3_0.equalsIgnoreCase(value)) {
                setObjectWrapper(Configuration.getDefaultObjectWrapper(Configuration.VERSION_2_3_0));
            } else if ("simple".equalsIgnoreCase(value)) {
                setObjectWrapper(ObjectWrapper.SIMPLE_WRAPPER);
            } else if ("beans".equalsIgnoreCase(value)) {
                setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
            } else if ("jython".equalsIgnoreCase(value)) {
                Class clazz = Class.forName("freemarker.ext.jython.JythonWrapper");
                setObjectWrapper((ObjectWrapper) clazz.getField("INSTANCE").get(null));
            } else {
                setObjectWrapper((ObjectWrapper) _ObjectBuilderSettingEvaluator.eval(value, ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent()));
            }
        } else if (BOOLEAN_FORMAT_KEY_SNAKE_CASE.equals(name) || BOOLEAN_FORMAT_KEY_CAMEL_CASE.equals(name)) {
            setBooleanFormat(value);
        } else if (OUTPUT_ENCODING_KEY_SNAKE_CASE.equals(name) || OUTPUT_ENCODING_KEY_CAMEL_CASE.equals(name)) {
            setOutputEncoding(value);
        } else if (URL_ESCAPING_CHARSET_KEY_SNAKE_CASE.equals(name) || URL_ESCAPING_CHARSET_KEY_CAMEL_CASE.equals(name)) {
            setURLEscapingCharset(value);
        } else if (STRICT_BEAN_MODELS_KEY_SNAKE_CASE.equals(name) || STRICT_BEAN_MODELS_KEY_CAMEL_CASE.equals(name)) {
            setStrictBeanModels(StringUtil.getYesNo(value));
        } else if (AUTO_FLUSH_KEY_SNAKE_CASE.equals(name) || AUTO_FLUSH_KEY_CAMEL_CASE.equals(name)) {
            setAutoFlush(StringUtil.getYesNo(value));
        } else if (SHOW_ERROR_TIPS_KEY_SNAKE_CASE.equals(name) || SHOW_ERROR_TIPS_KEY_CAMEL_CASE.equals(name)) {
            setShowErrorTips(StringUtil.getYesNo(value));
        } else if (API_BUILTIN_ENABLED_KEY_SNAKE_CASE.equals(name) || API_BUILTIN_ENABLED_KEY_CAMEL_CASE.equals(name)) {
            setAPIBuiltinEnabled(StringUtil.getYesNo(value));
        } else if (NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE.equals(name) || NEW_BUILTIN_CLASS_RESOLVER_KEY_CAMEL_CASE.equals(name)) {
            if ("unrestricted".equals(value)) {
                setNewBuiltinClassResolver(TemplateClassResolver.UNRESTRICTED_RESOLVER);
            } else if ("safer".equals(value)) {
                setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
            } else if ("allows_nothing".equals(value) || "allowsNothing".equals(value)) {
                setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
            } else if (value.indexOf(":") != -1) {
                List segments = parseAsSegmentedList(value);
                Set allowedClasses = null;
                List trustedTemplates = null;
                for (int i = 0; i < segments.size(); i++) {
                    KeyValuePair kv = (KeyValuePair) segments.get(i);
                    String segmentKey = (String) kv.getKey();
                    List segmentValue = (List) kv.getValue();
                    if (segmentKey.equals(ALLOWED_CLASSES_SNAKE_CASE) || segmentKey.equals(ALLOWED_CLASSES_CAMEL_CASE)) {
                        allowedClasses = new HashSet(segmentValue);
                    } else if (segmentKey.equals(TRUSTED_TEMPLATES_SNAKE_CASE) || segmentKey.equals(TRUSTED_TEMPLATES_CAMEL_CASE)) {
                        trustedTemplates = segmentValue;
                    } else {
                        throw new ParseException("Unrecognized list segment key: " + StringUtil.jQuote(segmentKey) + ". Supported keys are: " + "\"" + ALLOWED_CLASSES_SNAKE_CASE + "\", " + "\"" + ALLOWED_CLASSES_CAMEL_CASE + "\", " + "\"" + TRUSTED_TEMPLATES_SNAKE_CASE + "\", " + "\"" + TRUSTED_TEMPLATES_CAMEL_CASE + "\". ", 0, 0);
                    }
                }
                setNewBuiltinClassResolver(new OptInTemplateClassResolver(allowedClasses, trustedTemplates));
            } else if ("allow_nothing".equals(value)) {
                throw new IllegalArgumentException("The correct value would be: allows_nothing");
            } else if ("allowNothing".equals(value)) {
                throw new IllegalArgumentException("The correct value would be: allowsNothing");
            } else if (value.indexOf('.') != -1) {
                setNewBuiltinClassResolver((TemplateClassResolver) _ObjectBuilderSettingEvaluator.eval(value, TemplateClassResolver.class, false, _SettingEvaluationEnvironment.getCurrent()));
            } else {
                throw invalidSettingValueException(name, value);
            }
        } else if (LOG_TEMPLATE_EXCEPTIONS_KEY_SNAKE_CASE.equals(name) || LOG_TEMPLATE_EXCEPTIONS_KEY_CAMEL_CASE.equals(name)) {
            setLogTemplateExceptions(StringUtil.getYesNo(value));
        } else if (WRAP_UNCHECKED_EXCEPTIONS_KEY_SNAKE_CASE.equals(name) || WRAP_UNCHECKED_EXCEPTIONS_KEY_CAMEL_CASE.equals(name)) {
            setWrapUncheckedExceptions(StringUtil.getYesNo(value));
        } else if (LAZY_AUTO_IMPORTS_KEY_SNAKE_CASE.equals(name) || LAZY_AUTO_IMPORTS_KEY_CAMEL_CASE.equals(name)) {
            setLazyAutoImports(value.equals(NULL) ? null : Boolean.valueOf(StringUtil.getYesNo(value)));
        } else if (LAZY_IMPORTS_KEY_SNAKE_CASE.equals(name) || LAZY_IMPORTS_KEY_CAMEL_CASE.equals(name)) {
            setLazyImports(StringUtil.getYesNo(value));
        } else if (AUTO_INCLUDE_KEY_SNAKE_CASE.equals(name) || AUTO_INCLUDE_KEY_CAMEL_CASE.equals(name)) {
            setAutoIncludes(parseAsList(value));
        } else if (AUTO_IMPORT_KEY_SNAKE_CASE.equals(name) || AUTO_IMPORT_KEY_CAMEL_CASE.equals(name)) {
            setAutoImports(parseAsImportList(value));
        } else {
            unknown = true;
        }
    } catch (Exception e) {
        throw settingValueAssignmentException(name, value, e);
    }
    if (unknown) {
        throw unknownSettingException(name);
    }
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) Configuration(freemarker.template.Configuration) AttemptExceptionReporter(freemarker.template.AttemptExceptionReporter) TemplateException(freemarker.template.TemplateException) NullArgumentException(freemarker.template.utility.NullArgumentException) IOException(java.io.IOException) DefaultObjectWrapper(freemarker.template.DefaultObjectWrapper) SimpleObjectWrapper(freemarker.template.SimpleObjectWrapper) ObjectWrapper(freemarker.template.ObjectWrapper) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 4 with ObjectWrapper

use of freemarker.template.ObjectWrapper in project freemarker by apache.

the class Environment method setMacroContextLocalsFromArguments.

/**
 * Sets the local variables corresponding to the macro call arguments in the macro context.
 */
private void setMacroContextLocalsFromArguments(final Macro.Context macroCtx, final Macro macro, final Map namedArgs, final List positionalArgs) throws TemplateException, _MiscTemplateException {
    String catchAllParamName = macro.getCatchAll();
    if (namedArgs != null) {
        final SimpleHash catchAllParamValue;
        if (catchAllParamName != null) {
            catchAllParamValue = new SimpleHash((ObjectWrapper) null);
            macroCtx.setLocalVar(catchAllParamName, catchAllParamValue);
        } else {
            catchAllParamValue = null;
        }
        for (Iterator it = namedArgs.entrySet().iterator(); it.hasNext(); ) {
            final Map.Entry argNameAndValExp = (Map.Entry) it.next();
            final String argName = (String) argNameAndValExp.getKey();
            final boolean isArgNameDeclared = macro.hasArgNamed(argName);
            if (isArgNameDeclared || catchAllParamName != null) {
                Expression argValueExp = (Expression) argNameAndValExp.getValue();
                TemplateModel argValue = argValueExp.eval(this);
                if (isArgNameDeclared) {
                    macroCtx.setLocalVar(argName, argValue);
                } else {
                    catchAllParamValue.put(argName, argValue);
                }
            } else {
                throw new _MiscTemplateException(this, (macro.isFunction() ? "Function " : "Macro "), new _DelayedJQuote(macro.getName()), " has no parameter with name ", new _DelayedJQuote(argName), ".");
            }
        }
    } else if (positionalArgs != null) {
        final SimpleSequence catchAllParamValue;
        if (catchAllParamName != null) {
            catchAllParamValue = new SimpleSequence((ObjectWrapper) null);
            macroCtx.setLocalVar(catchAllParamName, catchAllParamValue);
        } else {
            catchAllParamValue = null;
        }
        String[] argNames = macro.getArgumentNamesInternal();
        final int argsCnt = positionalArgs.size();
        if (argNames.length < argsCnt && catchAllParamName == null) {
            throw new _MiscTemplateException(this, (macro.isFunction() ? "Function " : "Macro "), new _DelayedJQuote(macro.getName()), " only accepts ", new _DelayedToString(argNames.length), " parameters, but got ", new _DelayedToString(argsCnt), ".");
        }
        for (int i = 0; i < argsCnt; i++) {
            Expression argValueExp = (Expression) positionalArgs.get(i);
            TemplateModel argValue = argValueExp.eval(this);
            try {
                if (i < argNames.length) {
                    String argName = argNames[i];
                    macroCtx.setLocalVar(argName, argValue);
                } else {
                    catchAllParamValue.add(argValue);
                }
            } catch (RuntimeException re) {
                throw new _MiscTemplateException(re, this);
            }
        }
    }
}
Also used : TemplateModel(freemarker.template.TemplateModel) SimpleSequence(freemarker.template.SimpleSequence) SimpleHash(freemarker.template.SimpleHash) Iterator(java.util.Iterator) TemplateModelIterator(freemarker.template.TemplateModelIterator) ObjectWrapper(freemarker.template.ObjectWrapper) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap)

Example 5 with ObjectWrapper

use of freemarker.template.ObjectWrapper in project freemarker by apache.

the class DeepUnwrap method unwrap.

private static Object unwrap(TemplateModel model, boolean permissive) throws TemplateModelException {
    Environment env = Environment.getCurrentEnvironment();
    TemplateModel nullModel = null;
    if (env != null) {
        ObjectWrapper wrapper = env.getObjectWrapper();
        if (wrapper != null) {
            nullModel = wrapper.wrap(null);
        }
    }
    return unwrap(model, nullModel, permissive);
}
Also used : Environment(freemarker.core.Environment) ObjectWrapper(freemarker.template.ObjectWrapper) WrapperTemplateModel(freemarker.ext.util.WrapperTemplateModel) AdapterTemplateModel(freemarker.template.AdapterTemplateModel) TemplateModel(freemarker.template.TemplateModel)

Aggregations

ObjectWrapper (freemarker.template.ObjectWrapper)6 TemplateModel (freemarker.template.TemplateModel)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 List (java.util.List)2 Map (java.util.Map)2 Environment (freemarker.core.Environment)1 Namespace (freemarker.core.Environment.Namespace)1 WrapperTemplateModel (freemarker.ext.util.WrapperTemplateModel)1 AdapterTemplateModel (freemarker.template.AdapterTemplateModel)1 AttemptExceptionReporter (freemarker.template.AttemptExceptionReporter)1 Configuration (freemarker.template.Configuration)1 DefaultObjectWrapper (freemarker.template.DefaultObjectWrapper)1 DefaultObjectWrapperBuilder (freemarker.template.DefaultObjectWrapperBuilder)1 SimpleHash (freemarker.template.SimpleHash)1 SimpleObjectWrapper (freemarker.template.SimpleObjectWrapper)1 SimpleSequence (freemarker.template.SimpleSequence)1 TemplateException (freemarker.template.TemplateException)1 TemplateModelIterator (freemarker.template.TemplateModelIterator)1