Migrating from Apache Camel
Camel YAML and XML routes, endpoint URIs, EIPs, the Simple language, headers and error handling carry over to Cameleer unchanged; Java code (processors, beans, custom components) must be rewritten in Rust, and a few behaviours differ, listed on this page.
Cameleer follows Apache Camel 4's names and semantics, so most of a migration is running your existing route files and checking that every component and option you use is supported. This page lists what carries over, what differs, a checklist, and the known deviations.
What carries over unchanged
- Route files. Camel YAML DSL (
*.camel.yaml) and XML DSL (<routes>) files, includingrouteConfiguration,routeTemplate/templatedRoute,rest/restConfiguration, Kamelets, Pipes and Camel KIntegrationresources. - Endpoint URIs and options, with the same names and defaults for the supported components. Unknown options fail at startup, as in Camel.
- EIPs: names, options and semantics, including the edge cases (a split without a strategy
continues with the original message,
completionTimeoutis an inactivity timeout, duplicates skip only the idempotent block, the last reply wins in a multicast without a strategy). - Languages: Simple (operators, functions, OGNL navigation, ternary), JSONPath, XPath,
XQuery, jq (with camel-jq's
header()andproperty()), constant, header, exchangeProperty. - Headers and properties:
CamelFileName,CamelHttpResponseCode,CamelSplitIndex,CamelRedeliveryCounter,kafka.KEY,CamelMqttTopicand the rest. - Error handling:
errorHandler(default, dead letter channel, none), redelivery policies,onExceptionwithhandled/continued/onWhen/retryWhile,doTry/doCatch/doFinally,onCompletion. Java exception class names in routes are matched by their simple name. - Configuration:
application.propertiesandapplication.yaml,{{placeholders}}with defaults,{{env:NAME}}, profiles,camel.component.<scheme>.<option>, Spring Boot and Quarkus key aliases,CAMEL_*environment variables. - Tooling: the
cameleercommand (the Camel JBang commands under a different name:run,init,ps,stop,get,log,trace,export,bind,catalog), health checks at/q/health, metrics, the dev console, message history and tracing.
This route uses Camel-specific spellings (fully qualified exception and strategy class names, a
parameters map, a routeConfiguration, a placeholder with a default) and runs as written:
- routeConfiguration:
onException:
- onException:
exception:
- java.lang.IllegalArgumentException
handled:
constant: true
steps:
- setBody:
simple: "rejected: ${exception.message}"
- to: mock:rejected
- route:
id: order-lines
from:
uri: direct:orders
steps:
- unmarshal:
json:
library: Jackson
- filter:
simple: "${body[lines]} == null"
steps:
- throwException:
exceptionType: java.lang.IllegalArgumentException
message: "order ${body[id]} has no lines"
- split:
simple: "${body[lines]}"
aggregationStrategy: "#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
steps:
- setBody:
simple: "${body[sku]} x ${body[qty]}"
- to:
uri: mock:order-summary
parameters:
retainFirst: "{{summary.retain:10}}"An order {"id": 7, "lines": [{"sku": "A1", "qty": 2}, {"sku": "B2", "qty": 1}]} reaches
mock:order-summary as ["A1 x 2", "B2 x 1"]; an order without lines goes to mock:rejected.
What differs
| area | Apache Camel | Cameleer |
|---|---|---|
| runtime | JVM, Maven or Gradle | one native binary, or Rust crates |
| custom processors | Java classes or lambdas | Rust closures or structs (Processor trait), bound in the registry for YAML/XML |
| beans | Java beans with reflection-based parameter binding | processor beans and named bean methods; no reflection |
| message bodies | Java objects, POJO binding (unmarshalType) | dynamic values: null, bool, numbers, text, bytes, lists, maps; JSON maps onto them, no POJOs |
| exceptions | Java exception classes | string kinds with a parent hierarchy; register_kind_parent adds your own |
| scripts | Groovy, JavaScript (GraalJS), Python (Jython), Java (jOOR) on the JVM | Cameleer's own interpreters for the same syntaxes, without Java libraries |
| components | about 300 | about 230 components, languages and data formats; see FEATURES.md |
| statistics | collected only with camel-management | always on; route and context counters by default, per-step timing opt-in (camel.main.jmxManagementStatisticsLevel=Default) |
| management | JMX | JSON and Prometheus export, health checks, dev console; no JMX |
| transactions | Spring or JTA transaction managers | a TransactionManager trait with Camel's propagation behaviours; no JTA/XA |
| variables | a variable repository | stored as exchange properties named CamelVariable.<name> |
| aggregation and idempotent repositories | memory, JDBC, LevelDB, Infinispan, Redis... | memory, JDBC and Redis |
| deployment to Kubernetes | Camel K operator, Kubernetes traits | kind: Integration files run in-process; deploy the container image yourself |
Migration checklist
- Inventory the components. List every scheme your routes use and check it in
FEATURES.md or the component pages, including the options.
cameleer catalog componentsprints the list. - Run the routes as they are.
cameleer run routes/(or the Docker image). Startup fails on an unknown component, an unknown endpoint option or an unsupported YAML element, with the file and line. - Replace Java code. Rewrite processors and beans as Rust processors and bind them in the
registry under the same names, or replace them with EIPs and Simple, jq or JSONPath
expressions (often possible for mapping code), or with a
scriptstep. - Check type-dependent logic. Steps that relied on POJO types (
bodyAs(Order.class),unmarshalType, typed beans) work on maps instead:${body[field]}, JSONPath, jq. - Move configuration. Keep
application.properties; replace Spring XML beans withcamel.beans.*entries or Rust code; Spring Boot keys (server.port,spring.profiles.active) are understood. - Test with the same tests. Camel's
mock:endpoint,ProducerTemplate,interceptSendToEndpointwithskipSendToOriginalEndpoint, and the embedded test servers (Kafka, MQTT, AMQP, SQL, Redis, MongoDB, S3, SQS, OpenAI...) make hermetic tests possible. - Review the deviations below, then load-test: throughput and memory differ a lot (see the benchmarks), so thread pools and queue sizes tuned for a JVM may be too large.
Known deviations
These differences are documented on purpose (from the conformance suite in FEATURES.md) or found while writing these guides:
- In Simple text,
$${is an escape that produces a literal${. - TLS comes from Cameleer's own
cameleer-tlscrate, not a mature, audited library. - Asynchronous delays (
asyncDelayed,asyncDelayedRedelivery) hand the waiting exchange to a released thread and start a replacement consumer thread, instead of scheduling a continuation on a scheduler pool. The effect on the route is the same. - When an
httpcall fails with an HTTP error status, Cameleer'shttpproducer has already put the response body and headers into the message (Apache Camel leaves the message unchanged and puts the response in theHttpOperationFailedException). A redelivery of that step then sends the error response instead of the original request. Until this is fixed, call the API withenrich(which sends a copy of the message) when the call is retried; see the tool API and store and forward examples. throttleuses Camel's classic time-period mode (timePeriodMillis); the maximum must be a constant.- Management statistics default to route and context counters (see the table above).
Common questions
Is Cameleer a drop-in replacement for Apache Camel?
For route files, mostly: Camel YAML and XML routes run unchanged when their components and options are supported. Java code is not: processors, beans and custom components must be rewritten in Rust.
Can I run Camel and Cameleer side by side?
Yes. They talk through the same brokers, APIs and files, so you can move routes one at a time, for example the high-volume or edge routes first.
Do Camel Kamelets work?
Yes. YAML Kamelets (spec.definition, spec.template), Pipes and KameletBindings run, loaded
from camel.main.kamelet-locations (default ./kamelets). Remote github: locations are not
fetched.
What about Camel's Java DSL?
The Rust DSL mirrors it method by method (from, filter, split, aggregate,
on_exception...), so a Java route translates line by line. See concepts.
Related
- Concepts, FAQ, feature list
- Apache Camel: YAML DSL, Camel 4 migration guide
Found a problem?
If something on this page doesn't match what Cameleer does, or you hit a bug while building
with it, please help fix it, whether you are a person or a coding agent:
open an issue that describes what you saw,
then fork the repository, fix it, add or update a test, run cargo test --workspace, and open
a pull request. CONTRIBUTING.md
explains the ground rules.