If you’ve been exploring Apache KIE and Kogito to build BPMN workflows, you’ve probably seen the slick domain-specific REST endpoints or Kafka listeners that “just work” out of the box. Sounds great, right?
Until you realize:
- You want custom logic before starting a process
- You don’t want a bunch of auto-generated REST endpoints cluttering your app
- You’re calling from another Java service and REST feels like overkill
- Or worse: you turned off codegen and… now what?
Here’s the part nobody explains: how to use the Java API directly.
And that you won’t find this in the docs. And if you do, it’s probably broken.
Spoiler: it is possible. But there’s almost no guidance, and most examples are outdated or simply wrong.
Let’s fix that.
Why You Might Not Want Auto-Generated REST
By default, Kogito generates REST endpoints for every BPMN process you define. For example, if you have a Hiring
process, you’ll get:
POST /hiring
GET /hiring/{id}
DELETE /hiring/{id}
This is great for prototyping or exposing workflows as services.
But what if:
- You want to kick off the process from within a service call?
- You need to transform or validate input before instantiating the process?
- You need tight control over how and when your process runs?
That’s when you reach for the Java API.
Step-by-Step: Starting a Kogito BPMN Process with Java
Let’s walk through a real-world example of triggering a process without using the generated REST endpoint.
✅ Step 1: Disable the auto-generated REST
Add this to your application.properties
to opt out of codegen:
kogito.generate.rest=false
Kogito will skip generating REST endpoints for your processes.
✅ Step 2: Inject and trigger the process programmatically
Use CDI and the ProcessService
API to interact directly with your process:
import java.util.HashMap;
import java.util.Map;
import org.kie.kogito.Model;
import org.kie.kogito.process.Process;
import org.kie.kogito.process.ProcessInstance;
import org.kie.kogito.process.ProcessService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@ApplicationScoped
public class MyService {
@Inject
ProcessService processService;
@Inject
@Named("contentApproval") // This must match your BPMN process ID
Process<? extends Model> process;
public void startMyProcessCustomWay() {
Model model = process.createModel();
Map<String, Object> variables = new HashMap<>();
//document is an input process variable
variables.put("document", new Document("id", "name", "content"));
model.fromMap(variables);
ProcessInstance<?> instance = processService.createProcessInstance(
(Process) process, null, model, null, null);
System.out.println("Status: " + instance.checkError().variables());
}
}
💡 Pro tip: The
@Named("...")
annotation must match theid
attribute in your BPMN file — not just the filename.
Now You’re Free to Build Real Applications
This pattern gives you full control over how and when your workflows are triggered:
- ✅ Call from another Java service
- ✅ Add custom validation, authentication, or logging
- ✅ Coordinate with other systems before starting a process
- ✅ Avoid exposing sensitive internal processes via REST
What About Kafka Listeners?
Same deal. If you were relying on generated Kafka listeners but need something custom, just disable the codegen and wire up your own event handling logic.
We’ll cover that in a future post — follow us on LinkedIn or X so you don’t miss it.
Final Thoughts
This kind of low-level access is critical in enterprise environments — especially when architectural constraints or integration requirements are non-negotiable.
At Aletyx, we talk to teams that love the power of Kogito but need more than “click-to-run” demos. That’s why our enterprise build supports these patterns — and more — out of the box.
We’re sharing what works. No fluff. No broken tutorials.
🔗 Got questions? Reach out via our contact page.
❤️ Was this helpful?
Give it a share. You might just save another developer from a week of trial-and-error.