Apache Camel route templates in Java DSL let you define a reusable route “shape” and then create many concrete routes from it by supplying parameters. This avoids copy‑pasting similar routes and centralizes changes.


Core idea in Java DSL

In Java DSL, a route template is declared inside a RouteBuilder using routeTemplate("id") and a set of templateParameter(...) entries. Placeholders like {{name}} and {{period}} inside the route definition are filled in when you create concrete routes from the template.

Conceptually:
$$
\text{routeTemplate("id")} + \text{parameters} \Rightarrow \text{concrete route}
$$
This separates what changes (parameters) from what stays the same (the processing steps), so you can add or modify routes by changing parameters instead of duplicating code.


Defining a route template

You define the template in a RouteBuilder just like a normal route, but with routeTemplate and templateParameter.

import org.apache.camel.builder.RouteBuilder;

// Defines the route template using Java DSL
static class MyRouteTemplates extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        routeTemplate("greetingTemplate")
                .templateParameter("name")
                .templateParameter("greeting")
                .templateParameter("period", "3s")

                .from("timer:{{name}}?period={{period}}")
                .setBody(simple("{{greeting}} from route {{name}} at ${date:now:HH:mm:ss}"))
                .log("${body}");
    }
}

Why it’s structured like this:

  • routeTemplate("greetingTemplate") marks this as a template (a blueprint), not a route that runs by itself.
  • Each templateParameter(...) declares one thing that can vary between route instances and can optionally have a default.
  • {{name}}, {{greeting}}, and {{period}} are placeholders; Camel will substitute them when you create real routes from this template.

All variable pieces are explicitly listed as parameters, so the template is easy to understand and validate.


Creating routes from the template with TemplatedRouteBuilder

To turn the template into real routes, you use TemplatedRouteBuilder with the CamelContext and supply parameter values.javadoc+1

import org.apache.camel.CamelContext;
import org.apache.camel.builder.TemplatedRouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

void main() throws Exception {
    CamelContext context = new DefaultCamelContext();

    // Register template
    context.addRoutes(new MyRouteTemplates());

    // Create routes from template using TemplatedRouteBuilder
    TemplatedRouteBuilder.builder(context, "greetingTemplate")
            .routeId("helloFast")
            .parameter("name", "fast")
            .parameter("greeting", "Hello")
            .parameter("period", "2s")
            .add();

    TemplatedRouteBuilder.builder(context, "greetingTemplate")
            .routeId("helloSlow")
            .parameter("name", "slow")
            .parameter("greeting", "Kia ora")
            .parameter("period", "5s")
            .add();

    context.start();

    // Let timers fire for a while
    Thread.sleep(15000);

    context.stop();
}

What’s happening and why:

  • context.addRoutes(new MyRouteTemplates()) loads the template into the CamelContext, but does not yet create concrete routes.
  • Each TemplatedRouteBuilder.builder(context, "greetingTemplate") call:
    • Selects the template by id (greetingTemplate).
    • Assigns a routeId for the route instance.
    • Supplies parameter values (name, greeting, period).
    • Calls .add() to materialize and register a concrete route.

You end up with multiple active routes that share the same logic but differ only in their parameters.


Optional and negated parameters

Special placeholder variants help with optional and Boolean parameters inside templates:

  • {{?param}} → if param is set, include its value; if not, drop the option entirely from the URI.
  • {{!param}} → use the opposite Boolean value of param.

Example with clear naming:

routeTemplate("httpTemplate")
    .templateParameter("path")
    .templateParameter("replyTimeout")
    .templateParameter("disableLogging")

    .from("direct:start")
    .to("http://example.com/{{path}}"
        + "?replyTimeout={{?replyTimeout}}"
        + "&loggingEnabled={{!disableLogging}}");

Behavior and rationale:

  • If replyTimeout is not provided, the replyTimeout option is omitted from the URI entirely, so you avoid dangling replyTimeout=.
  • If disableLogging = true, then {{!disableLogging}} becomes false, so loggingEnabled=false on the endpoint.
  • If disableLogging = false, then loggingEnabled=true.

Use {{!param}} when the semantics of the parameter are intentionally opposite to the endpoint’s option name (e.g., disableX vs enabledX); when they are aligned, simply use {{param}}.