Cameleer

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, including routeConfiguration, routeTemplate/templatedRoute, rest/restConfiguration, Kamelets, Pipes and Camel K Integration resources.
  • 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, completionTimeout is 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() and property()), constant, header, exchangeProperty.
  • Headers and properties: CamelFileName, CamelHttpResponseCode, CamelSplitIndex, CamelRedeliveryCounter, kafka.KEY, CamelMqttTopic and the rest.
  • Error handling: errorHandler (default, dead letter channel, none), redelivery policies, onException with handled/continued/onWhen/retryWhile, doTry/doCatch/doFinally, onCompletion. Java exception class names in routes are matched by their simple name.
  • Configuration: application.properties and application.yaml, {{placeholders}} with defaults, {{env:NAME}}, profiles, camel.component.<scheme>.<option>, Spring Boot and Quarkus key aliases, CAMEL_* environment variables.
  • Tooling: the cameleer command (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:

yaml example: migrate-camel-yaml
- 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

areaApache CamelCameleer
runtimeJVM, Maven or Gradleone native binary, or Rust crates
custom processorsJava classes or lambdasRust closures or structs (Processor trait), bound in the registry for YAML/XML
beansJava beans with reflection-based parameter bindingprocessor beans and named bean methods; no reflection
message bodiesJava objects, POJO binding (unmarshalType)dynamic values: null, bool, numbers, text, bytes, lists, maps; JSON maps onto them, no POJOs
exceptionsJava exception classesstring kinds with a parent hierarchy; register_kind_parent adds your own
scriptsGroovy, JavaScript (GraalJS), Python (Jython), Java (jOOR) on the JVMCameleer's own interpreters for the same syntaxes, without Java libraries
componentsabout 300about 230 components, languages and data formats; see FEATURES.md
statisticscollected only with camel-managementalways on; route and context counters by default, per-step timing opt-in (camel.main.jmxManagementStatisticsLevel=Default)
managementJMXJSON and Prometheus export, health checks, dev console; no JMX
transactionsSpring or JTA transaction managersa TransactionManager trait with Camel's propagation behaviours; no JTA/XA
variablesa variable repositorystored as exchange properties named CamelVariable.<name>
aggregation and idempotent repositoriesmemory, JDBC, LevelDB, Infinispan, Redis...memory, JDBC and Redis
deployment to KubernetesCamel K operator, Kubernetes traitskind: Integration files run in-process; deploy the container image yourself

Migration checklist

  1. Inventory the components. List every scheme your routes use and check it in FEATURES.md or the component pages, including the options. cameleer catalog components prints the list.
  2. 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.
  3. 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 script step.
  4. Check type-dependent logic. Steps that relied on POJO types (bodyAs(Order.class), unmarshalType, typed beans) work on maps instead: ${body[field]}, JSONPath, jq.
  5. Move configuration. Keep application.properties; replace Spring XML beans with camel.beans.* entries or Rust code; Spring Boot keys (server.port, spring.profiles.active) are understood.
  6. Test with the same tests. Camel's mock: endpoint, ProducerTemplate, interceptSendToEndpoint with skipSendToOriginalEndpoint, and the embedded test servers (Kafka, MQTT, AMQP, SQL, Redis, MongoDB, S3, SQS, OpenAI...) make hermetic tests possible.
  7. 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:

  1. In Simple text, $${ is an escape that produces a literal ${.
  2. TLS comes from Cameleer's own cameleer-tls crate, not a mature, audited library.
  3. 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.
  4. When an http call fails with an HTTP error status, Cameleer's http producer has already put the response body and headers into the message (Apache Camel leaves the message unchanged and puts the response in the HttpOperationFailedException). A redelivery of that step then sends the error response instead of the original request. Until this is fixed, call the API with enrich (which sends a copy of the message) when the call is retried; see the tool API and store and forward examples.
  5. throttle uses Camel's classic time-period mode (timePeriodMillis); the maximum must be a constant.
  6. 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.

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.

Edit this page on GitHub