This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/docs by this push:
     new d0ac4ac7e6 docs: FreeMarker view module topic page + 9.5.0 
release-notes entry + view-module cross-links (TODO-84)
d0ac4ac7e6 is described below

commit d0ac4ac7e6b7ed8d351afdf2768df799e716d0df
Author: James Bognar <[email protected]>
AuthorDate: Tue May 26 13:25:48 2026 -0400

    docs: FreeMarker view module topic page + 9.5.0 release-notes entry + 
view-module cross-links (TODO-84)
    
    Co-authored-by: Cursor <[email protected]>
---
 pages/release-notes/9.5.0.md                 |  53 ++++-
 pages/topics/10.14d.JspViewSupport.md        |   7 +-
 pages/topics/10.14e.ThymeleafViewSupport.md  |   8 +-
 pages/topics/10.14f.MustacheViewSupport.md   |   8 +-
 pages/topics/10.14g.FreemarkerViewSupport.md | 298 +++++++++++++++++++++++++++
 sidebars.ts                                  |   5 +
 6 files changed, 369 insertions(+), 10 deletions(-)

diff --git a/pages/release-notes/9.5.0.md b/pages/release-notes/9.5.0.md
index 6944b97074..78c624ac21 100644
--- a/pages/release-notes/9.5.0.md
+++ b/pages/release-notes/9.5.0.md
@@ -3189,7 +3189,7 @@ See <a 
href="/docs/topics/MicroserviceCoreInject">Inject-Aware Microservice</a>
 
 #### `View` interface — engine-agnostic server-side render contract
 
-- New `org.apache.juneau.rest.view.View` interface. Carries the data a 
templating engine needs to render a response: `String getTemplateName()`, 
`Map<String, Object> getAttributes()`, and a `default Map<String, String> 
getResponseHeaders()` seam. Engine-agnostic — concrete implementations live in 
per-engine bridge modules (`juneau-rest-server-view-jsp`, 
`juneau-rest-server-view-thymeleaf`, and `juneau-rest-server-view-mustache` all 
ship in 9.5.0; a FreeMarker bridge is queued behind them).
+- New `org.apache.juneau.rest.view.View` interface. Carries the data a 
templating engine needs to render a response: `String getTemplateName()`, 
`Map<String, Object> getAttributes()`, and a `default Map<String, String> 
getResponseHeaders()` seam. Engine-agnostic — concrete implementations live in 
per-engine bridge modules (`juneau-rest-server-view-jsp`, 
`juneau-rest-server-view-thymeleaf`, `juneau-rest-server-view-mustache`, and 
`juneau-rest-server-view-freemarker` all ship in 9.5.0; Pha [...]
 - Designed as the stable extension point for the new view-module family. New 
methods will be added as `default`-bodied where possible to preserve backward 
compatibility with downstream view impls.
 
 ```java
@@ -3857,6 +3857,57 @@ public class AppResource extends RestServlet {
 
 See [Mustache View Support](/docs/topics/MustacheViewSupport) for the full 
topic — engine-selection matrix, Spring Boot integration notes (Spring Boot's 
official starter ships `jmustache`, not `mustache.java`), path-traversal 
hardening, and known limitations.
 
+### juneau-rest-server-view-freemarker (new module)
+
+A new opt-in REST module, `juneau-rest-server-view-freemarker`, adds [Apache 
FreeMarker](https://freemarker.apache.org/) view-rendering to 
`juneau-rest-server` — sibling to `juneau-rest-server-view-jsp`, 
`juneau-rest-server-view-thymeleaf`, and `juneau-rest-server-view-mustache`. 
The same `View` interface (see [juneau-rest-server](#juneau-rest-server)) 
shipped with 9.5.0 backs all four bridges; with this module, the Phase B 
sibling lineup is complete. Engine-agnostic POM stance: the brid [...]
+
+FreeMarker is the engine behind countless admin consoles, code generators, 
email templates, and reporting tools — Apache-family alignment (ASF-maintained 
engine, same license as Juneau itself), richer expression syntax than 
logic-less Mustache, and native HTML auto-escaping via the `.ftlh` template 
flavor. The core engine has zero servlet-container dependencies; it asks 
`freemarker.template.Configuration` for a `Template` and 
`template.process(dataModel, writer)` streams the rendered out [...]
+
+#### New Classes
+
+- **`org.apache.juneau.rest.view.freemarker.BasicFreemarkerResource`** — REST 
mixin attachable via `@Rest(mixins=BasicFreemarkerResource.class)`. Adds a 
default `/freemarker/*` mount that renders raw `.ftl` / `.ftlh` templates under 
the configured base path, and contributes `FreemarkerViewRenderer` to the 
mixin's response-processor chain. Builder API: 
`BasicFreemarkerResource.create().basePath("/templates/").templateSuffix(".ftlh").cacheTemplates(true).build()`.
 Configurable mount path v [...]
+- **`org.apache.juneau.rest.view.freemarker.FreemarkerView`** — `View` 
implementation. Immutable value class; fluent builder: 
`FreemarkerView.of("hello.ftlh").attr("name", name).header("Cache-Control", 
"no-store")`. `attr(...)` rejects `null` values to surface caller bugs early.
+- **`org.apache.juneau.rest.view.freemarker.FreemarkerViewRenderer`** — 
`ResponseProcessor` that detects `FreemarkerView`-typed return values and asks 
the configured `freemarker.template.Configuration` to 
`getTemplate(name).process(dataModel, writer)` directly onto the response 
writer. When no FreeMarker engine is on the classpath, surfaces 
`NO_ENGINE_DIAGNOSTIC` naming the missing dependency (with a pointer to 
`spring-boot-starter-freemarker` for Spring Boot apps).
+
+#### Dependency
+
+```xml
+<dependency>
+    <groupId>org.apache.juneau</groupId>
+    <artifactId>juneau-rest-server-view-freemarker</artifactId>
+    <version>9.5.0</version>
+</dependency>
+<!-- engine: -->
+<dependency>
+    <groupId>org.freemarker</groupId>
+    <artifactId>freemarker</artifactId>
+    <version>2.3.34</version>
+</dependency>
+```
+
+#### Composition example
+
+```java
+@Rest(path="/app", mixins=BasicFreemarkerResource.class)
+public class AppResource extends RestServlet {
+
+    @Bean
+    BasicFreemarkerResource freemarker() {
+        return BasicFreemarkerResource.create()
+            .basePath("/templates/")
+            .templateSuffix(".ftlh")
+            .build();
+    }
+
+    @RestGet("/hello/{name}")
+    public View hello(@Path String name) {
+        return FreemarkerView.of("hello").attr("name", name);
+    }
+}
+```
+
+See [FreeMarker View Support](/docs/topics/FreemarkerViewSupport) for the full 
topic — engine-selection matrix, Spring Boot integration notes 
(`spring-boot-starter-freemarker` autoconfigures a `Configuration` bean the 
bridge picks up automatically), `.ftl` vs `.ftlh` auto-escape selection, 
template caching, path-traversal hardening, and known limitations.
+
 ### juneau-bean-rfc7807 (new module)
 
 A new bean module, `juneau-bean-rfc7807`, provides typed beans for [RFC 7807 — 
Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc7807) 
(`application/problem+json`). RFC 7807 was obsoleted by [RFC 
9457](https://www.rfc-editor.org/rfc/rfc9457) in July 2023, but the data model 
and the IANA media-type registration are unchanged.
diff --git a/pages/topics/10.14d.JspViewSupport.md 
b/pages/topics/10.14d.JspViewSupport.md
index 110c57b5c0..c48f39c0fb 100644
--- a/pages/topics/10.14d.JspViewSupport.md
+++ b/pages/topics/10.14d.JspViewSupport.md
@@ -11,9 +11,9 @@ The `juneau-rest-server-view-jsp` module adds JSP (JavaServer 
Pages) view-render
 > This page covers the JSP-specific bridge. For the engine-agnostic
 > [`View`](/site/apidocs/org/apache/juneau/rest/view/View.html) interface 
 > itself, see the
 > [9.5.0 release notes](/docs/release-notes/9.5.0) under the 
 > `juneau-rest-server` section.
-> Sibling view modules [Thymeleaf](/docs/topics/ThymeleafViewSupport) and
-> [Mustache](/docs/topics/MustacheViewSupport) ship the same shape in 9.5.0; a 
FreeMarker
-> bridge is queued behind them.
+> Sibling view modules [Thymeleaf](/docs/topics/ThymeleafViewSupport),
+> [Mustache](/docs/topics/MustacheViewSupport), and
+> [FreeMarker](/docs/topics/FreemarkerViewSupport) ship the same shape in 
9.5.0.
 
 ## Why JSP?
 
@@ -236,5 +236,6 @@ Both subclasses mount independently and each resolves 
templates against its own
 - [REST Server — Static-Files Mixin](/docs/topics/StaticFilesMixin)
 - [Thymeleaf View Support](/docs/topics/ThymeleafViewSupport) — sibling bridge 
for Thymeleaf
 - [Mustache View Support](/docs/topics/MustacheViewSupport) — sibling bridge 
for Mustache
+- [FreeMarker View Support](/docs/topics/FreemarkerViewSupport) — sibling 
bridge for FreeMarker
 - [Response Processors](/docs/topics/ResponseProcessors)
 - [9.5.0 release notes — `juneau-rest-server-view-jsp` (new 
module)](/docs/release-notes/9.5.0)
diff --git a/pages/topics/10.14e.ThymeleafViewSupport.md 
b/pages/topics/10.14e.ThymeleafViewSupport.md
index 05bfaa48ec..d8faaaf3f0 100644
--- a/pages/topics/10.14e.ThymeleafViewSupport.md
+++ b/pages/topics/10.14e.ThymeleafViewSupport.md
@@ -12,9 +12,10 @@ the core.
 > This page covers the Thymeleaf-specific bridge. For the engine-agnostic
 > [`View`](/site/apidocs/org/apache/juneau/rest/view/View.html) interface 
 > itself, see the
 > [9.5.0 release notes](/docs/release-notes/9.5.0) under the 
 > `juneau-rest-server` section.
-> The sibling [JSP View Support](/docs/topics/JspViewSupport) and
-> [Mustache View Support](/docs/topics/MustacheViewSupport) pages cover the 
JSP and
-> Mustache bridges with the same shape; a future FreeMarker bridge will ship 
the same way.
+> The sibling [JSP View Support](/docs/topics/JspViewSupport),
+> [Mustache View Support](/docs/topics/MustacheViewSupport), and
+> [FreeMarker View Support](/docs/topics/FreemarkerViewSupport) pages cover 
the JSP,
+> Mustache, and FreeMarker bridges with the same shape.
 
 ## Why Thymeleaf?
 
@@ -238,6 +239,7 @@ Both subclasses mount independently and each resolves 
templates against its own
 - [REST Server — Composition (mixins, 
paths)](/docs/topics/RestServerComposition)
 - [JSP View Support](/docs/topics/JspViewSupport) — sibling bridge for 
JSP-based apps
 - [Mustache View Support](/docs/topics/MustacheViewSupport) — sibling bridge 
for Mustache
+- [FreeMarker View Support](/docs/topics/FreemarkerViewSupport) — sibling 
bridge for FreeMarker
 - [Response Processors](/docs/topics/ResponseProcessors)
 - [9.5.0 release notes — `juneau-rest-server-view-thymeleaf` (new 
module)](/docs/release-notes/9.5.0)
 - [Thymeleaf 3 documentation](https://www.thymeleaf.org/documentation.html)
diff --git a/pages/topics/10.14f.MustacheViewSupport.md 
b/pages/topics/10.14f.MustacheViewSupport.md
index c240f376d5..65330eabe5 100644
--- a/pages/topics/10.14f.MustacheViewSupport.md
+++ b/pages/topics/10.14f.MustacheViewSupport.md
@@ -12,9 +12,10 @@ the core.
 > This page covers the Mustache-specific bridge. For the engine-agnostic
 > [`View`](/site/apidocs/org/apache/juneau/rest/view/View.html) interface 
 > itself, see the
 > [9.5.0 release notes](/docs/release-notes/9.5.0) under the 
 > `juneau-rest-server` section.
-> The sibling [JSP View Support](/docs/topics/JspViewSupport) and
-> [Thymeleaf View Support](/docs/topics/ThymeleafViewSupport) pages cover the 
JSP and
-> Thymeleaf bridges with the same shape; a future FreeMarker bridge will ship 
the same way.
+> The sibling [JSP View Support](/docs/topics/JspViewSupport),
+> [Thymeleaf View Support](/docs/topics/ThymeleafViewSupport), and
+> [FreeMarker View Support](/docs/topics/FreemarkerViewSupport) pages cover 
the JSP,
+> Thymeleaf, and FreeMarker bridges with the same shape.
 
 ## Why Mustache?
 
@@ -249,6 +250,7 @@ Both subclasses mount independently and each resolves 
templates against its own
 - [REST Server — Composition (mixins, 
paths)](/docs/topics/RestServerComposition)
 - [JSP View Support](/docs/topics/JspViewSupport) — sibling bridge for 
JSP-based apps
 - [Thymeleaf View Support](/docs/topics/ThymeleafViewSupport) — sibling bridge 
for Thymeleaf
+- [FreeMarker View Support](/docs/topics/FreemarkerViewSupport) — sibling 
bridge for FreeMarker
 - [Response Processors](/docs/topics/ResponseProcessors)
 - [9.5.0 release notes — `juneau-rest-server-view-mustache` (new 
module)](/docs/release-notes/9.5.0)
 - [mustache.java on GitHub](https://github.com/spullara/mustache.java)
diff --git a/pages/topics/10.14g.FreemarkerViewSupport.md 
b/pages/topics/10.14g.FreemarkerViewSupport.md
new file mode 100644
index 0000000000..bc90eca922
--- /dev/null
+++ b/pages/topics/10.14g.FreemarkerViewSupport.md
@@ -0,0 +1,298 @@
+---
+title: "FreeMarker View Support"
+slug: FreemarkerViewSupport
+---
+
+# FreeMarker View Support
+
+The `juneau-rest-server-view-freemarker` module adds
+[Apache FreeMarker](https://freemarker.apache.org/) view-rendering to 
`juneau-rest-server`
+without bleeding the FreeMarker engine dependency into the core.
+
+> This page covers the FreeMarker-specific bridge. For the engine-agnostic
+> [`View`](/site/apidocs/org/apache/juneau/rest/view/View.html) interface 
itself, see the
+> [9.5.0 release notes](/docs/release-notes/9.5.0) under the 
`juneau-rest-server` section.
+> The sibling [JSP View Support](/docs/topics/JspViewSupport),
+> [Thymeleaf View Support](/docs/topics/ThymeleafViewSupport), and
+> [Mustache View Support](/docs/topics/MustacheViewSupport) pages cover the 
JSP, Thymeleaf,
+> and Mustache bridges with the same shape.
+
+## Why FreeMarker?
+
+Apache FreeMarker is a mature, widely deployed Java templating engine — the 
engine behind
+admin consoles, code generators, email templates, and reporting tools in 
countless
+production codebases. The reference implementation
+[`org.freemarker:freemarker`](https://freemarker.apache.org/) has zero 
servlet-container
+dependencies, renders directly to a `java.io.Writer`, and runs unchanged under 
MockRest,
+Jetty microservices, and Spring Boot. It's the recommended choice when you 
want a richer
+expression syntax than logic-less Mustache, native HTML auto-escaping
+(`.ftlh` templates), and the Apache-family alignment bonus of an 
ASF-maintained engine
+matching Juneau's own license stance.
+
+## Module contents
+
+| Class | Role |
+|---|---|
+| [`View`](/site/apidocs/org/apache/juneau/rest/view/View.html) (in 
`juneau-rest-server` core) | Engine-agnostic contract: `getTemplateName()`, 
`getAttributes()`, `getResponseHeaders()`. |
+| 
[`BasicFreemarkerResource`](/site/apidocs/org/apache/juneau/rest/view/freemarker/BasicFreemarkerResource.html)
 | Mixin. Mounts `/freemarker/*` for raw `.ftl` / `.ftlh` template requests; 
registers `FreemarkerViewRenderer` on the response-processor chain. Builder: 
`basePath(String)` (default `/`), `templateSuffix(String)` (default `""`), 
`cacheTemplates(boolean)` (default `true`). |
+| 
[`FreemarkerView`](/site/apidocs/org/apache/juneau/rest/view/freemarker/FreemarkerView.html)
 | `View` implementation. Immutable; fluent: 
`FreemarkerView.of("hello.ftlh").attr("name", name).header("Cache-Control", 
"no-store")`. |
+| 
[`FreemarkerViewRenderer`](/site/apidocs/org/apache/juneau/rest/view/freemarker/FreemarkerViewRenderer.html)
 | `ResponseProcessor` that detects `FreemarkerView` returns and asks the 
configured `freemarker.template.Configuration` to 
`getTemplate(name).process(dataModel, writer)` directly onto the response 
writer. |
+
+## Engine-agnostic packaging
+
+`juneau-rest-server-view-freemarker` ships **only `org.freemarker:freemarker` 
in `provided`
+scope**. No engine is bundled with the bridge module. Consumers add the engine 
matching
+their deployment.
+
+### Choosing a `Configuration`
+
+| Deployment | Recommended setup | Maven coordinates |
+|---|---|---|
+| **Juneau microservice / Jetty / MockRest** | Bridge-default `Configuration` 
(built on first use, anchored on the importer's classloader and the configured 
`basePath`; pins `IncompatibleImprovements` to `VERSION_2_3_34`, sets 
`DefaultEncoding=UTF-8`, uses `HTMLOutputFormat`) | `org.freemarker:freemarker` 
|
+| **Spring Boot** | `spring-boot-starter-freemarker` autoconfigures a 
`freemarker.template.Configuration` bean the bridge picks up automatically | 
`org.springframework.boot:spring-boot-starter-freemarker` |
+| **Custom loaders / output formats / shared template caches** | User-supplied 
`@Bean freemarker.template.Configuration` (configure your own `TemplateLoader`, 
`OutputFormat`, etc.) | Whatever you build on top of `freemarker` |
+
+The bridge picks up a `Configuration` bean from the request's `BeanStore` via
+`BeanStore.getBean(Configuration.class)` first; if no configuration bean is 
registered, it
+constructs a default `Configuration` rooted at the classpath directory derived 
from
+`basePath` (e.g. `basePath("/templates/")` → classloader resource root 
`/templates`).
+
+When no FreeMarker engine is on the classpath, the renderer surfaces a clear 
diagnostic
+naming the missing dependency:
+
+```text
+No Apache FreeMarker engine is available on the classpath. Add:
+  - org.freemarker:freemarker                       (FreeMarker engine core)
+Or, for Spring Boot:
+  - org.springframework.boot:spring-boot-starter-freemarker
+    (autoconfigures a freemarker.template.Configuration bean the bridge picks 
up).
+Or register a custom @Bean freemarker.template.Configuration with whatever 
loaders /
+encodings / output formats you need.
+See https://juneau.apache.org/docs/topics/FreemarkerViewSupport for the full 
matrix.
+```
+
+## Hello-world
+
+### Maven
+
+```xml
+<dependency>
+    <groupId>org.apache.juneau</groupId>
+    <artifactId>juneau-rest-server-view-freemarker</artifactId>
+    <version>9.5.0</version>
+</dependency>
+<!-- engine: -->
+<dependency>
+    <groupId>org.freemarker</groupId>
+    <artifactId>freemarker</artifactId>
+    <version>2.3.34</version>
+</dependency>
+```
+
+### Resource layout
+
+```text
+src/main/resources/
+  templates/
+    hello.ftlh
+```
+
+### FreeMarker template (`hello.ftlh`)
+
+`.ftlh` is FreeMarker's HTML-auto-escaping template flavor — variable 
references emit
+HTML-escaped output by default, defending against XSS regressions:
+
+```html
+<!DOCTYPE html>
+<html>
+<head><title>Hello</title></head>
+<body>
+<p>Hello, ${name}!</p>
+</body>
+</html>
+```
+
+Use the `.ftl` extension instead if you want raw (un-escaped) output — typical 
for
+plain-text email bodies or JSON-shaped responses where the caller controls 
escaping.
+
+### REST resource — `View`-return dispatch
+
+```java
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.servlet.*;
+import org.apache.juneau.rest.view.*;
+import org.apache.juneau.rest.view.freemarker.*;
+
+@Rest(path="/app", mixins=BasicFreemarkerResource.class)
+public class AppResource extends RestServlet {
+
+    @Bean
+    BasicFreemarkerResource freemarker() {
+        return BasicFreemarkerResource.create()
+            .basePath("/templates/")
+            .templateSuffix(".ftlh")
+            .build();
+    }
+
+    @RestGet("/hello/{name}")
+    public View hello(@Path String name) {
+        return FreemarkerView.of("hello").attr("name", name);
+    }
+}
+```
+
+`GET /app/hello/world` returns `Hello, world!` — `FreemarkerViewRenderer` 
intercepts the
+`FreemarkerView` return, hands the view's attributes to the active 
`Configuration` as the
+data model, and asks the resolved `Template` to render `/templates/hello.ftlh` 
directly onto
+the response writer. The `.ftlh` suffix is appended idempotently because the 
builder
+declared it.
+
+### REST resource — raw-template mount
+
+The mixin also installs a default `/freemarker/*` mount that renders raw 
templates under
+the configured base path. With `basePath("/templates/")` and 
`templateSuffix(".ftlh")`, a
+request for `GET /app/freemarker/about` renders `/templates/about.ftlh` 
directly — no Java
+handler required. The handler appends the configured `templateSuffix` if the 
requested path
+doesn't already end with it, so `/app/freemarker/about.ftlh` works too.
+
+The greedy `/*` handler is excluded from the generated Swagger / OpenAPI spec 
via
+`@OpSwagger(ignore=true)` since the path isn't API-meaningful.
+
+### Configurable mount path (SVL)
+
+The default mount `/freemarker/*` can be overridden via the SVL variable
+`${juneau.freemarker.path:freemarker}` — set via system property
+(`-Djuneau.freemarker.path=views`), environment variable 
(`JUNEAU_FREEMARKER_PATH=views`),
+or `Config` key (`juneau.freemarker.path = views`) to change the runtime mount 
without
+subclassing.
+
+## Path-traversal protection
+
+The raw-template handler funnels every user-supplied `@Path("/*") String path` 
through
+[`FileUtils.resolveVirtualPathSafely(String, 
String)`](/site/apidocs/org/apache/juneau/commons/utils/FileUtils.html#resolveVirtualPathSafely-java.lang.String-java.lang.String-)
+and rejects any `..` traversal that escapes the configured `basePath` with 
HTTP 403. Both
+direct (`/freemarker/../secret`) and nested
+(`/freemarker/a/b/../../../secret`) traversal attempts are blocked at the 
handler boundary
+before reaching the engine resolver. This is the same hardening the JSP / 
Thymeleaf /
+Mustache bridges apply; see
+[`BasicFreemarkerResource_PathTraversal_Test`](https://github.com/apache/juneau/blob/main/juneau-utest/src/test/java/org/apache/juneau/rest/view/freemarker/BasicFreemarkerResource_PathTraversal_Test.java)
+for the canonical coverage.
+
+## Template caching
+
+By default the bridge-built `Configuration` pins
+`TemplateUpdateDelayMilliseconds` to `Long.MAX_VALUE` — FreeMarker caches 
compiled templates
+indefinitely, which is the production-safe default. Toggle the builder's
+`cacheTemplates(false)` to set the delay to `0`, causing FreeMarker to 
re-check the
+underlying resource on every render (suitable for dev hot-reload):
+
+```java
+@Bean
+BasicFreemarkerResource freemarker() {
+    return BasicFreemarkerResource.create()
+        .basePath("/templates/")
+        .templateSuffix(".ftlh")
+        .cacheTemplates(false)   // dev hot-reload
+        .build();
+}
+```
+
+This flag only affects the **bridge-default** `Configuration`. User-supplied
+`@Bean Configuration` instances are not mutated; configure caching directly on 
your own
+bean.
+
+## Spring Boot integration
+
+Spring Boot ships `spring-boot-starter-freemarker`, which autoconfigures a
+`freemarker.template.Configuration` bean pre-wired with sane defaults
+(classpath:`/templates/` loader, UTF-8 encoding, view caching toggled on
+`spring.freemarker.cache`). The bridge picks that bean up automatically:
+
+```java
+@Configuration
+public class AppConfig {
+
+    // No @Bean Configuration needed — spring-boot-starter-freemarker provides 
one.
+
+    @Bean
+    public BasicFreemarkerResource freemarker() {
+        return BasicFreemarkerResource.create()
+            .basePath("/templates/")
+            .templateSuffix(".ftlh")
+            .build();
+    }
+}
+```
+
+The Spring `BeanStore` adapter resolves the autoconfigured `Configuration` 
through
+`ApplicationContext.getBean(...)`; no additional plumbing is required. The 
bridge default
+is bypassed entirely when the starter is on the classpath.
+
+### Known constraint — response-processor ordering
+
+Juneau's default response-processor chain runs `SerializedPojoProcessor` ahead 
of
+mixin-registered processors. When the host class has a method returning 
`FreemarkerView`,
+the host class needs to add `FreemarkerViewRenderer` to its *own* 
`responseProcessors` list
+to take precedence over the generic POJO serializer. Tracked as a framework 
enhancement to
+add a `prepend` mechanism for mixin processors (TODO-96); the real-container 
integration
+tests that exercise the `View`-return path under embedded Tomcat / Jetty are 
deferred until
+that lands (the FreeMarker analog of TODO-97 for JSP, TODO-107 for Thymeleaf, 
and TODO-108
+for Mustache).
+
+## Multiple base paths
+
+Some apps want `/views/` for the public site and `/admin/views/` for the admin 
console.
+Register two `BasicFreemarkerResource` beans, each in its own subclass with 
its own
+`paths` override:
+
+```java
+@Rest(paths={"/views/*"})
+public class PublicViewsResource extends BasicFreemarkerResource {
+    public PublicViewsResource() {
+        super(BasicFreemarkerResource.create()
+            .basePath("/templates/public/")
+            .templateSuffix(".ftlh"));
+    }
+}
+
+@Rest(paths={"/admin/views/*"})
+public class AdminViewsResource extends BasicFreemarkerResource {
+    public AdminViewsResource() {
+        super(BasicFreemarkerResource.create()
+            .basePath("/templates/admin/")
+            .templateSuffix(".ftlh"));
+    }
+}
+```
+
+Both subclasses mount independently and each resolves templates against its own
+`basePath`.
+
+## Limitations and out-of-scope
+
+- **No bridge-default `Configuration` mutation for user beans.** The
+  `cacheTemplates(boolean)` builder knob only configures the *bridge-default*
+  `Configuration`. If you provide your own `@Bean Configuration` (Spring Boot 
autoconfig
+  counts), configure caching directly on that bean — the bridge does not 
mutate it.
+- **`.ftlh` is the recommended HTML default.** FreeMarker's auto-escape 
selection is by
+  file extension. For HTML responses prefer `.ftlh`; using `.ftl` for HTML 
leaves variable
+  references un-escaped and risks XSS regressions when an attribute binding is 
later
+  changed to come from user input. The bridge does not force a suffix — that's 
the
+  consumer's choice.
+- **Macros, includes, and FreeMarker imports are users' responsibility.** The 
bridge
+  passes template names through unchanged to 
`Configuration.getTemplate(name)`; macros,
+  `<#import>`, and `<#include>` resolve through whatever `TemplateLoader` your 
active
+  `Configuration` is wired with (the bridge default uses a single 
classloader-rooted
+  loader anchored on `basePath`).
+
+## See also
+
+- [REST Server — Composition (mixins, 
paths)](/docs/topics/RestServerComposition)
+- [JSP View Support](/docs/topics/JspViewSupport) — sibling bridge for 
JSP-based apps
+- [Thymeleaf View Support](/docs/topics/ThymeleafViewSupport) — sibling bridge 
for Thymeleaf
+- [Mustache View Support](/docs/topics/MustacheViewSupport) — sibling bridge 
for Mustache
+- [Response Processors](/docs/topics/ResponseProcessors)
+- [9.5.0 release notes — `juneau-rest-server-view-freemarker` (new 
module)](/docs/release-notes/9.5.0)
+- [Apache FreeMarker](https://freemarker.apache.org/)
+- [FreeMarker template language 
reference](https://freemarker.apache.org/docs/index.html)
diff --git a/sidebars.ts b/sidebars.ts
index b6e570a239..07a29cea72 100644
--- a/sidebars.ts
+++ b/sidebars.ts
@@ -1407,6 +1407,11 @@ const sidebars: SidebarsConfig = {
                                                        id: 
'topics/10.14f.MustacheViewSupport',
                                                        label: '10.14f. 
Mustache View Support',
                                                },
+                                               {
+                                                       type: 'doc',
+                                                       id: 
'topics/10.14g.FreemarkerViewSupport',
+                                                       label: '10.14g. 
FreeMarker View Support',
+                                               },
                                                {
                                                        type: 'doc',
                                                        id: 
'topics/10.15.ClientVersioning',

Reply via email to