BPMN schema validation fails when Flowable jar is loaded from a non-ASCII unpacked Spring Boot classpath
Description
We encountered a BPMN schema validation failure in Flowable 7.2.0 when the Flowable dependency jar is loaded from an unpacked Spring Boot executable jar located under a path containing non-ASCII characters.
The BPMN XML itself is valid. The failure happens during Flowable's default BPMN schema validation.
Environment
- Flowable:
7.2.0 - Spring Boot:
3.2.12 - Deployment style: unpacked executable jar, started with
org.springframework.boot.loader.launch.JarLauncher - Java: reproduced on Java 17 / Java 21
- OS: Windows
- Runtime path contains non-ASCII characters, for example:
D:/workspace/流程/runtime/.runtime.jar.exploded/BOOT-INF/lib/flowable-bpmn-converter-7.2.0.jarWhy the classpath contains non-ASCII characters
Our application uses Spring Boot's efficient deployment style by unpacking the executable jar before startup.
This is similar to the deployment approach described in the Spring Boot reference documentation:
In this mode, the executable jar is exploded and the application is started from the unpacked directory. The runtime classpath then contains entries such as:
<workspace>/runtime/.runtime.jar.exploded/BOOT-INF/classes
<workspace>/runtime/.runtime.jar.exploded/BOOT-INF/lib/*We use this deployment mode mainly to improve cold startup time.
The <workspace> directory is user-controlled. In desktop, local-runtime, or embedded-runtime scenarios, this directory can naturally contain localized names, for example:
D:/workspace/流程/runtime/.runtime.jar.exploded/BOOT-INF/lib/flowable-bpmn-converter-7.2.0.jarTherefore, the Flowable dependency jar becomes part of a classpath whose physical path contains non-ASCII characters.
This is not related to the BPMN file name or BPMN content. It is a consequence of running a valid Spring Boot unpacked deployment from a localized workspace path.
Actual Error From Our Application
Application-specific package names and local paths are anonymized below, but the Flowable, Spring Boot, JDK, and Xerces stack frames are unchanged.
2026-06-02 13:32:08.701 [main] ERROR o.f.e.impl.bpmn.deployer.ParsedDeploymentBuilder - Could not parse resource process1.bpmn
org.flowable.bpmn.exceptions.XMLException: src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:292)
at org.flowable.engine.impl.bpmn.parser.BpmnParse.execute(BpmnParse.java:148)
at org.flowable.engine.impl.bpmn.deployer.ParsedDeploymentBuilder.createBpmnParseFromResource(ParsedDeploymentBuilder.java:97)
at org.flowable.engine.impl.bpmn.deployer.ParsedDeploymentBuilder.build(ParsedDeploymentBuilder.java:55)
at org.flowable.engine.impl.bpmn.deployer.BpmnDeployer.deploy(BpmnDeployer.java:78)
at org.flowable.engine.impl.persistence.deploy.DeploymentManager.deploy(DeploymentManager.java:62)
at org.flowable.engine.impl.cmd.DeployCmd.executeDeploy(DeployCmd.java:135)
at org.flowable.engine.impl.cmd.DeployCmd.execute(DeployCmd.java:70)
at org.flowable.engine.impl.cmd.DeployCmd.execute(DeployCmd.java:45)
at org.flowable.engine.impl.interceptor.CommandInvoker$1.run(CommandInvoker.java:75)
at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:199)
at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:128)
at org.flowable.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:80)
at org.flowable.engine.impl.interceptor.BpmnOverrideContextInterceptor.execute(BpmnOverrideContextInterceptor.java:26)
at org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:53)
at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:105)
at org.flowable.common.spring.SpringTransactionInterceptor.lambda$execute$0(SpringTransactionInterceptor.java:57)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at org.flowable.common.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:57)
at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:51)
at org.flowable.engine.impl.RepositoryServiceImpl.deploy(RepositoryServiceImpl.java:99)
at org.flowable.engine.impl.repository.DeploymentBuilderImpl.deploy(DeploymentBuilderImpl.java:206)
at com.example.runtime.process.service.ProcessDeployService.deployProcess(ProcessDeployService.java:140)
at com.example.runtime.process.service.ProcessDeployService.deployProcesses(ProcessDeployService.java:112)
at com.example.runtime.process.service.ProcessDeployService.deployAndCacheProcesses(ProcessDeployService.java:81)
at com.example.runtime.process.config.FlowableAutoConfiguration.buildAndStartEngine(FlowableAutoConfiguration.java:247)
at com.example.runtime.process.config.FlowableAutoConfiguration.initialize(FlowableAutoConfiguration.java:112)
at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:383)
at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:255)
at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:174)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:455)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:388)
at org.springframework.boot.context.event.EventPublishingRunListener.ready(EventPublishingRunListener.java:109)
at org.springframework.boot.SpringApplicationRunListeners.lambda$ready$6(SpringApplicationRunListeners.java:80)
at org.springframework.boot.SpringApplicationRunListeners.ready(SpringApplicationRunListeners.java:80)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:332)
at com.example.runtime.Application.main(Application.java:27)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:106)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)
Caused by: org.xml.sax.SAXParseException; systemId: jar:file:/D:/workspace/流程/runtime/.runtime.jar.exploded/BOOT-INF/lib/flowable-bpmn-converter-7.2.0.jar!/org/flowable/impl/bpmn/parser/BPMN20.xsd; lineNumber: 15; columnNumber: 70; src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4254)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4237)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1791)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:170)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3707)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:543)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:281)
at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:612)
at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:644)
at org.flowable.bpmn.converter.BpmnXMLConverter.createSchema(BpmnXMLConverter.java:252)
at org.flowable.bpmn.converter.BpmnXMLConverter.validateModel(BpmnXMLConverter.java:231)
at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:283)
... 51 common frames omittedMinimal Reproduction
The following minimal Spring Boot application uses Flowable in the normal way. It does not manually load BPMN20.xsd and does not configure a custom classloader. It only calls Flowable's default BPMN XML conversion with schema validation enabled.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.12</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>flowable-non-ascii-classpath-repro</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-bpmn-converter</artifactId>
<version>7.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>src/main/java/com/example/repro/FlowableNonAsciiClasspathReproApplication.java
package com.example.repro;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.common.engine.api.io.InputStreamProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@SpringBootApplication
public class FlowableNonAsciiClasspathReproApplication implements CommandLineRunner {
private static final String BPMN_XML = """
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
targetNamespace="http://example.com/process">
<process id="process1" isExecutable="true">
<startEvent id="start" />
</process>
</definitions>
""";
public static void main(String[] args) {
SpringApplication.run(FlowableNonAsciiClasspathReproApplication.class, args);
}
@Override
public void run(String... args) {
BpmnXMLConverter converter = new BpmnXMLConverter();
converter.convertToBpmnModel(new BpmnInputStreamProvider(), true, false);
System.out.println("Flowable BPMN XML conversion succeeded");
}
private static class BpmnInputStreamProvider implements InputStreamProvider {
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(BPMN_XML.getBytes(StandardCharsets.UTF_8));
}
}
}reproduce.ps1
param(
[string]$WorkDir = "$env:TEMP\flowable-repro-流程"
)
$ErrorActionPreference = "Stop"
mvn -DskipTests package
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
Remove-Item -Recurse -Force $WorkDir -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $WorkDir | Out-Null
Copy-Item ".\target\flowable-non-ascii-classpath-repro-1.0.0.jar" "$WorkDir\app.jar"
Push-Location $WorkDir
try {
jar -xf app.jar
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
java org.springframework.boot.loader.launch.JarLauncher
exit $LASTEXITCODE
}
finally {
Pop-Location
}How to Run the Reproduction
From the reproduction project directory:
pwsh -NoProfile -File .\reproduce.ps1The script creates an unpacked runtime layout like:
%TEMP%\flowable-repro-流程\BOOT-INF\classes
%TEMP%\flowable-repro-流程\BOOT-INF\lib\flowable-bpmn-converter-7.2.0.jarReproduction Output
Starting FlowableNonAsciiClasspathReproApplication v1.0.0 using Java 21.0.6
(C:\Users\<user>\AppData\Local\Temp\flowable-repro-流程\BOOT-INF\classes started by <user>
in C:\Users\<user>\AppData\Local\Temp\flowable-repro-流程)
org.flowable.bpmn.exceptions.XMLException: src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:292) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:262) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
at com.example.repro.FlowableNonAsciiClasspathReproApplication.run(FlowableNonAsciiClasspathReproApplication.java:34) ~[classes/:1.0.0]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.2.12.jar:3.2.12]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) ~[spring-boot-3.2.12.jar:3.2.12]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:342) ~[spring-boot-3.2.12.jar:3.2.12]
at com.example.repro.FlowableNonAsciiClasspathReproApplication.main(FlowableNonAsciiClasspathReproApplication.java:28) ~[classes/:1.0.0]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102) ~[flowable-repro-%e6%b5%81%e7%a8%8b/:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) ~[flowable-repro-%e6%b5%81%e7%a8%8b/:na]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) ~[flowable-repro-%e6%b5%81%e7%a8%8b/:na]
Caused by: org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'extension' to a(n) 'element declaration' component.
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4254) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4237) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1791) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:170) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3707) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:666) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:618) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:577) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:543) ~[na:na]
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:281) ~[na:na]
at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:612) ~[na:na]
at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:644) ~[na:na]
at org.flowable.bpmn.converter.BpmnXMLConverter.createSchema(BpmnXMLConverter.java:252) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
at org.flowable.bpmn.converter.BpmnXMLConverter.validateModel(BpmnXMLConverter.java:231) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
at org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModel(BpmnXMLConverter.java:283) ~[flowable-bpmn-converter-7.2.0.jar:7.2.0]
... 27 common frames omittedObserved Behavior
When the Flowable jar is loaded from an unpacked Spring Boot classpath under a non-ASCII directory, Flowable's default BPMN XML conversion fails during schema validation.
The failure occurs inside:
org.flowable.bpmn.converter.BpmnXMLConverter.createSchema
org.flowable.bpmn.converter.BpmnXMLConverter.validateModel
org.flowable.bpmn.converter.BpmnXMLConverter.convertToBpmnModelExpected Behavior
Flowable should be able to load and validate its built-in BPMN schema resources from classpath jars even when the jar path contains non-ASCII characters.
Non-ASCII classpath locations are valid in localized user environments and should not prevent BPMN deployment or schema validation.
Source: flowable/flowable-engine