What’s FreeMarker 3 (FM3 from now on)

The most important goal of FM3 is to fix/evolve the template language without backward-compatibility constraints (because otherwise it's just impossible to do many things). As that way we are breaking backward compatibility anyway, the Java API and many internals also go through heavy cleanup and refactoring.

There's no plan for discontinuing or deprecating FreeMarker 2.x (FM2 from now on). FM3 is rather an additional, significantly better templating solution, primarily targeting new projects looking for the best option available. (Note that FM2 and FM3 can be used next to each other in the same application, as they live in different Java packages.)

Note that FM3 is not a rewrite from scratch. It has branched out from FM2, and works gradually towards its goals, with maintaining a passing test suite. This branch can be found here: https://github.com/apache/incubator-freemarker/tree/3

Why is this branch necessary?

The 15 years of backward compatibility constraints FM2 drags with itself is very significant at this point (it often prevents improvements, and the legacy/deprecates features complicate usage and maintenance). New projects that need a template engine and choose FreeMarker are clearly negatively affected by this legacy burden, while backward compatibility with FM2 doesn’t add much value for them. So while supporting existing projects is important, sticking to FM2 means extra cost for the new projects, which always grow in number, while the number of active old projects decreases.

As of existing products that depend on FM2, migration to FM3 can be quite expensive, mostly because the fully automatic conversion of the templates will not be possible (due to changes in template language semantics). For some projects it may still worth migrating on the long run. For some applications, especially those which support multiple template engines anyway, using FM3 only for the new templates, or gradually migrating existing templates can be a viable option too.

So what FreeMarker 3 will be like?

Some of the more important planned changes are listed bellow. But nothing is graved into stone until we do a release, so we are open for ideas, recommendations. It’s also possible that due to time constraints some of these will be skipped (though there's no set deadline):

API and architecture:

  • Switching to org.apache.freemarker package and Maven group. [Status: Done]
  • Modularization: FM2 is one big jar, which contains lot of non-core functionality. FM3 should be split to multiple modules (jar-s, sub-projects), especially the Servlet/JSP support should be factored out. [Status: Done; we have freemarker-core.jar, freemarker-servlet.jar, etc. See the aggregate JavaDoc here; each org.apache.freemarker subpackage is a module.]
  • Configuration (and TemplateConfiguration and Template) should be immutable. Builder and fluent API-s should be used to configure them. [Status: Done, see Configuration.Builder, etc.]
  • Change Configuration defaults to fit best practices [Status: Done]
  • Switch the build system from Ant to Gradle [Status: Partially done; the project has already switched to Gradle, but additional tasks will be needed for distribution and such.]
  • Template loading/caching architecture improvements:
    • Better TemplateLoader, especially considering more efficient loading for databases [Status: Done]
    • Optionally allow the whole loading/caching mechanism to be replaced, as opposed to only replacing some aspects of the hard-wired logic [Status: Done, see TemplateResolver]
    • Two layer caching: When two different template lookups point to the same physical template “file”, they should use a common entry from a 2nd level cache, rather than loading/caching the same template twice. [Status: Possible solutions were discussed]
    • The template acquisition feature need to be fixed (or dropped) [Status: Not done]
  • Either clean up the TemplateModel API‑s (especially, hashes should support non-string keys), or switch to MOP mechanism instead of object wrapping [Status: Some API cleanup was done]
  • Unify the various FM2 callable FTL types (TemplateDirectiveModel-s, TemplateTransformModel-s, macros, functions (defined in template), TemplateMethodModel-s, TemplateMethodModelEx-s, etc.) into fever, more universal classes. [Status: Done. See the new TemplateDirectiveModel and TemplateFunctionModel, which together replace all legacy interfaces. These support both named and positional parameters, just like macros. Also, #macro and #function now creates a TemplateDirectiveModel-s or TemplateFunctionModel, respectively.]
  • New API-s needed for "custom dialects" feature (see later). Such as, allow defining custom directives and custom functions (callable as built-ins), which are looked up and bound to the template during the parsing phase. [Status: Not done]
  • Android compatibility [Status: Not done]
  • Various smaller cleanup tasks [Status: A lot of it was done… like we have switched to SLF4J and removed the internal log abstraction, removed the support for emulating old bugs, replaced int constants with Java 5 enums on most places, etc.]

Template language:

  • Support camel case naming convention only (such as <#outputFormat '...'>, x?upperCase, <#setting dateFormat='...'>) [Status: Done]

  • Remove support for legacy syntax and deprecated directives/built-ins [Status: Partially done]
  • Allow both positional and named parameters in the same invocation, for both directives (macros) and functions (and built-ins) [Status: Done]

  • Make the syntax of directives more regular. This helps tooling, learning, and will be needed for custom dialects (see later). [Status: Not done]

  • Allow examining the content of templates programmatically, with published API [Status: Not done]

  • Support “dialects”, that is, to add application specific new directives/built-ins that are as convenient and terse to invoke as core ones. (It must be obvious for the users if they are using a non-standard dialect, like from the different file extension.) [Status: Not done]

  • Better null handling: Differentiate null and missing in some cases, more convenient null/missing handler operators. [Status: Not done, but there's a plan on how to do it]

  • Replace #assign/#global/#local with #var/#set. Allow block-scope variables. [Status: Not done]

  • Directives (macros) should support something similar to named bodies aka. fragments. [Status: Not done]

  • Should support alternative syntaxes to avoid clashes with the generated content, especially with “${“ [Status: Not done]

  • Better white-space control (including option for dynamic indentation) [Status: Not done]

  • Allow literal "-" at directive name position and named-argument name position [Status: Not done]

  • Namespace prefixes with colon, to allow tricks like calling an user defined function with built-in syntax, and more [Status: Not done]

Note that the detailed change log can be found here: https://github.com/apache/incubator-freemarker/blob/3/FM3-CHANGE-LOG.txt

  • No labels