Scanning bpmn files in submodules of a spring boot 2 application

I am developing a runnable jar with an embedded process engine. The application is a spring boot 2 application and comprises multiple modules. I’d like to include the process definitions (.bpmn files) in a module that is not the module that contains the repackager plugin to compose the runnable jar. There is a direct dependency though from the ‘main’ module to the modules that contains the bpmn files. Those are placed in the src/main/resources directory of that module.

The only way I can get this working is by placing the bpmn files in the module that contains the main application class after all. Classpath elements in the other modules are not found.

Can anyone help me gettting this to work? From the documentation I expect it to be possible, but I cannot get this to work.

I assume you use the “EnableProcessApplication” annotation? If so, try to put an empty META-INF/processes.xml file in every module that contains bpmn files. That should trigger the scan.
If it does not work, this is an issue in the spring boot starter and should be reported and fixed.

Thanks for the reply. It works as expected. I had a typo in the name of the processes.xml file that I overlooked for quite some time. Once that was fixed, it just works.

Sorry, but I have to come back on this after all. When I run my application from my IDE it works fine, but with a runnable spring boot jar that is (re)packaged by the spring-boot-maven-plugin it does not find the resources to deploy.

What I see in the logging is the following.

  • ENGINE-08024 Found processes.xml file at jar:file:/…/app-dist.jar!/BOOT-INF/lib/module.jar!/META-INF/processes.xml
  • ENGINE-08004 Rootpath is file:/…/app-dist.jar
  • ENGINE-08021 Not creating a deployment for process archive ‘’: no resources provided.

So it recognizes the processs.xml file correctly from the submodule, but scanning for the bpmn files is done at the wrong level. The scanner only looks at the contents of the runnable jar; but the bpmn files are included in a nested jar. And that level is not taken into account.

I am using:

  • camunda-spring-boot-starter 3.2.1
  • camunda 7.10.0
  • spring-boot 2.1.4

Perhaps I am missing some additional configuration item, but I need some help to get this working. Again: in the IDE it works fine, but as a repackaged spring boot runnable jar, the bpmn files in the modules are not taken into account when starting the app.

I also created a minimal app with two modules (one for the app and one for the process part) in which this behaviour is reproducable.

1 Like

Sorry to add to an old post, but I find myself having exactly the same issue.

With a packaged Jar if I remove the @EnableProcessApplication from the main application class it auto deploys all the processes. If I put the annotation back it only loads the processes in the top-level module, and doesn’t deploy the processes in the sub modules. I’ve added an empty processes.xml to the submodules and it mentions the sub module at startup but seems to deploy the processes defined in the top level module only, and ignore the ones in the sub modules.

The output from the logs is as follows - it finds the processes.xml in both META-INF folders, but only loads the BPMN models from the top level @SpringBootApplication annotated module (in the log output below sfw-broker is the top-level, sfw-broker-commservice is a maven module dependency):

2019-06-02 18:35:17.553  INFO [service-broker,,,] 5337 --- [           main] org.camunda.bpm.container                : ENGINE-08024 Found processes.xml file at jar:file:/Users/stevedavis/Java/SmartDeploy-NMS/smartdeploy-evo-sfw/sfw-broker-group/sfw-broker/target/sfw-broker-1.0-SNAPSHOT.jar!/META-INF/processes.xml
2019-06-02 18:35:17.671  INFO [service-broker,,,] 5337 --- [           main] org.camunda.bpm.container                : ENGINE-08024 Found processes.xml file at jar:file:/Users/stevedavis/Java/SmartDeploy-NMS/smartdeploy-evo-sfw/sfw-broker-group/sfw-broker/target/sfw-broker-1.0-SNAPSHOT.jar!/BOOT-INF/lib/sfw-broker-commservice-1.0-SNAPSHOT.jar!/META-INF/processes.xml

There are 1 x BPMN models in the main module (that gets deployed OK) and 2 x BPMN models in the sub-module (that don’t get deployed - unless I remove the @EnableProcessApplication annotation).

Has anyone managed to get this working, and have a working example they can share? Thanks

Using: Camunda 7.9.0, Camunda Spring Boot Starter 3.0.0, Spring Boot 2.0.5

For anyone who is interested, I ended up writing my own deployer class as below (quick and dirty first version).

I left the @EnableProcessApplication on the Spring Boot App main class, and in the processes.xml I set the “isScanForProcessDefinitions” to false.

import static java.time.Instant.now;
import static java.util.Arrays.asList;

import javax.annotation.PostConstruct;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
public class CamundaResourceDeployer {

    @Setter
    @Value("${myapp.workflow.auto-deploy-at-startup:true}")
    private boolean autoDeployAtStartup;

    @Setter
    @Value("classpath*:**/processes/*.bpmn")
    private Resource[] bpmnResources;

    @Setter
    @Value("classpath*:**/processes/*.cmmn")
    private Resource[] cmmnResources;

    @Setter
    @Value("classpath*:**/processes/*.dmn")
    private Resource[] dmnResources;

    @Setter
    @Value("${spring.application.name}")
    private String appName;

    private final ProcessEngine processEngine;

    @PostConstruct
    public void deployCamundaResources() {

        try {

            log.info("Discovered BPMN Resources : {}", asList(bpmnResources));
            log.info("Discovered CMMN Resources : {}", asList(cmmnResources));
            log.info("Discovered DMN  Resources : {}", asList(dmnResources));

            log.info("Auto-Deploy Camunda Resources at Startup : {}", autoDeployAtStartup);

            if (!autoDeployAtStartup) {
                log.info("Auto Deploy disabled.");
                return;
            }

            if (bpmnResources.length == 0 && cmmnResources.length == 0 && dmnResources.length == 0) {
                log.info("No resources found to be deployed.");
                return;
            }

            String uniqueId = appName + " - " + now().toEpochMilli();

            DeploymentBuilder deploymentBuilder = processEngine.getRepositoryService().createDeployment()
                                                               .enableDuplicateFiltering(true).name(uniqueId);

            for (Resource resource : bpmnResources) {

                log.debug("Adding BPMN deployment : {}", resource.getFilename());
                deploymentBuilder.addInputStream(resource.getFilename(), resource.getInputStream());

            }

            for (Resource resource : cmmnResources) {

                log.debug("Adding CMMN deployment : {}", resource.getFilename());
                deploymentBuilder.addInputStream(resource.getFilename(), resource.getInputStream());

            }

            for (Resource resource : dmnResources) {

                log.debug("Adding DMN  deployment : {}", resource.getFilename());
                deploymentBuilder.addInputStream(resource.getFilename(), resource.getInputStream());

            }

            Deployment deployment = deploymentBuilder.deploy();

            log.info("Deployment details : id : {}, name : {}", deployment.getId(), deployment.getName());

        } catch (Exception e) {

            log.error(e.getMessage(), e);

        }

    }

}
1 Like

Hello. Did you resolve the issue? I have exactly the same problem…

Hi. I solved this issue by adding Gradle Copy task, and copying meta-inf folder from the nested jar into correct application level.

task metaInfCopy(type: Copy) {
    from('YourNestedApplication/build/resources/main/META-INF')
    into('YourMainApplication/build/resources/main/META-INF')
}

and adding this task to the build gradle bootJarMainClassName.dependsOn ':metaInfCopy'
There are could be also some requirement adding dependsOn configs.