Lucee 7 and Axis 1 SOAP

I’ve been doing some Lucee 7 testing on our product.
I found that producing webservices is not working on my development machine where I’m using CommandBox that comes with Undertow server. If I use Lucee Windows Installer that comes with Tomcat and install itit works normally. I believe it is an issue regarding javax => jakarta migration.

Example webservice.cfc that should be run in browser /webservice.cfc?wsdl

component {
	remote string function sayHello() {
        return "hello #now()#";
	}
}

I got stackoverflow error that appears in onError method also cannot be dumped … only the exception message:
Lucee detected a missing javax class: javax.servlet.ServletContext This typically occurs when running Lucee 7 on a Jakarta-based servlet container (for example Tomcat 10+) with extensions that were compiled for javax.servlet APIs. SOLUTION: Update your extensions to Jakarta-compatible versions. Check for updated versions of your extensions (Redis, Lucene, etc.) that support Jakarta EE.

public void function onError(required any exception, string eventName="") output=true {
	writeDump(var=arguments.exception.message, label="arguments.exception.message");
	abort;
}

Is Tomcat 10.1+ really required to use Lucee 7 according to documentation?

  • Jakarta EE: Full migration from javax to jakarta namespace (requires Tomcat 10.1+)

What can I do?

My stack

OS: Windows 11
Java Version: Eclipse Adoptium 21.0.8
Tomcat Version: 11.0.22
WildFly / Undertow Version: 2.3.21.Final
Lucee Version: 7.0.4.34
Axis 1 Webservices for Jakarta EE: 1.5.0.6

AXIS hasnt been ported to Jakarta, and probably wont be. We had a look at what it would take to port it and there were many challenges. We ended up building our own SOAP dispatcher that was backwards compatible with AXIS, it took a couple of weeks and used a lot of tokens but we are about to push it into production.

Yes, I see Axis (WebServices - Axis) released last version in 2006 - 20 years ago, so there is no hope with Jakarta.
Other options:

So @dman1 you made your own SOAP dispatcher in CFML or Java? Are doing it multiple components/classes? I’m also thinking to make my own SOAP engine … :sweat_smile: Benefit is also that it will be the same for Lucee and Coldfusion that we are also supporting.

But in my opinion, it would be necessary to support Soap services on the Lucee side in some way, even if it means replacing the Axis library. Enterprise environments “unfortunately” still use SOAP for integration. In their place, I would opt for a standard solution like Jakarta XML Web Services. But I know that this is not as easy as it sounds…

I wonder what Lucee thinks about this?

We have a large number of clients spanning 20 years that rely on SOAP, so we couldn’t just ditch it, nor could we ask them to modify ancient integrations to support deprecation of old SOAP methods, so we had to build it. We did it in CFML.
We first built a SOAP capture and captured every inbound request type, that gave us parity shapes to work with and test against, then we built a test harness that called all our endpoints and captured responses.
Then it was a case of having AI build a plan, reviewing the extension source code and replicating that in CFML, then iterating over the tests to prove parity.
Below is a prompt you can use to get started, some of this is a bit specific to our needs but the AI will iterate over the parity captures.

 Build a CFML-native SOAP dispatcher (Lucee 6, forward-compatible to Lucee 7) that replaces the Apache Axis 1.4 engine, which Lucee 7 drops because it  depends on the deprecated javax.xml.rpc. It must serve existing remote CFCs unchanged — business methods stay where they are; the dispatcher only handles the wire.

Hard requirement: byte-compatible wire format with Axis 1.4 output, because partners have cached WSDLs and coded around quirks. Specifically:
 - SOAP 1.1, style="rpc" + use="encoded", not document/literal
 - Dispatch by the local name of the first child element inside soap:Body — soapAction is always "", so the header is useless
 - Per-host targetNamespace derived from the request hostname
 - Emit apachesoap:Map for struct returns; soap-enc:Array for arrays; multi-ref encoding (href="#id0"/id="id0") toggleable, on by default
 - Preserve partner casing quirks (don't normalize arg/method names)
 - Tolerate envelope-prefix variation (soapenv/soap/SOAP-ENV/ns0/env), redeclared namespaces, and xmlns="" resets
 
 Components (single responsibility each): envelope parser (XXE-safe xmlParse), argument marshaller (XML → argumentCollection), encoded type deserializer (xsi:type decode + multi-ref resolve) and serializer (scalar/Map/Array), response builder, SOAP 1.1/1.2 fault builder, WSDL generator (CFC introspection →WSDL with stable namespace prefixes) with a host-keyed TTL cache, plus an outbound SOAP client for internal callers.

Take the allow-list of servable CFCs as injected config. Validate parity by capturing real Axis responses and diffing canonicalized XML (xmllint --c14n), not raw bytes — Axis reorders attributes non-deterministically.

Great, thank you for sharing.