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 theCamelContext, but does not yet create concrete routes.- Each
TemplatedRouteBuilder.builder(context, "greetingTemplate")call:- Selects the template by id (
greetingTemplate). - Assigns a
routeIdfor the route instance. - Supplies parameter values (
name,greeting,period). - Calls
.add()to materialize and register a concrete route.
- Selects the template by id (
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}}→ ifparamis set, include its value; if not, drop the option entirely from the URI.{{!param}}→ use the opposite Boolean value ofparam.
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
replyTimeoutis not provided, thereplyTimeoutoption is omitted from the URI entirely, so you avoid danglingreplyTimeout=. - If
disableLogging = true, then{{!disableLogging}}becomesfalse, sologgingEnabled=falseon the endpoint. - If
disableLogging = false, thenloggingEnabled=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}}.
Leave a Reply