Class StaticFilesMixin

java.lang.Object
org.apache.juneau.rest.server.staticfile.StaticFilesMixin

public class StaticFilesMixin extends Object
Mixin that serves static files from the active StaticFiles implementation under /static/* (configurable).

Wraps the existing BasicStaticFiles plumbing (a StaticFiles implementation, not a servlet) in a servlet-level mixin so any Juneau resource can opt into static-file serving via @Rest(mixins=StaticFilesMixin.class). The mixin reads the active StaticFiles from the bean store at request time — importer's @Bean StaticFiles declarations + classpath defaults are picked up automatically.

Configurable mount path:

The default mount /static/* can be overridden via the SVL variable ${juneau.staticfiles.path:static} — set via system property (-Djuneau.staticfiles.path=assets), environment variable (JUNEAU_STATICFILES_PATH=assets), or Config key (juneau.staticfiles.path = assets) to change the runtime mount without subclassing. Resolution happens once at RestContext construction time (SVL resolution in @RestOp(path)).

Override accepts bare token (static), leading slash (/static), trailing slash (static/), or wildcard suffix (/static/*) — all resolve to the same mount.

Migration note (10.0.0): Earlier development snapshots of this mixin mounted at both /static/* and /htdocs/* as historical convenience aliases — that dual default has been collapsed to a single SVL-configurable mount as part of the "single path per op" principle. Deployers who relied on the /htdocs/* alias must now either set -Djuneau.staticfiles.path=htdocs or compose a second resource mounted with the htdocs override. The default StaticFiles classpath search root still walks both static/ and htdocs/ directories — only the URL-side mount is now single.

Mixin-only deployment:

This resource is designed for composition via @Rest(mixins=...). The mount path is pinned at the op level by @RestGet(path="/{juneau.staticfiles.path:static}/*") on getStaticFile(org.apache.juneau.rest.server.RestRequest, java.lang.String, java.util.Locale) (and the matching RestOp for HEAD); a class-level @Rest(paths=...) declaration would be silently ignored under the mixin pattern (see @Rest(paths) Javadoc).

Composition example:

// Vanilla resource gains static-file serving at /static/*. @Rest(path="/api", mixins=StaticFilesMixin.class) public class ApiResource extends RestServlet { @RestGet("/items") public List<Item> items() { ... } }

Behavior:
  • GET hits the active StaticFiles bean (resolved via RestRequest.getStaticFiles()); missing paths surface as NotFound thrown from the handler.
  • HEAD requests are accepted via the standard servlet HEAD-via-GET contract: the response carries identical headers to the corresponding GET (including Cache-Control and Content-Type) with an empty body.
  • Cache-Control headers come from the BasicStaticFiles default (max-age=86400, public); importers can override via BasicStaticFiles.create(beanStore).headers(...) when registering their own @Bean StaticFiles.
  • Default classpath base searches both static/ and htdocs/ directories on the importer's classpath (recursive walk via BasicStaticFiles's built-in ResourceSupplier hook).
Path matching:

The handler declares @RestGet(path="/${juneau.staticfiles.path:static}/*") so a single Java method binds to the configured prefix (default /static/*). The trailing /* captures the multi-segment remainder via @Path("/*") String path. Juneau's UrlPathMatcher does not support the Spring/JAX-RS {var:regex} syntax — each {var} matches a single segment only, and multi-segment matching is only available via the trailing-* pattern shown here (same idiom as the legacy BasicRestServlet.getHtdoc(...) accessor).

OpenAPI surface:

The greedy /* handler is not API-meaningful and is excluded from generated Swagger / OpenAPI specs via @OpSwagger(ignore=true).

See Also:
Since:
10.0.0