10 · Case study
A Mule 4 integration applicationMule 4 · DataWeave · RAML · Java 21 · Spring Boot
The system
The problem
A Mule 4 application is XML. Flows and sub-flows in src/main/mule, connectors configured against properties files, DataWeave scripts doing the transformation, and often a RAML or OpenAPI specification with an APIkit router generating the entry points from it. Read as a picture it is a graph of enterprise integration patterns; read as a repository it is a few thousand lines of XML whose behaviour depends on which connector versions the runtime resolves.
That is the visible half. The other half is not in the repository at all. Rate limiting, client-id enforcement, JWT validation and IP allow-listing are usually applied as policies in API Manager, and a migration that reads only the source will produce a Spring Boot application that does exactly what the flows did and none of what the platform was doing around them. That gap is the one that shows up in production rather than in a test.
What ran
Every <flow> and <sub-flow> with its steps in order: listeners and requesters, database and queue operations, choice, foreach, scatter-gather, until-successful, try and its error handlers, and every flow reference. What comes out is the integration topology — which flows are entry points, which are called, and what each one touches.
Connector configurations, configuration-properties files, and secure properties are resolved to the values the flows actually read. A property with no value in the repository is reported as unresolved rather than defaulted, because a default invented here becomes an endpoint pointing somewhere wrong.
DataWeave is a functional transformation language and it is the genuinely hard part of this migration. Each script is parsed and re-expressed as Java mapping code, with the source script kept beside the generated method so the two can be read together. Where a script uses a construct with no provable Java equivalent, the migration says so and leaves the case for a person — it does not produce mapping code that looks finished and silently drops a field.
Where the application is built from a RAML or OpenAPI specification with an APIkit router, the specification is the source of truth for the new controllers, so the migrated service presents the same interface by construction rather than by inspection. RAML is converted to OpenAPI and both are kept.
Spring Integration and Apache Camel both express the same patterns a Mule flow is built from, and which one fits depends on the team rather than the source; it is a question the questionnaire asks. A flow becomes a route or an integration flow, an error handler becomes the equivalent handler, and a connector becomes the Spring starter for that protocol.
Every entry point in the source has an entry point in the target, every flow reference resolves, no property is left unresolved, the generated API matches the specification, and the project builds and its tests run. A gate at fail severity blocks cutover.
What it did
A Spring Boot service on Java 21
A normal Maven or Gradle project a Java team can read, debug in an IDE, and test without a proprietary runtime. The flow layer is Spring Integration or Camel; everything around it is ordinary Spring.
The policy gap, written down
Every policy the application depended on but did not contain — rate limits, client-id enforcement, token validation — listed as work to re-create at whatever gateway takes API Manager's place. Naming it is the point; it cannot be migrated from a repository that never held it.
DataWeave beside its replacement
Each generated mapping method carries the DataWeave it came from as a comment. Reviewing a transformation migration means reading both, and putting them in one place is the difference between a review that happens and one that does not.
Where it ended
Where the platform ends and the application begins. Some of what Mule gave you was the runtime: deployment, scaling, monitoring, the policy layer. Replacing it means deciding which of those move to your existing platform and which need something new. The migration produces the application and an explicit list of what the platform was doing; the second list is the one worth reading first.
What happens next
The reason to migrate off a low-code integration platform with a parser rather than by hand is that the flows are already a formal description. They are XML with a schema, and the patterns they use have direct equivalents. What has no equivalent — DataWeave, and the policies that lived in the control plane — is a short and knowable list, and a migration is worth trusting exactly to the extent that it tells you what that list contains.