Namespaces - FreeMarker Manual

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# Namespaces

When you run FTL templates, you have a (possibly empty) set of variables that you have created with `assign` and `macro` directives, as can be seen from the previous chapter. A set of variables like this is called a namespace. In simple cases you use only one namespace, the so-called main namespace. You don't realize this, since normally you use only this namespace.

But if you want to build reusable collection of macros, functions and other variables -- usually referred as library by lingo -- the usage of multiple namespaces becomes inevitable. Just consider if you have a big collection of macros, that you use in several projects, or even you want to share it with other people. It becomes impossible to be sure that the library does not have a macro (or other variable) with the same name as the name of a variable in the data-model, or with the same name as a the name of a variable in another library used in the template. In general, variables can clobber each other because of the name clashes. So you should use a separate namespace for the variables of each library.

## Creating a library

Let's create a simple library. Assume you commonly need the variables `copyright` and `mail` (before you ask, macros are variables):

    <#macro copyright date>
      <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>
    </#macro>

    <#assign mail = "jsmith@acme.com">

Store the above in the file `lib/my_test.ftl` (in the directory where you store the templates). Assume you want to use this in `aWebPage.ftl`. If you use `<#include "/lib/my_test.ftl">` in the `aWebPage.ftl`, then it will create the two variables in the main namespace, and it is not good now, since you want them to be in a namespace that is used exclusively by the ``My Test Library''. Instead of `include` you have to use `import` directive. This directive is, at the first glance, similar to `include`, but it will create an empty namespace for `lib/my_test.ftl` and will execute that there. `lib/my_test.ftl` will find itself in an clean new world, where only the variables of data-model are present (since they are visible from everywhere), and will create the two variables in this new world. That's fine for now, but you want to access the two variables from `aWebPage.ftl`, and that uses the main namespace, so it can't see the variables of the other namespace. The solution is that the `import` directive not only creates the new namespace, but a new hash variable in the namespace used by the caller of `import` (the main namespace in this case), that will act as a gate into the newly created namespace. So this is how `aWebPage.ftl` will look like:

    <#import "/lib/my_test.ftl" as my> <#-- the hash called "my" will be the "gate" -->
    <@my.copyright date="1999-2002"/>
    ${my.mail}

Note how it accesses the variables in the namespace created for `/lib/my_test.ftl` using the newly created namespace accessing hash, `my`. This will print:

      <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.</p>
    jsmith@acme.com

If you would have a variable called `mail` or `copyright` in the main namespace, that would not cause any confusion, since the two templates use separated namespaces. For example, modify the `copyright` macro in `lib/my_test.ftl` to this:

    <#macro copyright date>
      <p>Copyright (C) ${date} Julia Smith. All rights reserved.
      <br>Email: ${mail}</p>
    </#macro>

and then replace `aWebPage.ftl` with this:

    <#import "/lib/my_test.ftl" as my>
    <#assign mail="fred@acme.com">
    <@my.copyright date="1999-2002"/>
    ${my.mail}
    ${mail}

and the output will be this:

      <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
      <br>Email: jsmith@acme.com</p>
    jsmith@acme.com
    fred@acme.com

This is like that because when you have called the `copyright` macro, FreeMarker has temporarily switch to the namespace that was created by the `import` directive for `/lib/my_test.ftl`. Thus, the `copyright` macro always sees the `mail` variable that exists there, and not the other `mail` that exists in the main namespace.

## Writing the variables of imported namespaces

Occasionally you may want to create or replace a variable in an imported namespace. You can do this with the `assign` directive, if you use its `namespace` parameter. For example, this:

    <#import "/lib/my_test.ftl" as my>
    ${my.mail}
    <#assign mail="jsmith@other.com" in my>
    ${my.mail}

will output this:

    jsmith@acme.com
    jsmith@other.com

## Namespaces and data-model

The variables of the data-model are visible from everywhere. For example, if you have a variable called `user` in the data-model, `lib/my_test.ftl` will access that, exactly as `aWebPage.ftl` does:

    <#macro copyright date>
      <p>Copyright (C) ${date} ${user}. All rights reserved.</p>
    </#macro>

    <#assign mail = "${user}@acme.com">

If `user` is ``Fred'', then the usual example:

    <#import "/lib/my_test.ftl" as my>
    <@my.copyright date="1999-2002"/>
    ${my.mail}

will print this:

      <p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
    Fred@acme.com

Don't forget that the variables in the namespace (the variables you create with `assign` or `macro` directives) have precedence over the variables of the data-model when you are in that namespace. Thus, the contents of data-model does not interfere with the variables created by the library.

Note:

In some unusual applications you want to create variables in the template those are visible from all namespaces, exactly like the variables of the data-model. But you can't change the data-model with templates. Still, it is possible to achieve similar result with the `global` directive; read the reference for more details.

## The life-cycle of namespaces

A namespace is identified by the path that was used with the `import` directive. If you try to `import` with the same path for multiple times, it will create the namespace and run the template specified by the path for the very first invocation of `import` only. The later `import`s with the same path will just create a ``gate'' hash to the same namespace. For example, let this be the `aWebPage.ftl`:

    <#import "/lib/my_test.ftl" as my>
    <#import "/lib/my_test.ftl" as foo>
    <#import "/lib/my_test.ftl" as bar>
    ${my.mail}, ${foo.mail}, ${bar.mail}
    <#assign mail="jsmith@other.com" in my>
    ${my.mail}, ${foo.mail}, ${bar.mail}

The output will be:

    jsmith@acme.com, jsmith@acme.com, jsmith@acme.com
    jsmith@other.com, jsmith@other.com, jsmith@other.com

since you see the same namespace through `my`, `foo` and `bar`.

Note that namespaces are not hierarchical, they exist independently of each other. That is, if you `import` namespace N2 while you are in name space N1, N2 will not be inside N1. N1 just gets a hash by which it can access N2. This is the same N2 namespace that you would access if, say, you `import` N2 when you are in the main namespace.

Each template processing job has its own private set of namespaces. Each template-processing job is a separated cosmos that exists only for the short period of time while the given page is rendered, and then it vanishes with all its populated namespaces. Thus, whenever we say that ```import` is called for the first time'' and such, we are always talking in the context of a single template processing job.

## Writing libraries for other people

If you have written a good quality library that can be useful for other people, you may want to make it available on the Internet (like on http://freemarker.org/libraries.html). To prevent clashes with the names of libraries used by other authors, and to make it easy to write libraries that import other published libraries, there is a de-facto standard that specifies the format of library paths. The standard is that the library must be available (importable) for templates and other libraries with a path like this:

`/lib/yourcompany.com/your_library.ftl`

For example if you work for Example Inc. that owns the www.example.com homepage, and you develop a widget library, then the path of the FTL file to import should be:

`/lib/example.com/widget.ftl`

Note that the www is omitted. The part after the 3rd slash can contain subdirectories such as:

`/lib/example.com/commons/string.ftl`

An important rule is that the path should not contain upper-case letters. To separate words, use `_`, as in `wml_form` (not `wmlForm`).

Note that if you do not develop the library for a company or organization, you should use the URL of the project homepage, such as `/lib/example.sourceforge.net/example.ftl`, or `/lib/geocities.com/jsmith/example.ftl`.

Previous Next