FreeMarker Common Operations

Last updated: January 8, 2024

freemarker conditional assignment

Whether you're just starting out or have years of experience, Spring Boot is obviously a great choice for building a web application.

Jmix builds on this highly powerful and mature Boot stack, allowing devs to build and deliver full-stack web applications without having to code the frontend. Quite flexibly as well, from simple web GUI CRUD applications to complex enterprise solutions.

Concretely, The Jmix Platform includes a framework built on top of Spring Boot, JPA, and Vaadin , and comes with Jmix Studio, an IntelliJ IDEA plugin equipped with a suite of developer productivity tools.

The platform comes with interconnected out-of-the-box add-ons for report generation, BPM, maps, instant web app generation from a DB, and quite a bit more:

>> Become an efficient full-stack developer with Jmix

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page .

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page .

Get non-trivial analysis (and trivial, too!) suggested right inside your IDE or Git platform so you can code smart, create more value, and stay confident when you push.

Get CodiumAI for free and become part of a community of over 280,000 developers who are already experiencing improved and quicker coding.

Write code that works the way you meant it to:

>> CodiumAI. Meaningful Code Tests for Busy Devs

DbSchema is a super-flexible database designer, which can take you from designing the DB with your team all the way to safely deploying the schema .

The way it does all of that is by using a design model , a database-independent image of the schema, which can be shared in a team using GIT and compared or deployed on to any database.

And, of course, it can be heavily visual, allowing you to interact with the database using diagrams, visually compose queries, explore the data, generate random data, import data or build HTML5 database reports.

>> Take a look at DBSchema

Slow MySQL query performance is all too common. Of course it is. A good way to go is, naturally, a dedicated profiler that actually understands the ins and outs of MySQL.

The Jet Profiler was built for MySQL only , so it can do things like real-time query performance, focus on most used tables or most frequent queries, quickly identify performance issues and basically help you optimize your queries.

Critically, it has very minimal impact on your server's performance, with most of the profiling work done separately - so it needs no server changes, agents or separate services.

Basically, you install the desktop application, connect to your MySQL server , hit the record button, and you'll have results within minutes:

>> Try out the Profiler

A quick guide to materially improve your tests with Junit 5:

Do JSON right with Jackson

Download the E-book

Get the most out of the Apache HTTP Client

Get Started with Apache Maven:

Working on getting your persistence layer right with Spring?

Explore the eBook

Building a REST API with Spring?

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> REST With Spring (new)

Get started with Spring and Spring Boot, through the reference Learn Spring course:

>> LEARN SPRING

Looking for the ideal Linux distro for running modern Spring apps in the cloud?

Meet Alpaquita Linux : lightweight, secure, and powerful enough to handle heavy workloads.

This distro is specifically designed for running Java apps . It builds upon Alpine and features significant enhancements to excel in high-density container environments while meeting enterprise-grade security standards.

Specifically, the container image size is ~30% smaller than standard options, and it consumes up to 30% less RAM:

>> Try Alpaquita Containers now.

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth , to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project .

You can explore the course here:

>> Learn Spring Security

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot .

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Get started with Spring Boot and with core Spring, through the Learn Spring course:

1. Introduction

FreeMarker is a template engine, written in Java, and maintained by the Apache Foundation. We can use the FreeMarker Template Language, also known as FTL, to generate many text-based formats like web pages, email, or XML files.

In this tutorial, we’ll see what we can do out-of-the-box with FreeMarker, though note that it is quite configurable  and even integrates nicely with Spring .

Let’s get started!

2. Quick Overview

To inject dynamic content in our pages, we need to use a syntax that FreeMarker understands :

  • ${…} in the template will be replaced in the generated output with the actual value of the expression inside the curly brackets – we call this interpolation – a couple of examples are ${1 + 2 } and ${variableName}
  • FTL tags are like HTML tags (but contain # or @ ) and FreeMarker interprets them, for example <#if…></#if>
  • Comments in FreeMarker start with <#– and end with –>

3. The Include Tag

The FTL include directive is a way for us to follow the DRY principle in our application. We will define the repetitive content in a file and reuse it across different FreeMarker templates with single include tag.

One such use case is when we want to include the menu section inside many pages. First, we’ll define the menu section inside a file – we’ll call it menu.ftl – with the following content:

And on our HTML page, let’s include the created menu.ftl :

And we can also include FTL in our fragments, which is great.

4. Handling Value Existence

FTL will consider any null value as a missing value. Thus, we need to be extra careful and add logic to handle null inside our template.

We can use the ?? operator to check if an attribute, or nested property, exists. The result is a boolean:

So, we’ve tested the attribute for null, but that’s not always enough. Let’s now define a default value as a fallback for this missing value. To do this, we need the ! operator placed after the name of the variable:

Using round brackets, we can wrap many nested attributes.

For example, to check if the attribute exists and has a nested property with another nested property, we wrap everything:

Finally, putting everything together, we can embed these among static content:

And, if the student were null , we’d see:

Please notice the additional ?c directive used after the ?? . We did it to convert the boolean value to a human-readable string.

5. The If-Else Tag

Control structures are present in FreeMarker, and the traditional if-else is probably familiar:

While the elseif and else branches are optional, the conditions must resolve to a boolean value.

To help us with our evaluations, we’ll likely use one of:

  • x == y to check is x is equal to y
  • x != y to return true only if x differs from y
  • x lt y means that x must be strictly smaller than y – we can also use < instead of lt
  • x gt y evaluates to true only if x is strictly greater than y – we can use > instead of gt
  • x lte y tests if x is less than or equal to y – the alternative to lte is <=
  • x gte y tests if x is greater than or equal to y – the alternative of gte is >=
  • x?? to check the existence of x
  • sequence?seqContains(x) validates the existence of x inside a sequence

It’s very important to keep in mind that FreeMarker considers >= and > as closing characters for an FTL tag. The solution is to wrap their usage in parentheses or use gte or gt instead.

Putting it together, for the following template:

We end up with the resulting HTML code:

6. Containers of Sub-Variables

In FreeMarker, we have three types of containers for sub-variables:

  • Hashes are a sequence of key-value pairs – the key must be unique inside the hash and we don’t have an ordering
  • Sequences are lists where we have an index associated with each value – a noteworthy fact is that sub-variables can be of different types
  • Collections are a special case of sequences where we can’t access the size or retrieve values by index – we can still iterate them with the list tag though!

6.1. Iterating Items

We can iterate over a container in two basic ways. The first one is where we iterate over each value and have logic happening for each of them:

Or, when we want to iterate a Hash , accessing both the key and the value:

The second form is more powerful because it also allows us to define the logic that should happen at various steps in the iteration:

The item represents the name of the looped variable, but we can rename it to what we want. The else branch is optional.

For a hands-on example, well define a template where we list some statuses:

This will return us the following HTML when our container is [“200 OK”, “404 Not Found”, “500 Internal Server Error”] :

6.2. Items Handling

A hash allows us two simple functions: keys to retrieve only the keys contained, and values to retrieve only the values.

A sequence is more complex; we can group the most useful functions:

  • chunk and join to get a sub-sequence or combine two sequences
  • reverse , sort, and sortBy for modifying the order of elements
  • first and last will retrieve the first or last element, respectively
  • size represents the number of elements in the sequence
  • seqContains , seqIndexOf , or seqLastIndexOf to look for an element

7. Type Handling

FreeMarker comes with a huge variety of functions (built-ins) available for working with objects. Let’s see some frequently used functions.

7.1. String Handling

  • url and urlPath will URL-escape the string, with the exception that urlPath will not escape slash /
  • jString , jsString, and jsonString will apply the escaping rules for Java, Javascript and JSON, respectively
  • capFirst , uncapFirst , upperCase , lowerCase and capitalize are useful for changing the case of our string, as implied by their names
  • boolean , date , time , datetime and number are functions for converting from a string to other types

Let’s now use a few of those functions:

And the output for the template above will be:

When using the date function, we’ve also passed the pattern to use for parsing the String object. FreeMarker uses the local format unless specified otherwise , for example in the string function available for date objects.

7.2. Number Handling

  • round , floor and ceiling can help with rounding numbers
  • abs will return a number’s absolute value
  • string will convert the number to a string. We can also pass four pre-defined number formats: computer , currency , number , or percent or define our own format, like [ “0.###” ]

Let’s do a chain of a few mathematical operations:

And as expected, the resulting value is 11.12.

7.3. Date Handling

  • .now represents the current date-time
  • date , time and datetime can return the date and time sections of the date-time object
  • string will convert date-times to strings – we can also pass the desired format or use a pre-defined one

We’re going to now get the current time and format the output to a string containing only the hours and minutes:

The resulting HTML will be:

8. Exception Handling

We’ll see two ways to handle exceptions for a FreeMarker template.

The first way is to use attempt-recover tags to define what we should try to execute and a block of code that should execute in case of error.

The syntax is:

Both attempt and recover tags are mandatory. In case of an error, it rolls back the attempted block and will execute only the code in the recover section .

Keeping this syntax in mind, let’s define our template as:

When attributeWithPossibleValue is missing, we’ll see:

And the output when attributeWithPossibleValue exists is:

The second way is to configure FreeMarker what should happen in case of exceptions.

With Spring Boot, we easily configure this via properties file; here are some available configurations:

  • spring.freemarker.setting.template_exception_handler=rethrow re-throws the exception
  • spring.freemarker.setting.template_exception_handler=debug outputs the stack trace information to the client and then re-throws the exception.
  • spring.freemarker.setting.template_exception_handler=html_debug outputs the stack trace information to the client, formatting it so it will be usually well readable in the browser, and then re-throws the exception.
  • spring.freemarker.setting.template_exception_handler=ignore skips the failing instructions, letting the template continue executing.
  • spring.freemarker.setting.template_exception_handler=default

9. Calling Methods

Sometimes we want to call Java methods from our FreeMarker templates. We’ll now see how to do it.

9.1. Static Members

To start accessing static members, we could either update our global FreeMarker configuration or add a S taticModels type attribute on the model, under the attribute name statics :

Accessing static elements is straight-forward.

First, we import the static elements of our class using the assign tag, then decide on a name and, finally, the Java classpath.

Here’s how we’ll import Math class in our template, show the value of the static PI field, and use the static pow method:

The resulting HTML is:

9.2. Bean Members

Bean members are very easy to access: use the dot (.) and that’s it!

For our next example, we will add a Random object to our model:

In our FreeMarker template, let’s generate a random number:

This will cause output similar to:

9.3. Custom Methods

The first step for adding a custom method is to have a class that implements FreeMarker’s TemplateMethodModelEx interface and defines our logic inside the exec method:

We’ll add an instance of our new class as an attribute on the model:

The next step is to use our new method inside our template:

Finally, the resulting output is:

10. Conclusion

In this article, we’ve seen how to use the FreeMarker template engine inside our project. We’ve focused on common operations, how to manipulate different objects, and a few more advanced topics.

The implementation of all these snippets is available over on GitHub .

Just published a new writeup on how to run a standard Java/Boot application as a Docker container, using the Liberica JDK on top of Alpaquita Linux:

>> Spring Boot Application on Liberica Runtime Container.

Slow MySQL query performance is all too common. Of course it is.

The Jet Profiler was built entirely for MySQL , so it's fine-tuned for it and does advanced everything with relaly minimal impact and no server changes.

Explore the secure, reliable, and high-performance Test Execution Cloud built for scale. Right in your IDE:

Basically, write code that works the way you meant it to.

Build your API with SPRING - book cover

last modified January 27, 2024

This is an introductory tutorial of the FreeMarker Java template engine. We introduce the FreeMarker template engine and create several console and web applications. Maven is used to build our examples. NetBeans is used to manage the applications.

Table of contents

Freemarker template engine.

A template engine combines static data with dynamic data to produce content. A template is an intermediate representation of the content; it specifies how the output will be generated.

A FreeMarker template file has by convention a .ftl extension.

FreeMarker is not restricted to templates for HTML pages; it can be used to generate e-mails, configuration files, source code etc.

We use this FreeMarker dependency in a Gradle project.

FreeMarker interpolations

Interpolations are expressions put between the ${ } characters. FreeMarker will replace an interpolation in the output with the actual value of the expression inside the curly brackets.

In the following example, we use a FreeMarker template file to generate simple text output.

The example prints a simple text to the console. The final text was processed by a template engine.

The setClassForTemplateLoading sets the class whose method will be used to load templates. The templates are located in the views subdirectory of src/main/resources directory.

With the getTemplate method, we retrieve the test.ftlh template file.

The data model is created. The data from the model will be dynamically placed into the FreeMarker template file.

The test.ftlh template file contains one interpolation; it will be replaced with the generated string.

This is the Gradle build file.

FreeMarker list directive

The next example produces a list of cars.

We have a Car bean. It has two attributes: name and price.

Here we create a list of Car objects and put it into the data model.

The template file contains a #list directive which prints the attributes of the car objects; the attributes are accessed with the dot character.

FreeMarker directives

FreeMarker directives are special tags that perform an action. There are two kinds of directives: built-in and custom.

The <#assign> directive creates a new name variable. The value of the variable is printed with the ${name} syntax.

In the example, we assing a new sequence of colour names to the colours variable. The <#list> directive goes through the collection and prints each item.

The <#compress> directive removes superfluous white-space when we use a white-space insensitive format (e.g. HTML or XML)

The program removed all superfluous white-space.

FreeMarker with Spark

In the following example, we are going to integrate the FreeMarker template engine into our Spark application.

This is the hello.ftlh template file; it refers to the name variable which was passed with the ModelAndView object.

Spring Boot FreeMarker

The Application sets up the Spring Boot application. The @SpringBootApplication annotation defines the class as a configuration class,enables auto-configuration, and enables component scanning.

The server responds with a message back to the client. The response is created from the hello.ftlh template file.

The Spring Boot starts an embedded Tomcat server, listening on port 8080.

In this tutorial we have worked with the FreeMarker template engine.

My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Java tutorials .

Page Contents

Description

  • name : name of the variable. It is not expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1> . Note that this string literal does not expand interpolations (as "${foo}" ).
  • value : the value to store. Expression.
  • namespacehash : a hash that was created for a namespace (by import ). Expression.

With this you can create a new variable, or replace an existing variable. Note that only top-level variables can be created/replaced (i.e. you can't create/replace some_hash.subvar , but some_hash ).

For more information about variables, read this: Template Author's Guide/Miscellaneous/Defining variables in the template

Example: variable seasons will store a sequence:

Example: Increments the numerical value stored in variable test :

As a convenience feature, you can do more assignments with one assign tag. For example this will do the same as the two previous examples:

If you know what namespaces are: assign directive creates variables in namespaces. Normally it creates the variable in the current namespace (i.e. in the namespace associated with the template where the tag is). However, if you use in namespacehash then you can create/replace a variable of another namespace than the current namespace. For example, here you create/replace variable bgColor of the namespace used for /mylib.ftl :

An extreme usage of assign is when it captures the output generated between its start-tag and end-tag. That is, things that are printed between the tags will not be shown on the page, but will be stored in the variable. For example:

will print:

Please note that you should not to use this to insert variables into strings:

You should simply write:

FreeMarker Manual -- For FreeMarker 2.3.20
HTML generated: 2013-06-27 20:54:33 GMT

FreeMarker: getDataType Function for Variable Comparison

Comparing Variables in FreeMarker: getDataType Function

Abstract: In this article, we will discuss how to use the getDataType function in FreeMarker to compare variables and determine their data types.

FreeMarker is a popular templating engine that is used to generate dynamic web pages. It is a powerful tool that allows developers to separate the presentation logic from the business logic. One of the most common tasks when working with variables in FreeMarker is to determine their data type. This is where the getDataType function comes in handy.

What is the getDataType Function?

The getDataType function is a built-in function in FreeMarker that returns the data type of a given variable. It is a useful function for debugging and for implementing conditional logic in your templates. The function takes a single argument, which is the variable whose data type you want to determine.

Using the getDataType Function

Using the getDataType function is straightforward. Here's an example:

In this example, we first declare two variables, x and y , with different data types. We then use the getDataType function to determine the data type of each variable and store the result in two new variables, xDataType and yDataType . Finally, we use conditional logic to check the data type of each variable and display a message accordingly.

Advanced Usage of the getDataType Function

The getDataType function can also be used with more complex data types, such as lists and maps. Here's an example:

In this example, we declare a list and a map, and then use the getDataType function to determine their data types. We check if the data type of the list is a "sequence" and if the data type of the map is a "hash\_map".

The getDataType function is a useful tool in FreeMarker for determining the data type of a variable. It can be used with simple and complex data types, and it is especially useful for debugging and implementing conditional logic in your templates. By mastering the use of the getDataType function, you can take your FreeMarker skills to the next level.

  • The getDataType function is a built-in function in FreeMarker that returns the data type of a given variable.
  • It takes a single argument, which is the variable whose data type you want to determine.
  • It can be used with simple and complex data types, such as integers, strings, lists, and maps.
  • It is useful for debugging and implementing conditional logic in your templates.
  • FreeMarker Documentation: getDataType Function
  • FreeMarker Documentation: Data Types

Learn how to effectively compare variables in FreeMarker templates using the getDataType function.

Error 265 in applepay integration with authorize.net and magento 2.4.5.

Learn how to troubleshoot and resolve error 265 when integrating ApplePay with Authorize.Net and Magento 2.4.5.

Issues Accessing RHEL 9's TSSH Component: Talend Faces Error

This article discusses a common issue encountered when trying to access RHEL 9's TSSH component using Talend, which results in an error.

Cucumber Not Showing Scenario Steps Passed or Failed: A 10-Minute Solution

Learn how to resolve the issue of Cucumber not showing scenario steps passed or failed with a simple 10-minute solution.

Calling Non-supported Functions in Matlab Simulink: A Workaround for Using Custom M-Files

Learn how to work around the limitation of calling non-supported functions in Matlab Simulink by using custom M-files in your Simulink model.

Keypresses Not Detected in Pygame: A Solution

In this article, we will discuss a common issue with Pygame where keypresses are not detected and provide a solution to this problem.

Tags: :  FreeMarker Template Engine Comparing Variables

Latest news

  • Making Site Content Updateable for Owners: A Software Development Approach
  • Handling CSRF Tokens in Cypress Test Runs: A Solution
  • Accessing Target Value in Java with keyMap<String, double>
  • Discord Slash: Python Bot Error
  • Accessing Response Headers with SyncGraphQLClientInterceptor in Software Development
  • MJML Freemarker: Compiling Hydrocurage Templates with Java
  • Beautiful Soup: Filtering Divs with Specific Classes
  • React Native EXPO: APK Build App Crashes at Startup (Probably React-Navigation)
  • Testing .Net 8 API with Fake Data: A Replacement for Real MySqlConnection
  • Databricks: Pyspark Writing Delta Format Mode - Overwrite Not Working Properly
  • Mounting Remote Directory Directly in Docker using sshfs Plugin: Non-Root User Issues
  • Resolving ETIMEDOUT Errors When Connecting Kubernetes Pods to Databases
  • Generating Current Database State with Liquibase using Gradle
  • DesignAutomationRevit: Successfully Uploading Revit Models to Application Bucket (Under 10MB)
  • TypeORM Problem: Incorrect SQL query generated for One-To-Many, Many-To-One relations
  • Creating Multiple Objects with distinct saved records using .NET Entity Framework: Not Adding Multiple Objects to a DB
  • Custom Themes and Style Build in Angular: Parent and Child Apps
  • TryHackMe CTF Walkthrough: Clear Instructions
  • Flutter InAppWebView Build Issue: Execution Failed - Missing Classes
  • Troubleshooting Kubernetes Nodes with RHEL: Lost Connection
  • Bootstrap Select: Select Option Not Working
  • Flask-socket.io: Socket Keep-Alive Issues
  • Java Concurrency without Using ThreadExecutorService: A Deep Dive
  • Converting Python Pandas to Polars: A Melt Example
  • Unable to Configure Service ID for Apple Sign in with Cognito
  • Detecting Video Audio Sync Issues in AVPlayer Streams
  • Accessing Array Records within Record using VirtualStringGrid in C#
  • Scaling User Feed Posts in a Social Media App: Strategies for Managing Large Volumes of Data
  • Resolving Jest Errors: 'Not Use Import Statement Outside Module' in React & TypeScript Projects
  • Adjusting Species Name Size to Make it Visible: A Solution
  • Building PWA using BubbleWrap: Error with Existing Keystore
  • Troubleshooting SignalR: No Response from Server
  • Rewriting HTML4 Transitional to HTML5: Single Height <div> Lines
  • Using RD Instead of RO and RQ 64-bit Registers in Intel x86 Manual
  • Removing Specific Pages from WordPress Sitemap
  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

How does #assign and #global variables scope works in ftl's?

I am currently looking to figure the scope of #assign variable. However, scope seems to be confusing please see following example and try to explain. I have some hypothesis which works but if somebody has concrete documentation, it will be very helpful.

Can somebody explain scope in #assign and #global?

  • scripting-language

Subodh Gupta's user avatar

That example should work equally well with #assign and #global . You had some kind of oversight there.

As of #assign VS #global : Variables set via #assign are only visible from the template where they were assigned, plus in the templates that where #include -d in that template (or #include -d in an #include -d template, etc.), because #include -ing is pretty much like copy-pasting. But if you #import a template, as that will have its own namespace, it won't share #assign -ed variables with the #import -ing template. It will share the global variables with it though; variables set with #global are seen from every templates, just like the data-model. You should hardly ever use #global BTW.

ddekany's user avatar

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged freemarker scripting-language or ask your own question .

  • Featured on Meta
  • We spent a sprint addressing your requests — here’s how it went
  • Upcoming initiatives on Stack Overflow and across the Stack Exchange network...
  • The [lib] tag is being burninated
  • What makes a homepage useful for logged-in users

Hot Network Questions

  • A manifold whose tangent space is a sum of line bundles and higher rank vector bundles
  • Translation of the two lines of Latin in Shakespear's Venus and Adonis
  • Can a big mass defect make the mass negative?
  • How can one count how many pixels a GIF image has via command line?
  • Reproducing Ruth Vollmer's acrylic Steiner surface
  • ForeignFunctionLoad / RawMemoryAllocate and c-struct that includes an array
  • Is a "single" cpu safer than multiple cores?
  • Signature of Rav Ovadia Hedaya
  • Can I put multiple journeys and dates on one train ticket in UK?
  • How can I watch a timelapse movie on the Nikon D7100?
  • Is "sinnate" a word? What does it mean?
  • Big zeros in block diagonal matrix
  • Offline, multi-machine, 2-factor authentication information vault?
  • Fill the grid subject to product, sum and knight move constraints
  • What Does Feynman Mean When He Says Amplitude and Probabilities?
  • How to POSIX-ly ignore "warning: command substitution: ignored null byte in input"?
  • Coincidence between coefficients of tanh(tan(x/2)) and Chow ring computations?
  • Did Joe Biden refer to himself as a black woman?
  • Recommend an essay, article, entry, author, or branch of philosophy that addresses the futility of arguing for or against free will
  • How can I search File Explorer for files only (i.e. exclude folders) in Windows 10?
  • Is ElGamal homomorphic encryption using additive groups works only for Discrete Log ElGamal? What about EC ElGamal?
  • Radioactive rocks and an unusual track
  • What is the computational scaling of DFT energy vs gradient vs Hessian?
  • What real-world cultures inspired the various human name examples?

freemarker conditional assignment

FreeMarker

  • Report a Bug
  • Apache FreeMarker Manual
  • Template Language Reference
  • Built-in Reference

Built-ins for sequences

  • Alpha. index
  • Expressions
  • #directives

seq_contains

Seq_index_of, seq_last_index_of.

This built-in splits a sequence into multiple sequences of the size given with the 1st parameter to the built-in (like mySeq?chunk(3) ). The result is the sequence of these sequences. The last sequence is possibly shorter than the given size, unless the 2nd parameter is given (like mySeq?chunk(3, '-') ), that is the item used to make up the size of the last sequence to the given size. Example:

The output will be:

This built in is mostly for outputting sequnces in tabular/columnar format. When used with HTML tables, the 2nd parameter is often "\xA0" (that is the code of the no-break space character, also known as "nbsp"), so the border of the empty TD-s will not be missing.

The 1st parameter must be a number that is at least 1. If the number is not integer, it will be silently rounded down to integer (i.e. both 3.1 and 3.9 will be rounded to 3). The 2nd parameter can be of any type and value.

Returns a new sequence that contains the elements from the input sequence starting with from the first element that does not match the parameter predicate (condition). After that, all elements are included, regardless if they match the predicate or not. See the filter built-in for more details about parameters, and other details, but note that the condition in filter has opposite meaning (what to keep, instead of what to drop).

Example and comparison with filter :

As you can see, drop_while has stopped dropping the elements once it ran into the first element that didn't match the predicate ( x > 0 ). On the other hand, filter keeps the elements that match the same predicate, and it doesn't stop.

See also: take_while built-in

This built-in is available since 2.3.29

Returns a new sequence that only contains the elements for which the parameter condition (the predicate) returns true . For example:

This built-in has a single required parameter, the predicate (filter condition, what to keep). The predicate can be specified in 3 ways:

As a single argument lambda expression : element -> predicate . In that, element is the variable name with which you can refer to the current element in the predicate , and the predicate is an arbitrarily complex expression that must return a boolean value ( true or false ). An example this was shown above. Note again the predicates can be arbitrarily complex, like the predicate in products?filter(product -> product.discounted && !user.hasBought(product)) .

As a function or method that has a single argument, and returns boolean. For example, the "Negatives" example above could be implemented like this:

Note how we just referred to the function by name, and did not call it. Similarly, if you have a Java object called utils in the data-model, and it has a boolean isNegative(Number n) method, then you could use that like xs?filter(utils.isNegative) .

Remember, the condition (predicate) that you specify tells what to keep , not what to filter out! That is, the element will be in the result sequence when you return true , not when you return false . (It's like the WHERE condition in SQL, if you know that.)

While filter is most often used in the list directive , naturally it can be used anywhere where a filtered sequence is needed, and so this works as well:

Note however, that for a very long sequences, the above solution can consume significantly more memory. That's because <list seq ?filter( pred ) ... > is optimized to do filtering without building an intermediate filtered sequence, while the n above example, assign will first build the whole filtered sequence in memory, and we pass that filtered sequence later to list . But again, this only matters for very long sequences.

See also: take_while built-in , drop_while built-in

Lazy evaluation and its consequences

Identical rules apply to these built-ins as well: map( mapper ) , take_while( predicate ) , drop_while( predicate ) .

To optimize processing, filter might delays fetching the elements of the input sequence, and applying the predicate on them. But it's guaranteed that those operations are not delayed past the point where the execution of the directive or interpolation, whose parameter contains the seq ?filter( predicate ) , is finished. Some examples:

In the case of <list seq ?filter( predicate ) ... > nested content </#list> , when the execution enters the nested content , it's not true that all elements of seq was already consumed and filtered. Consuming and filtering seq is instead done bit by bit as list repeats the nested content. But it's guaranteed that past the </#list> tag (the end of the execution of the list directive), there are no delayed readings of seq , or delayed evaluation of the predicate . So avoid changing a such variable (or other system state) in the nested content of list , which influences the result of the predicate . Doing so could change the filtering for the rest of the seq .

In the case of <#assign filteredSeq = seq ?filter( predicate )> it's guaranteed that all elements of seq were processed, and thus predicate won't be evaluated after the assign directive.

In the case of ${ seq ?filter( predicate )?join(', ')} it's guaranteed that all elements of seq were processed, and thus predicate won't be evaluated after the assign directive.

Inside expressions however, there's no promise regarding when the elements are consumed and when the predicate is evaluated. Like in the case of seq ?filter( predicate1 )?filter( predicate2 ) , it's not guaranteed that predicate1 will only be evaluated before predicate2 . (Most likely they will be called alternately: predicate1 for the 1st element, then predicate2 for the 1st element, then predicate1 for the 2nd element, then predicate2 for the 2nd element, and so on.)

If you pass a filtered sequence to a custom directive (a macro) or function or method, as in <@ myMacro seq ?filter( predicate ) /> or myFunction ( seq ?filter( predicate )) , then it's guaranteed that the filtering is not delayed past the point when the custom directive/function/method is invoked. That is, your macro/function/method will aways receive a fully constructed filtered sequence.

Also note that in it's not guaranteed that all elements of the input sequence will be read, and therefore that the predicate will be evaluated for all elements. Some examples of such cases:

You may break out from <list seq ?filter( predicate ) ... > before it reaches the last element, in which case the rest of the seq elements won't be fetched and filtered.

In the case of seq ?filter( predicate )[2] , which reads the 3rd element of the filtered sequence, FreeMarker stops fetching and filtering the elements of seq when we have found the 3rd element that matches the predicate .

In the case of seq ?filter( predicate )?size != 0 , which tells whether the filtered sequence is non-empty, we stop fetching and filtering the elements of seq when we have found the 1st element that matches the predicate . (That's certainly surprising as ?size needs to process the whole sequence to tell the size. But in this case FreeMarker notices that we don't really need the exact size.)

If you are a Java programmer, note how the filter built-in differs from Java Stream.filter . Stream.filter is "lazy", while FreeMarker filter is basically "eager", and is only "lazy" in special cases, and within a limited scope. Thus, unlike in Java, calling filter is not always free. In particular, if you assign a filtered sequence to a variable, or pass it to a custom directive/function/method, the filtered sequence will be created eagerly.

Filtering very long input that you don't hold in memory

Some applications, particularly those that render huge tables, use sequence-like values in the data-model that are not held in memory at once, instead they are like a stream of elements that you can only read in the order as they are given to you (on the Java side these are java.util.Iterator -s, or java.util.Iterables , or the like). These will have "collection" type in the template language, which is like a restricted sequence.

filter works with collection input too. As you have seen earlier, filter might stores the entire filtered sequence in the memory, which in this case sounds concerning, because if the input was too big to fit into the memory (hence it wasn't exposed as a sequence), then the filtered collection can be too big as well. For that reason, if the input is not a sequence (but a collection), filter never collects its result into the memory, and never fetches and processes the input elements until they are really needed ("lazy" behavior). Furthermore the result of filter is then a collection, not a sequence, therefor sequence operations (like seq [ index ] ) will not work on it.

Unlike with sequence input, any operation that would cause collecting the whole filtered result into the memory will now fail. Let's see that through examples. Let's say we have hugeTable in the data-model, which is not a sequence, but still a collection (probably an Iterator in Java). Then, consider:

This works fine, since list doesn't require collecting the result into the memory

Consider this:

This fails, as filtering can't be postponed beyond the containing directive ( assign ), so FreeMareker had to put the entire filtered result into filteredHugeTable . If, however, you know that filteredHugeTable won't be too big, you can explicitly collect the result into a sequence via the sequence built-in :

Naturally, applying the sequence built-in allows all sequence operations, such as seq [ index ] , seq [ range ] , or seq ? size . If these operations are directly applied on a sequence that was converted from a collection, then FreeMarker optimizes out actually creating the sequence in memory. So these won't consume much memory regardless of the size of the filtered hugeTable :

hugeTable?filter( predicate )?sequence[index] : FreeMarker will just fetch and drop the elements till it reaches the element at the desired position.

hugeTable?filter( predicate )?sequence[0..9] : FreeMarker will just collect the first 10 elements.

hugeTable?filter( predicate )?sequence?size : In this case the whole hugeTable will be fetched, which is possibly slow, but the fetched elements are still not collected into the memory, as they only need to be counted.

Filtering missing (null) values

The argument to a lambda expression can hold the missing (Java null ) value, and reading such value will not fall back to a higher scope. Thus, something like seq?filter(it -> it??) , which filters out missing element from the sequence, will work reliably.

Returns the first item of the sequence. Thus value ?first is the same as value [0] , except that, since FreeMarker 2.3.26, value ?first also works if value doesn't support getting items with numerical index, but still supports to be listed (i.e., with FTL collection values).

If the sequence or collection is empty, the result will be a missing value (as in empty ?first!'No item was found' ).

Concatenates the items of a sequence to a single string, with the given separator. For example:

will output:

Sequence items that are not strings will be converted to string with the same conversion rules as of ${ ... } (except, of course, no automatic escaping is applied at this stage).

?join( ... ) can have up to 3 parameters:

Separator, required: The string that is inserted between items

Empty value, defaults to "" (empty string): The value used if the sequence contains no items.

List ending, defaults to "" (empty string): The value printed after the last value, if the list sequence wasn't empty.

So this (where [] means an empty sequence):

Sequences coming from Java might contain null values. Those values will be ignored by this built-in, exactly like if they were removed from the list.

The last subvariable of the sequence. Template processing will die with error if the sequence is empty.

Returns an new sequence where all elements are replaced with the result of the parameter lambda, function, or method. For example, you have a list of user objects in users , but instead you need a list of user names in variable, then you could do this:

The parameter work like the parameter of the with filter built-in (so see there), except that the lambda/function/method you specify can return values of any type.

Regarding lazy evaluation, and handling of very long inputs, it also works on the same way as the filter built-in .

Returns the smaller ( min ) or greatest ( max ) item of the sequence (or collection). The items must be either all numbers, or all date/time values of the same kind (date-only, time-only, date-time), or else a comparison error will occur. These are the same restrictions as for the < and > operators .

Missing items (i.e., Java null -s) will be silently ignored. If the sequence is empty or it only contains missing (Java null ) items, the result itself will be missing.

The sequence with reversed order.

The seq_ prefix is required in the built-in name to differentiate it from the contains built-in that searches a substring in a string (since a variable can be both string and sequence on the same time).

Tells if the sequence contains the specified value (according the == operator of the template language, not according Java's Object.equals ). It has 1 parameter, the value to find. Example:

To find the value the built-in uses FreeMarker's comparison rules (as if you was using == operator ), except that comparing two values of different types or of types for which FreeMarker doesn't support comparison will not cause error, just will be evaluated as the two values are not equal. Thus, you can use it only to find scalar values (i.e. string, number, boolean or date/time values). For other types the result will be always false .

For fault tolerance, this built-in also works with collections.

This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3.

The seq_ prefix is required in the built-in name to differentiate it from the index_of built-in that searches a substring in a string (since a variable can be both string and sequence on the same time).

Returns the index of the first occurrence of a value in the sequence, or -1 if the sequence doesn't contain the specified value. The value to find is specified as the first parameter. For example this template:

will output this:

To find the value the built-in uses FreeMarker's comparison rules (as if you was using == operator ), except that comparing two values of different types or of types for which FreeMarker doesn't support comparison will not cause error, just will be evaluated as the two values are not equal. Thus, you can use it only to find scalar values (i.e. string, number, boolean or date/time values). For other types the result will be always -1 .

The index where the searching is started can be optionally given as the 2nd parameter. This may be useful if the same item can occur for multiple times in the same sequence. There is no restriction on the numerical value of the second parameter: if it is negative, it has the same effect as if it were zero, and if it is greater than the length of the sequence, it has the same effect as if it were equal to the length of the sequence. Decimal values will be truncated to integers. For example:

The seq_ prefix is required in the built-in name to differentiate it from the last_index_of built-in that searches a substring in a string (since a variable can be both string and sequence on the same time).

Returns the index of the last occurrence of a value in the sequence, or -1 if the sequence doesn't contain the specified value. That is, it is the same as seq_index_of , just it searches backward starting from the last item of the sequence. It also supports the optional 2nd parameter that specifies the index where the searching is started. For example:

The number of sub variables in sequence (as a numerical value). The highest possible index in sequence s is s?size - 1 (since the index of the first subvariable is 0) assuming that the sequence has at least one subvariable.

Returns the sequence sorted in ascending order. (For descending order use this and then the reverse built in .) This will work only if all sub variables are strings, or if all sub variables are numbers, or if all sub variables are date values (date, time, or date+time), or if all sub variables are booleans (since 2.3.17). If the sub variables are strings, it uses locale (language) specific lexical sorting (which is usually not case sensitive). For example:

will print (with US locale at least):

Returns the sequence of hashes sorted by the given hash subvariable in ascending order. (For descending order use this and then the reverse built in .) The rules are the same as with the sort built-in , except that the sub variables of the sequence must be hashes, and you have to give the name of a hash subvariable that will decide the order. For example:

If the subvariable that you want to use for the sorting is on a deeper level (that is, if it is a subvariable of a subvariable and so on), then you can use a sequence as parameter, that specifies the names of the sub variables that lead down to the desired subvariable. For example:

Returns a sequence that only contains the elements of the input sequence which are before the first element that doesn't match the parameter predicate (filter condition). This is very similar to the filter built-in , so see further details there.

As you can see, take_while has stopped at the first number that didn't match the predicate ( x > 0 ), while filter has continued finding further matches.

See also: drop_while built-in

  • What is FreeMarker?
  • Version history
  • Privacy policy

Often used / Reference

  • Try template online
  • Expressions cheatsheet
  • .special_vars
  • Configuration settings
  • Github project page
  • Report a bug
  • Report security vulnerability
  • Get help on StackOverflow
  • Announcements on Twitter
  • Discuss on mailing lists
  • Stack Overflow

Last generated: 2024-06-02 12:06:49 GMT , for Freemarker 2.3.33

© 1999 –2024 The Apache Software Foundation . Apache FreeMarker, FreeMarker, Apache Incubator, Apache, the Apache FreeMarker logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.

IMAGES

  1. Spring MVC and FreeMarker Tutorial with Examples

    freemarker conditional assignment

  2. FreeMarker Tutorial for Beginners

    freemarker conditional assignment

  3. FreeMarker: Conditional Statements

    freemarker conditional assignment

  4. Introduction to FreeMarker Template (FTL). FTL Tutorial

    freemarker conditional assignment

  5. Introduction and use of freemarker

    freemarker conditional assignment

  6. Introduction and use of freemarker

    freemarker conditional assignment

VIDEO

  1. freeCodeCamp

  2. 10th Chapter : 5 Conditional Sentences Assignment 1, 2 .Solutions 2024 -25 Total English Morning

  3. freeCodeCamp

  4. Freemarker layout sample

  5. Conditional and selected signal assignment statements

  6. Module 9A: Three Address Code Generation for Simple Boolean Expressions

COMMENTS

  1. if, else, elseif

    Note: When you want to test if x > 0 or x >= 0, writing <#if x > 0> and <#if x >= 0> is WRONG, as the first > will close the #if tag. To work that around, write <#if x gt 0> or <#if gte 0>.Also note that if the comparison occurs inside parentheses, you will have no such problem, like <#if foo.bar(x > 0)> works as expected.

  2. If-else statement inside a parameter of a freemarker macro?

    That can have a non-string result and lazy-evaluates its parameters. In FreeMarker you can approach this as a boolean formatting task: [@printForm (myForm.id == 0)?string('add', 'change') /] Update: Here's a full working example: This does seem to work in a non freemarker scope, but when you use it as a parameter to a macro it doesn't work ...

  3. boolean assignment in freemarker using conditional statements

    In freemarker, can you assign a boolean value like this: [#if something = value] [#assign bool = true] [/#if] To then be used in a conditional statement like this: [#if bool] ...do something. [/#if] So far I have not been successful doing this in this format, but thought I might be missing something.

  4. Expressions

    When you supply value for interpolations: The usage of interpolations is ${ expression } where expression gives the value you want to insert into the output as text. So ${(5 + 8)/2} prints "6.5" to the output (or possibly "6,5" if the language of your output is not US English). When you supply a value for the directive parameter: You have ...

  5. FreeMarker Manual

    FreeMarker Manual -- For FreeMarker 2.3.20 HTML generated: 2013-06-27 20:54:33 GMT ...

  6. Built-ins for booleans

    The c built-in supports booleans since FreeMarker 2.3.20. This built-in converts a boolean to a "computer language" literal, as opposed to format it for human reading. This formats is independent of the boolean_format configuration setting, as that setting is meant to specify the format for human readers. Instead, it depends on the c_format ...

  7. Basics of Personalization in MessageGears (Using Freemarker)

    Condition Statements are a powerful part of the FreeMarker templating language. Conditional Statements are used to handle content that should only display if one or more conditions are met. ... Variables are established in FreeMarker using the Assign tag. Assigning variables can be done within one line of code, or broken into multiple lines to ...

  8. Conditional Statements

    When setting up a conditional statement you must begin by assigning a variable for any fields you want to reference using the #assign Freemarker Tag. At this point, the values for those variables are checked, a condition is included to account for edge cases, and the conditional statement is closed out.

  9. FreeMarker Common Operations

    spring.freemarker.setting.template_exception_handler=html_debug outputs the stack trace information to the client, formatting it so it will be usually well readable in the browser, and then re-throws the exception. spring.freemarker.setting.template_exception_handler=ignore skips the failing instructions, letting the template continue executing.

  10. Java FreeMarker

    FreeMarker is a template engine for the Java programming language. Templates are written in the FreeMarker Template Language (FTL). ... The <#assign> tag creates a new plain variable. It can be accessed with the ${} construct. The variable is created in the template. ... Conditional processing of template sections can be done with he <#if>, <# ...

  11. What is the freeMarker template engine?

    Conditional statements FreeMarker supports conditional logic such as if, else, and elseif to control the flow of template execution based on certain conditions.

  12. assign

    It can also be one of the assignment shorthand operators (since FreeMarker 2.3.23): ++, -- , +=, -= , *=, /= or %=. Like <#assign. x++> is similar to <#assign x = x +. 1>, and <#assign x += 2> is the same as <#assign x = x + 2> . Note that ++ always means arithmetical addition (an so it will fail on non-numbers), unlike + or += that are ...

  13. FreeMarker Manual

    If you know what namespaces are: assign directive creates variables in namespaces. Normally it creates the variable in the current namespace (i.e. in the namespace associated with the template where the tag is). However, if you use ... FreeMarker Manual -- For FreeMarker 2.3.20

  14. FreeMarker Java Template Engine

    A few highlights of FreeMarker: Powerful template language: Conditional blocks, iterations, assignments, string and arithmetic operations and formatting, macros and functions, including other templates, escaping by default (optional), and many more

  15. Ternary conditional operator

    For example, to pass conditionally different values as an argument for a constructor of a field or a base class, it is impossible to use a plain if-else statement; in this case we can use a conditional assignment expression, or a function call. Bear in mind also that some types allow initialization, but do not allow assignment, or even that the ...

  16. Comparing Variables in FreeMarker: getDataType Function

    Comparing Variables in FreeMarker: getDataType Function. FreeMarker is a popular templating engine that is used to generate dynamic web pages. It is a powerful tool that allows developers to separate the presentation logic from the business logic. One of the most common tasks when working with variables in FreeMarker is to determine their data ...

  17. Defining variables in the template

    You access variables defined in the template the same way as you access variables defined in the data-model root. For example, if you create a variable called "foo" in the template, you can print its value with ${foo}. If, coincidently, there's a variable called "foo" in the data-model too, the variable created in the template will hide (not ...

  18. freemarker

    2. That example should work equally well with #assign and #global. You had some kind of oversight there. As of #assign VS #global: Variables set via #assign are only visible from the template where they were assigned, plus in the templates that where #include -d in that template (or #include -d in an #include -d template, etc.), because # ...

  19. Built-ins for sequences

    This built-in splits a sequence into multiple sequences of the size given with the 1st parameter to the built-in (like mySeq?chunk(3) ). The result is the sequence of these sequences. The last sequence is possibly shorter than the given size, unless the 2nd parameter is given (like mySeq?chunk(3, '-') ), that is the item used to make up the ...