Skip to main content

REST Server — Self-Registration

A Juneau servlet can declare where it wants to be mounted via the top-level path chain — @Rest(paths=...) or a getPaths() override — rather than having the deployer hard-code a URL pattern at registration time. Three mechanisms read that self-declaration and register the servlet accordingly, one per runtime.

All three resolve the mount path through the same resolver:

String[] paths = RestContext.resolveTopLevelPaths(servletClass, servletInstance, beanStore);

resolveTopLevelPaths(...) walks the precedence chain programmatic override → getPaths() getter → @Rest(paths) annotation default (with SVL substitution on annotation elements, so $C{...} / ${env} templates resolve against the supplied bean store). It reads the top-level chain (paths() / getPaths()), never path() (which is for child-composition). Because every mechanism funnels through this one method, mount paths are identical across runtimes.

Microservice (Jetty)​

No new API — the existing JettyServerComponent auto-discovery loop already calls resolveTopLevelPaths(...) for each @Bean Servlet it finds and mounts it at the resolved paths. A standalone companion (or any @Rest(paths=...) servlet) is mounted simply by exposing it as a bean:

@Bean Servlet version() { return new VersionServlet(); }   // auto-mounted at /version/*

Spring Boot​

Opt-in auto-configuration​

JuneauRestAutoConfiguration (in juneau-rest-server-springboot, registered via META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports) walks every RestServlet bean in the application context and mounts each at its self-declared path.

It is gated behind a property (no default — matchIfMissing=false):

juneau.rest.auto-register=true

When unset (or any value other than true) the auto-configuration contributes nothing and servlet registration stays fully manual. When active it:

  1. Skips any servlet instance already wired into a manual ServletRegistrationBean (explicit registrations always win — no double-mounts).
  2. Resolves each servlet's mount paths via resolveTopLevelPaths(...) using the application's registered BeanStore.
  3. Registers the servlet at each resolved path. Servlets that resolve to no top-level paths (pure mixins / child-composed resources) are skipped.

Explicit factory helper​

When you'd rather register servlets yourself but still want the mount path to come from the servlet (not a hard-coded string), use the always-available factory helper:

@Bean
ServletRegistrationBean<?> jspServlet(BeanStore beanStore) {
return JuneauServletRegistrations.forServlet(new JspServlet(), beanStore);
}

JuneauServletRegistrations.forServlet(...) derives the registration's URL mappings from the servlet's @Rest(paths) / getPaths(). A servlet that resolves to no top-level paths is rejected with an IllegalArgumentException.

Non-Spring (web.xml / external WAR)​

For plain Servlet-spec deployments, juneau-rest-server ships a jakarta.servlet.ServletContainerInitializer, JuneauRestServletContainerInitializer (discovered via META-INF/services/jakarta.servlet.ServletContainerInitializer). Through @HandlesTypes(RestServlet.class) the container hands it every RestServlet on the webapp classpath; it auto-mounts each concrete, @Rest-annotated, no-arg-instantiable servlet that self-declares top-level paths.

It is opt-in via a context init parameter (parity with the Spring Boot property), so it never collides with servlets the deployer declared manually in web.xml:

<context-param>
<param-name>juneau.rest.auto-register</param-name>
<param-value>true</param-value>
</context-param>

Cross-runtime parity​

RuntimeMechanismActivationReads
Jetty microserviceJettyServerComponent auto-discoveryalways (for @Bean Servlet)resolveTopLevelPaths(...)
Spring BootJuneauRestAutoConfigurationjuneau.rest.auto-register=trueresolveTopLevelPaths(...)
Spring BootJuneauServletRegistrations.forServlet(...)explicit @BeanresolveTopLevelPaths(...)
web.xml / WARJuneauRestServletContainerInitializerjuneau.rest.auto-register context-paramresolveTopLevelPaths(...)

See also​