Class Environment


  • public final class Environment
    extends Configurable
    Object that represents the runtime environment during template processing. For every invocation of a Template.process() method, a new instance of this object is created, and then discarded when process() returns. This object stores the set of temporary variables created by the template, the value of settings set by the template, the reference to the data model root, etc. Everything that is needed to fulfill the template processing job.

    Data models that need to access the Environment object that represents the template processing on the current thread can use the getCurrentEnvironment() method.

    If you need to modify or read this object before or after the process call, use Template.createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper)

    • Method Detail

      • getCurrentEnvironment

        public static Environment getCurrentEnvironment()
        Retrieves the environment object associated with the current thread, or null if there's no template processing going on in this thread. Data model implementations that need access to the environment can call this method to obtain the environment object that represents the template processing that is currently running on the current thread.
      • getMainTemplate

        public Template getMainTemplate()
        Returns the topmost Template, with other words, the one for which this Environment was created. That template will never change, like #include or macro calls don't change it. This method never returns null.
        Since:
        2.3.22
        See Also:
        getCurrentNamespace()
      • getCurrentTemplate

        public Template getCurrentTemplate()
        Returns the Template that we are "lexically" inside at the moment. This template will change when entering an #include or calling a macro or function in another template, or returning to yet another template with #nested. When you are calling a directive that's implemented in Java or a Java method from a template, the current template will be the last current template, not null. This method never returns null.
        Since:
        2.3.23
        See Also:
        getMainTemplate(), getCurrentNamespace()
      • getCurrentDirectiveCallPlace

        public DirectiveCallPlace getCurrentDirectiveCallPlace()
        Gets the currently executing custom directive's call place information, or null if there's no executing custom directive. This currently only works for calls made from templates with the <@...> syntax. This should only be called from the TemplateDirectiveModel that was invoked with <@...>, otherwise its return value is not defined by this API (it's usually null).
        Since:
        2.3.22
      • process

        public void process()
                     throws TemplateException,
                            java.io.IOException
        Processes the template to which this environment belongs to.
        Throws:
        TemplateException
        java.io.IOException
      • visit

        @Deprecated
        public void visit​(freemarker.core.TemplateElement element,
                          TemplateDirectiveModel directiveModel,
                          java.util.Map args,
                          java.util.List bodyParameterNames)
                   throws TemplateException,
                          java.io.IOException
        Deprecated.
        Should be internal API
        Throws:
        TemplateException
        java.io.IOException
      • isInAttemptBlock

        public boolean isInAttemptBlock()
        Tells if we are inside an #attempt block (but before #recover). This can be useful for TemplateExceptionHandler-s, as then they may don't want to print the error to the output, as #attempt will roll it back anyway.
        Since:
        2.3.20
      • setLocale

        public void setLocale​(java.util.Locale locale)
        Description copied from class: Configurable
        Sets the locale used for number and date formatting (among others), also the locale used for searching localized template variations when no locale was explicitly requested. On the Configuration level it defaults to the default locale of system (of the JVM), for server-side application usually you should set it explicitly in the Configuration to use the preferred locale of your application instead.
        Overrides:
        setLocale in class Configurable
        See Also:
        Configuration.getTemplate(String, Locale)
      • setSQLDateAndTimeTimeZone

        public void setSQLDateAndTimeTimeZone​(java.util.TimeZone timeZone)
        Description copied from class: Configurable
        Sets the time zone used when dealing with java.sql.Date and java.sql.Time values. It defaults to null for backward compatibility, but in most applications this should be set to the JVM default time zone (server default time zone), because that's what most JDBC drivers will use when constructing the java.sql.Date and java.sql.Time values. If this setting is null, FreeMarker will use the value of (Configurable.getTimeZone()) for java.sql.Date and java.sql.Time values, which often gives bad results.

        This setting doesn't influence the formatting of other kind of values (like of java.sql.Timestamp or plain java.util.Date values).

        To decide what value you need, a few things has to be understood:

        • Date-only and time-only values in SQL-oriented databases usually store calendar and clock field values directly (year, month, day, or hour, minute, seconds (with decimals)), as opposed to a set of points on the physical time line. Thus, unlike SQL timestamps, these values usually aren't meant to be shown differently depending on the time zone of the audience.
        • When a JDBC query has to return a date-only or time-only value, it has to convert it to a point on the physical time line, because that's what Date and its subclasses store (milliseconds since the epoch). Obviously, this is impossible to do. So JDBC just chooses a physical time which, when rendered with the JVM default time zone, will give the same field values as those stored in the database. (Actually, you can give JDBC a calendar, and so it can use other time zones too, but most application won't care using those overloads.) For example, assume that the system time zone is GMT+02:00. Then, 2014-07-12 in the database will be translated to physical time 2014-07-11 22:00:00 UTC, because that rendered in GMT+02:00 gives 2014-07-12 00:00:00. Similarly, 11:57:00 in the database will be translated to physical time 1970-01-01 09:57:00 UTC. Thus, the physical time stored in the returned value depends on the default system time zone of the JDBC client, not just on the content of the database. (This used to be the default behavior of ORM-s, like Hibernate, too.)
        • The value of the time_zone FreeMarker configuration setting sets the time zone used for the template output. For example, when a web page visitor has a preferred time zone, the web application framework may calls setTimeZone(TimeZone) with that time zone. Thus, the visitor will see java.sql.Timestamp and plain java.util.Date values as they look in his own time zone. While this is desirable for those types, as they meant to represent physical points on the time line, this is not necessarily desirable for date-only and time-only values. When sql_date_and_time_time_zone is null, time_zone is used for rendering all kind of date/time/dateTime values, including java.sql.Date and java.sql.Time, and then if, for example, time_zone is GMT+00:00, the values from the earlier examples will be shown as 2014-07-11 (one day off) and 09:57:00 (2 hours off). While those are the time zone correct renderings, those values are probably meant to be shown "as is".
        • You may wonder why this setting isn't simply "SQL time zone", that is, why's this time zone not applied to java.sql.Timestamp values as well. Timestamps in databases refer to a point on the physical time line, and thus doesn't have the inherent problem of date-only and time-only values. FreeMarker assumes that the JDBC driver converts time stamps coming from the database so that they store the distance from the epoch (1970-01-01 00:00:00 UTC), as requested by the Date API. Then time stamps can be safely rendered in different time zones, and thus need no special treatment.
        Overrides:
        setSQLDateAndTimeTimeZone in class Configurable
        Parameters:
        timeZone - Maybe null, in which case java.sql.Date and java.sql.Time values will be formatted in the time zone returned by Configurable.getTimeZone(). (Note that since null is an allowed value for this setting, it will not cause Configurable.getSQLDateAndTimeTimeZone() to fall back to the parent configuration.)
        See Also:
        Configurable.setTimeZone(TimeZone)
      • setOutputEncoding

        public void setOutputEncoding​(java.lang.String outputEncoding)
        Description copied from class: Configurable
        Informs FreeMarker about the charset used for the output. As FreeMarker outputs character stream (not byte stream), it's not aware of the output charset unless the software that encloses it tells it with this setting. Some templates may use FreeMarker features that require this information. Setting this to null means that the output encoding is not known.

        Defaults to null (unknown).

        Overrides:
        setOutputEncoding in class Configurable
      • applyEqualsOperatorLenient

        public boolean applyEqualsOperatorLenient​(TemplateModel leftValue,
                                                  TemplateModel rightValue)
                                           throws TemplateException
        Compares two TemplateModel-s according the rules of the FTL "==" operator, except that if the two types are incompatible, they are treated as non-equal instead of throwing an exception. Comparing dates of different types (date-only VS time-only VS date-time) will still throw an exception, however.
        Throws:
        TemplateException
        Since:
        2.3.20
      • setOut

        public void setOut​(java.io.Writer out)
      • getOut

        public java.io.Writer getOut()
      • setNumberFormat

        public void setNumberFormat​(java.lang.String formatName)
        Description copied from class: Configurable
        Sets the default number format used to convert numbers to strings. Currently, this is one of these:
        • "number": The number format returned by NumberFormat.getNumberInstance(Locale)
        • "currency": The number format returned by NumberFormat.getCurrencyInstance(Locale)
        • "percent": The number format returned by NumberFormat.getPercentInstance(Locale)
        • "computer": The number format used by FTL's c built-in (like in someNumber?c).
        • DecimalFormat pattern (like "0.##"). This syntax is extended by FreeMarker so that you can specify options like the rounding mode and the symbols used after a 2nd semicolon. For example, ",000;; roundingMode=halfUp groupingSeparator=_" will format numbers like ",000" would, but with half-up rounding mode, and _ as the group separator. See more about "extended Java decimal format" in the FreeMarker Manual.
        • If the string starts with @ character followed by a letter then it's interpreted as a custom number format, but only if either Configuration.getIncompatibleImprovements() is at least 2.3.24, or there's any custom formats defined (even if custom date/time/dateTime format). The format of a such string is "@name" or "@name parameters", where name is the key in the Map set by Configurable.setCustomNumberFormats(Map), and parameters is parsed by the custom TemplateNumberFormat.

        Defaults to "number".

        Overrides:
        setNumberFormat in class Configurable
      • getTemplateNumberFormat

        public TemplateNumberFormat getTemplateNumberFormat​(java.lang.String formatString,
                                                            java.util.Locale locale)
                                                     throws TemplateValueFormatException
        Returns the number format as TemplateNumberFormat, for the given format string and locale. To get a number format for the current locale, use getTemplateNumberFormat(String) instead.

        Note on performance (which was true at least for 2.3.24): Unless the locale happens to be equal to the current locale, the Environment-level format cache can't be used, so the format string has to be parsed and the matching factory has to be get an invoked, which is much more expensive than getting the format from the cache. Thus the returned format should be stored by the caller for later reuse (but only within the current thread and in relation to the current Environment), if it will be needed frequently.

        Parameters:
        formatString - A string that you could also use as the value of the numberFormat configuration setting.
        locale - The locale of the number format; not null.
        Throws:
        TemplateValueFormatException
        Since:
        2.3.24
      • getCNumberFormat

        public java.text.NumberFormat getCNumberFormat()
        Returns the NumberFormat used for the c built-in, except, if Incompatible Improvements is less than 2.3.31, this will wrongly give the format that the c built-in used before Incompatible Improvements 2.3.21. See more at Configuration(Version).
      • setTimeFormat

        public void setTimeFormat​(java.lang.String timeFormat)
        Description copied from class: Configurable
        Sets the format used to convert Date-s that are time (no date part) values to string-s, also the format that someString?time will use to parse strings.

        For the possible values see Configurable.setDateTimeFormat(String).

        Defaults to "", which is equivalent to "medium".

        Overrides:
        setTimeFormat in class Configurable
      • setDateFormat

        public void setDateFormat​(java.lang.String dateFormat)
        Description copied from class: Configurable
        Sets the format used to convert Date-s that are date-only (no time part) values to string-s, also the format that someString?date will use to parse strings.

        For the possible values see Configurable.setDateTimeFormat(String).

        Defaults to "" which is equivalent to "medium".

        Overrides:
        setDateFormat in class Configurable
      • setDateTimeFormat

        public void setDateTimeFormat​(java.lang.String dateTimeFormat)
        Description copied from class: Configurable
        Sets the format used to convert Date-s that are date-time (timestamp) values to string-s, also the format that someString?datetime will use to parse strings.

        The possible setting values are (the quotation marks aren't part of the value itself):

        • Patterns accepted by Java's SimpleDateFormat, for example "dd.MM.yyyy HH:mm:ss" (where HH means 24 hours format) or "MM/dd/yyyy hh:mm:ss a" (where a prints AM or PM, if the current language is English).

        • "xs" for XML Schema format, or "iso" for ISO 8601:2004 format. These formats allow various additional options, separated with space, like in "iso m nz" (or with _, like in "iso_m_nz"; this is useful in a case like lastModified?string.iso_m_nz). The options and their meanings are:

          • Accuracy options:
            ms = Milliseconds, always shown with all 3 digits, even if it's all 0-s. Example: 13:45:05.800
            s = Seconds (fraction seconds are dropped even if non-0), like 13:45:05
            m = Minutes, like 13:45. This isn't allowed for "xs".
            h = Hours, like 13. This isn't allowed for "xs".
            Neither = Up to millisecond accuracy, but trailing millisecond 0-s are removed, also the whole milliseconds part if it would be 0 otherwise. Example: 13:45:05.8

          • Time zone offset visibility options:
            fz = "Force Zone", always show time zone offset (even for for java.sql.Date and java.sql.Time values). But, because ISO 8601 doesn't allow for dates (means date without time of the day) to show the zone offset, this option will have no effect in the case of "iso" with dates.
            nz = "No Zone", never show time zone offset
            Neither = always show time zone offset, except for java.sql.Date and java.sql.Time, and for "iso" date values.

          • Time zone options:
            u = Use UTC instead of what the time_zone setting suggests. However, java.sql.Date and java.sql.Time aren't affected by this (see Configurable.setSQLDateAndTimeTimeZone(TimeZone) to understand why)
            fu = "Force UTC", that is, use UTC instead of what the time_zone or the sql_date_and_time_time_zone setting suggests. This also effects java.sql.Date and java.sql.Time values
            Neither = Use the time zone suggested by the time_zone or the sql_date_and_time_time_zone configuration setting (Configurable.setTimeZone(TimeZone) and Configurable.setSQLDateAndTimeTimeZone(TimeZone)).

          The options can be specified in any order.

          Options from the same category are mutually exclusive, like using m and s together is an error.

          The accuracy and time zone offset visibility options don't influence parsing, only formatting. For example, even if you use "iso m nz", "2012-01-01T15:30:05.125+01" will be parsed successfully and with milliseconds accuracy. The time zone options (like "u") influence what time zone is chosen only when parsing a string that doesn't contain time zone offset.

          Parsing with "iso" understands both extend format and basic format, like 20141225T235018. It doesn't, however, support the parsing of all kind of ISO 8601 strings: if there's a date part, it must use year, month and day of the month values (not week of the year), and the day can't be omitted.

          The output of "iso" is deliberately so that it's also a good representation of the value with XML Schema format, except for 0 and negative years, where it's impossible. Also note that the time zone offset is omitted for date values in the "iso" format, while it's preserved for the "xs" format.

        • "short", "medium", "long", or "full", which that has locale-dependent meaning defined by the Java platform (see in the documentation of DateFormat). For date-time values, you can specify the length of the date and time part independently, be separating them with _, like "short_medium". ("medium" means "medium_medium" for date-time values.)

        • Anything that starts with "@" followed by a letter is interpreted as a custom date/time/dateTime format, but only if either Configuration.getIncompatibleImprovements() is at least 2.3.24, or there's any custom formats defined (even if custom number format). The format of such string is "@name" or "@name parameters", where name is the key in the Map set by Configurable.setCustomDateFormats(Map), and parameters is parsed by the custom number format.

        Defaults to "", which is equivalent to "medium_medium".

        Overrides:
        setDateTimeFormat in class Configurable
      • getLocalVariable

        public TemplateModel getLocalVariable​(java.lang.String name)
                                       throws TemplateModelException
        Returns the loop or macro local variable corresponding to this variable name. Returns null if no such variable exists with the given name, or the variable was set to null. Doesn't read namespace or global variables.
        Throws:
        TemplateModelException
      • getVariable

        public TemplateModel getVariable​(java.lang.String name)
                                  throws TemplateModelException
        Returns the variable that is visible in this context, or null if the variable is not found. This is the correspondent to an FTL top-level variable reading expression. That is, it tries to find the the variable in this order:
        1. An loop variable (if we're in a loop or user defined directive body) such as foo_has_next
        2. A local variable (if we're in a macro)
        3. A variable defined in the current namespace (say, via <#assign ...>)
        4. A variable defined globally (say, via <#global ....>)
        5. Variable in the data model:
          1. A variable in the root hash that was exposed to this rendering environment in the Template.process(...) call
          2. A shared variable set in the configuration via a call to Configuration.setSharedVariable(...)
        Throws:
        TemplateModelException
      • setGlobalVariable

        public void setGlobalVariable​(java.lang.String name,
                                      TemplateModel value)
        Sets a variable in the global namespace, like <#global name=value>. This can be considered a convenient shorthand for getGlobalNamespace().put(name, model).

        Note that this is not an exact pair of getGlobalVariable(String), as that falls back to higher scopes if the variable is not in the global namespace.

        Parameters:
        name - The name of the variable.
        value - The new value of the variable. null in effect removes the local variable (reading it will fall back to higher scope).
      • setVariable

        public void setVariable​(java.lang.String name,
                                TemplateModel value)
        Sets a variable in the current namespace, like <#assign name=value>. This can be considered a convenient shorthand for: getCurrentNamespace().put(name, model).
        Parameters:
        name - The name of the variable.
        value - The new value of the variable. null in effect removes the local variable (reading it will fall back to higher scope).
      • setLocalVariable

        public void setLocalVariable​(java.lang.String name,
                                     TemplateModel value)
        Sets a local variable that's on the top-level inside a macro or function invocation, like <#local name=value>. Note that just like <#local name=value>, this will not set loop variables; it will totally ignore them, and might sets a local variable that a loop variable currently "shadows". As such, it's not exactly the pair of getLocalVariable(String), which also reads loop variables.
        Parameters:
        name - The name of the variable.
        value - The new value of the variable. null in effect removes the local variable (reading it will fall back to higher scope).
        Throws:
        java.lang.IllegalStateException - if the environment is not executing a macro body.
      • getKnownVariableNames

        public java.util.Set getKnownVariableNames()
                                            throws TemplateModelException
        Returns a set of variable names that are known at the time of call. This includes names of all shared variables in the Configuration, names of all global variables that were assigned during the template processing, names of all variables in the current name-space, names of all local variables and loop variables. If the passed root data model implements the TemplateHashModelEx interface, then all names it retrieves through a call to TemplateHashModelEx.keys() method are returned as well. The method returns a new Set object on each call that is completely disconnected from the Environment. That is, modifying the set will have no effect on the Environment object.
        Throws:
        TemplateModelException
      • outputInstructionStack

        public void outputInstructionStack​(java.io.PrintWriter pw)
        Prints the current FTL stack trace. Useful for debugging. TemplateExceptions incorporate this information in their stack traces.
      • getNamespace

        public Environment.Namespace getNamespace​(java.lang.String name)
        Returns the name-space for the name if exists, or null.
        Parameters:
        name - the template path that you have used with the import directive or importLib(String, String) call, in normalized form. That is, the path must be an absolute path, and it must not contain "/../" or "/./". The leading "/" is optional.
      • getMainNamespace

        public Environment.Namespace getMainNamespace()
        Returns the main namespace. This corresponds to the FTL .main hash.
      • getCurrentNamespace

        public Environment.Namespace getCurrentNamespace()
        Returns the current namespace. This corresponds to the FTL .namespace hash. Initially, the current name space is the main namespace, but when inside an #import-ed template, it will change to the namespace of that import. Note that #include doesn't affect the namespace, so if you are in an #import-ed template and then from there do an #include, the current namespace will remain the namespace of the #import.
      • getGlobalNamespace

        public Environment.Namespace getGlobalNamespace()
        Returns the name-space that contains the globally visible non-data-model variables (usually created with &lt;#global ...&gt;).
      • getDataModel

        public TemplateHashModel getDataModel()
        Returns a view of the data-model (also known as the template context in some other template engines) that falls back to shared variables.
      • getGlobalVariables

        public TemplateHashModel getGlobalVariables()
        Returns the read-only hash of globally visible variables. This is the correspondent of FTL .globals hash. That is, you see the variables created with <#global ...>, and the variables of the data-model. To create new global variables, use setGlobalVariable.
      • setCurrentVisitorNode

        public void setCurrentVisitorNode​(TemplateNodeModel node)
        sets TemplateNodeModel as the current visitor node. .current_node
      • importLib

        public Environment.Namespace importLib​(java.lang.String templateName,
                                               java.lang.String targetNsVarName,
                                               boolean lazy)
                                        throws java.io.IOException,
                                               TemplateException
        Like importLib(String, String), but you can specify if you want a lazy import or not.
        Returns:
        Not null. This is possibly a lazily self-initializing namespace, which mean that it will only try to get and process the imported template when you access its content.
        Throws:
        java.io.IOException
        TemplateException
        Since:
        2.3.25
      • toFullTemplateName

        public java.lang.String toFullTemplateName​(java.lang.String baseName,
                                                   java.lang.String targetName)
                                            throws MalformedTemplateNameException
        Resolves a reference to a template (like the one used in #include or #import), assuming a base name. This gives a root based, even if non-normalized and possibly non-absolute (but then relative to the root) template name, that could be used for Configuration.getTemplate(String). This is mostly used when a template refers to another template.

        If you need to guarantee that the result is also an absolute path, then apply rootBasedToAbsoluteTemplateName(String) on it.

        Parameters:
        baseName - The name to which relative targetName-s are relative to. Maybe null (happens when resolving names in nameless templates), which means that the base is the root "directory", and so the targetName is returned without change. Assuming TemplateNameFormat.DEFAULT_2_3_0 or TemplateNameFormat.DEFAULT_2_4_0, the rules are as follows. If you want to specify a base directory here, it must end with "/". If it doesn't end with "/", it's parent directory will be used as the base path. Might starts with a scheme part (like "foo://", or with TemplateNameFormat.DEFAULT_2_4_0 even just with "foo:").
        targetName - The name of the template, which is either a relative or absolute name. Assuming TemplateNameFormat.DEFAULT_2_3_0 or TemplateNameFormat.DEFAULT_2_4_0, the rules are as follows. If it starts with "/" or contains a scheme part separator ("://", also, with TemplateNameFormat.DEFAULT_2_4_0 a ":" with no "/" anywhere before it) then it's an absolute name, otherwise it's a relative path. Relative paths are interpreted relatively to the baseName. Absolute names are simply returned as is, ignoring the baseName, except, when the baseName has scheme part while the targetName doesn't have, then the schema of the baseName is prepended to the targetName.
        Throws:
        MalformedTemplateNameException
        Since:
        2.3.22
      • rootBasedToAbsoluteTemplateName

        public java.lang.String rootBasedToAbsoluteTemplateName​(java.lang.String rootBasedName)
                                                         throws MalformedTemplateNameException
        Converts a root based name (a name that's either relative to the root, or is absolute), which are typically used by the API (such as for Configuration.getTemplate(String)), to an absolute name, which can be safely passed to <#include path> and such, as it won't be misinterpreted to be relative to the directory of the template. For example, "foo/bar.ftl" is converted to "/foo/bar.ftl", while "/foo/bar" or "foo://bar/baz" remains as is, as they are already absolute names (see TemplateNameFormat for more about the format of names).

        You only need this if the template name will be passed to <#include name>, <#import name>, .get_optional_template(name) or a similar construct in a template, otherwise using non-absolute root based names is fine.

        Throws:
        MalformedTemplateNameException
        Since:
        2.3.28
      • getNamespaceForPrefix

        public java.lang.String getNamespaceForPrefix​(java.lang.String prefix)
        Returns:
        the namespace URI registered for this prefix, or null. This is based on the mappings registered in the current namespace.
      • getPrefixForNamespace

        public java.lang.String getPrefixForNamespace​(java.lang.String nsURI)
      • getDefaultNS

        public java.lang.String getDefaultNS()
        Returns:
        the default node namespace for the current FTL namespace
      • getCustomState

        public java.lang.Object getCustomState​(java.lang.Object identityKey)
        Returns the value of a custom state variable, or null if it's missing; see setCustomState(Object, Object) for more.
        Since:
        2.3.24
      • setCustomState

        public java.lang.Object setCustomState​(java.lang.Object identityKey,
                                               java.lang.Object value)
        Sets the value of a custom state variable. Custom state variables meant to be used by TemplateNumberFormatFactory-es, TemplateDateFormatFactory-es, and similar user-implementable, pluggable objects, which want to maintain an Environment-scoped state (such as a cache).
        Parameters:
        identityKey - The key that identifies the variable, by its object identity (not by Object.equals(Object)). This should be something like a private static final Object CUSTOM_STATE_KEY = new Object(); in the class that needs this state variable.
        value - The value of the variable. Can be anything, even null.
        Returns:
        The previous value of the variable, or null if the variable didn't exist.
        Since:
        2.3.24