Namespaces - Apache FreeMarker Manual

Unsupported web browser - Use a modern browser to view this website!

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# Namespaces

When you run templates, you have a (possibly empty) set of variables that you have created with `assign` and `macro` and `function` directives (see in the previous chapter). A set of template-made variables like that is called a namespace. In simple cases you use only one namespace, the main namespace. Whenever you define a variable in the main template (macros and functions are also variables, mind you), or in templates `include`-d in it, that's where the variable are created. The key property of a namespace is that the variable name uniquely identifies a value in it (i.e, you can't have multiple variables in it with the same name in the same namespace).

Sometimes you want to build reusable collection of macros, functions, and other variables, which we call a library. It's important that a library can use its own namespace, to avoid accidental name clashes. Consider, you may have many names in that library, and you intend to use the library in many templates, maybe even reuse it in several projects. It becomes impractical to keep track of where the library used in another template accidentally hides variables from the data-model, or what names you shouldn't assign to in the template to avoid overwriting the variables of the library. If you have multiple libraries used in the same template, this becomes even harder to track. So you should use a separate namespace for the variables of each library.

## Creating a library

Here's a simple library, which contains a `copyright` macro and a `mail` string:

Template

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

    <#assign mail = "user@example.com">

Save this into the `lib/example.ftl` file (inside the directory where you store the templates). Then create a template, let's say, `some_web_page.ftl`, and use the library in it:

Template

    <#import "/lib/example.ftl" as e>

    Some Web page...
    <@e.copyright date="1999-2002"/>
    ${e.mail}

Output

    Some Web page...
      <p>Copyright (C) 1999-2002 Someone. All rights reserved.</p>
    user@example.com

Note the `import` directive above, and the subsequent usage of the "`e`" variable. `import` is similar to the perhaps already familiar `include` directive, but it will create an empty namespace and will run `lib/example.ftl` in that namespace. So `lib/example.ftl` will find itself in a clean world, where only the variables of the data-models are visible (and the globals), and will create its two variables (`copyright` and `mail`) in this clean namespace. But you will need to access those two variables from another namespace (the main namespace), thus, the `import` directive creates a hash variable (`e` in this case) to access the namespace it has created . That variable is in the namespace that the `import`-ing template uses, and acts as a window to the namespace of the imported library.

To demonstrate that the two namespaces are separate, consider the example below. Replace `lib/example.ftl` with this:

Template

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

    <#assign mail = "user@example.com">

and `some_web_page.ftl` with this:

Template

    <#import "/lib/example.ftl" as e>
    <#assign mail="other@example.com">
    <@e.copyright date="1999-2002"/>
    ${e.mail}
    ${mail}

Output

      <p>Copyright (C) 1999-2002 Someone. All rights reserved.
      <br>Email: user@example.com</p>
    user@example.com
    other@example.com

As you can see, the `mail` variable assigned in `some_web_page.ftl` is separate from the `mail` variable assigned in the imported library.

## Writing the variables of imported namespaces

Sometimes you want to create or replace a variable in an imported namespace. You can do that with the `assign` directive and its `namespace` parameter:

Template

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

Output

    user@example.com
    other@example.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/example.ftl` will access that, exactly like `some_web_page.ftl` does:

Template

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

Assuming `user` is "John Doe":

Template

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

Output

    User is: John Doe
      <p>Copyright (C) 1999-2002 John Doe. All rights reserved.</p>

Don't forget that the variables in the namespace (the variables you create with `assign`, `macro`, and `function` directives) have precedence over the variables of the data-model when you are in that namespace. So generally, if a library is interested in a data-model variable, it doesn't assign to the same name.

Note:

In some unusual applications you want to create variables in the template that are visible from all namespaces, exactly like the variables of the data-model. While templates can't change the data-model, it's possible to achieve similar effect with the `global` directive; see the reference.

## The life-cycle of namespaces

A namespace is identified by the path used in the `import` directive (after it was normalized to an absolute path). If you try to `import` with equivalent paths for multiple times, it will create the namespace and run the template for only the first invocation of `import`. The later `import`-s with equivalent paths will just assign the same namespace to the variable specified after the `as` keyword. For example:

Template

    <#import "/lib/example.ftl" as e>
    <#import "/lib/example.ftl" as e2>
    <#import "/lib/example.ftl" as e3>
    ${e.mail}, ${e2.mail}, ${e3.mail}
    <#assign mail="other@example.com" in e>
    ${e.mail}, ${e2.mail}, ${e3.mail}

Output

    user@example.com, user@example.com, user@example.com
    other@example.com, other@example.com, other@example.com

As you access the same namespace through `e`, `e2`, and `e3`, the `email` has changed in all of them at once. The practical importance of this is that when you import the same library in multiple templates, only one namespace will be initialized and created for the library, which will be shared by all the importing templates.

Note that namespaces are not hierarchical; it doesn't mater what namespace are you in when `import` creates another namespace. For example, when you `import` namespace N2 while you are in name space N1, N2 will not be inside N1. N1 just gets the same N2 that you get if 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 separate universe that exists only for the short period while the main template is rendered, and then it vanishes with all its populated namespaces. Thus, whenever we say that "`import` is called for the first time", we always mean the first time within the lifespan of a single template processing job.

## Auto-importing

When you have to import the same libraries again and again in many templates, know that the Java programmers (or whoever is responsible for configuring FreeMarker) can specify auto-imports, which are imports that are automatically done in all templates. Auto imports can also be configured to be "lazy" (since FreeMarker 2.3.25), which means that they are only done when the imported library is actually used in the template. See the Java API documentation for more details: Configuration.setAutoImports, Configuration.setLazyAutoImports.

Previous Next