Skip to content

New WSDL Parser#2870

Merged
rrayst merged 6 commits into
6.Xfrom
new-wsdl-parser-from-7-4
Mar 15, 2026
Merged

New WSDL Parser#2870
rrayst merged 6 commits into
6.Xfrom
new-wsdl-parser-from-7-4

Conversation

@predic8

@predic8 predic8 commented Mar 13, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Enhanced WSDL parsing and validation framework with improved support for SOAP 1.1 and SOAP 1.2 bindings.
    • Improved schema validation with better error reporting and element extraction.
  • Bug Fixes

    • Improved handling of WSDL includes and imports with cyclic dependency resolution.
    • Enhanced SOAP message validation with better fault handling.
  • Dependencies

    • Updated Jackson (2.20.0 → 2.21.1), Spring (6.2.12 → 6.2.15), and Apache Commons libraries for improved security and performance.

predic8 added 2 commits March 13, 2026 10:04
… handling, and upgrade dependencies

- Consolidated and corrected static imports for consistency across classes.
- Unified handling of URI factories and base locations for WSDL and schema validation to reduce redundancy.
- Replaced redundant code and removed deprecated methods for improved maintainability.
- Upgraded dependencies: Jackson to 2.21.1, added jackson-bom, and updated Maven dependency configurations.
- Deprecated unused test cases and streamlined the test suite.
@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9e595c62-180b-4216-9577-1d9a37f89178

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive WSDL parser library and refactors the validation and routing infrastructure to use it. Changes include new WSDL parsing classes, updates to schema validation, interceptor rewiring for path-based WSDL handling, dependency version updates, and test resources for WSDL scenarios.

Changes

Cohort / File(s) Summary
Maven Dependencies
annot/pom.xml, core/pom.xml, pom.xml
Added jackson-annotations dependency; updated Jackson (2.20.0 → 2.21.1), Spring (6.2.12 → 6.2.15), and Log4j (2.25.2 → 2.25.3) versions; replaced deprecated soa-model-core with jatl; added groovy-json; updated commons, xmemcached, json-path, rhino-engine, swagger-parser versions.
Core Constants
core/src/main/java/.../Constants.java
Added XMLNS_NS and WSDL11_NS constants; updated HTTP_NS Javadoc.
WSDL Parser Library
core/src/main/java/.../util/wsdl/parser/*
Introduced comprehensive WSDL parser module: Definitions (parse factory), Service, Port, Binding, PortType, Operation, Message, Part, Address, WSDLElement (base), WSDLParserContext (record), WSDLParserException, WSDLParserUtil; added schema utilities (Schema, Types, SchemaElement, Import, Include, AbstractIncludeImport).
Validation Refactoring
core/src/main/java/.../interceptor/schemavalidation/AbstractXMLSchemaValidator.java, WSDLValidator.java, XMLSchemaValidator.java, ValidatorInterceptor.java
Refactored AbstractXMLSchemaValidator to use Element-based schemas; rewrote WSDLValidator to parse WSDL at construction via Definitions; updated ValidatorInterceptor with SOAPProxy field and schemaMappings handling; changed XMLSchemaValidator.getSchemas() signature.
New Validation Utilities
core/src/main/java/.../schemavalidation/WSDLMessageElementExtractor.java, WSDLSchemaExtractor.java
Added WSDLMessageElementExtractor for extracting WSDL request/response elements; added WSDLSchemaExtractor for extracting embedded XSD schemas from WSDL.
Interceptor Updates
core/src/main/java/.../interceptor/WSDLInterceptor.java, WSDLPublisherInterceptor.java, WebServiceExplorerInterceptor.java
WSDLInterceptor: added path-based rewriting, removed registry approach, changed setPort signature; WSDLPublisherInterceptor: added SOAPProxy integration, refactored path handling; WebServiceExplorerInterceptor: simplified WSDL parsing via Definitions.parse.
Utility Refactoring
core/src/main/java/.../util/FileUtil.java, URIUtil.java, WSDLUtil.java, soap/WSDLUtil.java
FileUtil: added toFileURIString helper; URIUtil: removed toFileURIString, added getNormalizedAbsolutePathOrUri; removed old WSDLUtil from util package; added new WSDLUtil to soap package for relative path rewriting.
SOAP Infrastructure
core/src/main/java/.../proxies/SOAPProxy.java, SOAPUtil.java, KubernetesWatcher.java, Envelope.java, resolver/ResolverMap.java, relocator/Relocator.java
SOAPProxy: refactored WSDL parsing to use Definitions.parse, added interceptor initialization for WSDLPublisher/Validator; SOAPUtil: added logging to analyseSOAPMessage; Envelope/KubernetesWatcher: switched to wildcard imports; ResolverMap: removed ExternalResolverConverter; Relocator: updated constructor and logging, removed deprecated method.
Other Infrastructure
core/src/main/java/.../interceptor/oauth2/authorizationservice/AuthorizationService.java, interceptor/RelocatingInterceptor.java
Minor formatting and type inference updates (var usage).
Comprehensive Test Suite
core/src/test/java/.../schemavalidation/WSDLMessageElementExtractorTest.java, WSDLSchemaExtractorTest.java, WSDLValidatorTest.java, .../util/WSDLParserTest.java, .../wsdl/parser/OperationTest.java, WSDLParserUtilTest.java, .../ws/WSDLIncludeImportTest.java
Added extensive test coverage for new WSDL parser, WSDLMessageElementExtractor, WSDLSchemaExtractor, and operation direction handling; removed old WSDLUtilTest; updated existing validation tests to use var and new assertion patterns.
Test Resources
core/src/test/resources/ws/*, import/*, include/*
Added WSDL definitions (calculator-fault.wsdl, hello-soap12.wsdl, cyclic/embedded/message-references WSDL variants); added XSD schema files for include/import scenarios (nested directories with cyclic, multiple, and message structure type definitions); updated inline-anytype.wsdl structure.
Distribution Tests
distribution/src/test/java/.../custom_error_messages/CustomErrorHandlingExampleTest.java
Updated test assertions from XML-based checks to JSON path assertions; changed request payload values and added validation failure logging.
Relocator Tests
core/src/test/java/.../relocator/RelocatorTest.java, RelocatorWADLTest.java
Commented out WSDL presence assertions in RelocatorTest; fully commented out RelocatorWADLTest (disabled without deletion).
Other Test Updates
core/src/test/java/.../SOAPFaultTest.java, SOAPMessageValidatorInterceptorTest.java, SOAPUtilTest.java, .../LargeBodyTest.java, .../URIUtilTest.java, .../ResolverTest.java
Minor var usage, assertion pattern updates, new test cases (analyseFault11DifferentNamespace); removed testMembraneSoaModel parameterized test; expanded URIUtilTest with getNormalizedAbsolutePathOrUri test cases; added LargeBodyTest static imports.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SOAPProxy
    participant WSDLParser as Definitions.parse()
    participant WSDLInterceptor
    participant ValidatorInterceptor
    participant WSDLSchemaExtractor

    Client->>SOAPProxy: init()
    SOAPProxy->>WSDLParser: parse(resolver, wsdl)
    WSDLParser->>WSDLSchemaExtractor: extract embedded schemas
    WSDLSchemaExtractor-->>WSDLParser: List<Document>
    WSDLParser-->>SOAPProxy: Definitions
    SOAPProxy->>WSDLInterceptor: setSoapProxy(this)
    SOAPProxy->>ValidatorInterceptor: setSoapProxy(this)
    SOAPProxy->>WSDLInterceptor: init()
    WSDLInterceptor->>WSDLInterceptor: setPathRewriterOnWSDLInterceptor(path)
    WSDLInterceptor-->>SOAPProxy: initialized
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

7.x, refactoring, wsdl-parser

Suggested reviewers

  • rrayst

Poem

🐰 A mighty parser hops to life,
WSDL schemas parsed with care,
No more registry strife,
Just paths rewrit in the air!
Validation now embraces the DOM,
And Definitions lead us back home. 🏠

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch new-wsdl-parser-from-7-4

@predic8

predic8 commented Mar 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@predic8

predic8 commented Mar 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai resume

- Ensured all relevant Java files across core and annot modules include the proper Apache License 2.0 headers.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
annot/pom.xml (1)

48-63: ⚠️ Potential issue | 🟠 Major

Keep the annot Log4j dependencies test-scoped.

The log4j-slf4j2-impl and log4j-core dependencies in annot/pom.xml are missing <scope>test</scope>. They should be scoped to tests in the annot module while remaining compile-scoped only in the distribution module.

Suggested fix
 		<dependency>
 			<groupId>org.apache.logging.log4j</groupId>
 			<artifactId>log4j-slf4j2-impl</artifactId>
+			<scope>test</scope>
 		</dependency>
 		<dependency>
 			<groupId>org.apache.logging.log4j</groupId>
 			<artifactId>log4j-core</artifactId>
+			<scope>test</scope>
 		</dependency>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@annot/pom.xml` around lines 48 - 63, The Log4j dependencies log4j-slf4j2-impl
and log4j-core in the annot module are missing test scope: update the dependency
entries for artifactId "log4j-slf4j2-impl" and "log4j-core" to include
<scope>test</scope> so they are only used for tests in the annot module (leave
other dependencies like jackson-databind and jackson-annotations unchanged);
ensure you modify the dependency declarations for those two artifactIds in the
pom so they are test-scoped.
core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java (1)

43-45: ⚠️ Potential issue | 🟠 Major

Keep the public constructor accepting Writer.

Nothing in this implementation requires OutputStreamWriter. The change narrows the public API for no functional gain and breaks callers that use StringWriter or custom Writer implementations. The commented-out test in RelocatorWADLTest.java (line 60) shows this was previously supported. For 6.X, preserve the wider type—XMLOutputFactory.createXMLEventWriter() accepts Writer natively.

♻️ Proposed fix
-    public Relocator(OutputStreamWriter osw, String protocol, String host,
+    public Relocator(Writer out, String protocol, String host,
                      int port, String contextPath, PathRewriter pathRewriter) throws Exception {
-        this.writer = XMLOutputFactory.newInstance().createXMLEventWriter(osw);
+        this.writer = XMLOutputFactory.newInstance().createXMLEventWriter(out);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java`
around lines 43 - 45, The public constructor currently narrows the API by taking
OutputStreamWriter; revert it to accept java.io.Writer instead (change
Relocator(OutputStreamWriter osw, String protocol, String host, int port, String
contextPath, PathRewriter pathRewriter) to Relocator(Writer writer, ...)), and
pass that Writer into
XMLOutputFactory.newInstance().createXMLEventWriter(writer) so StringWriter and
other Writer implementations continue to work (ensure signature visibility
remains public and update any direct references/tests such as
RelocatorWADLTest).
🟡 Minor comments (6)
core/src/test/resources/ws/import/message-references-import.wsdl-37-38 (1)

37-38: ⚠️ Potential issue | 🟡 Minor

Binding operation name mismatch with portType.

The binding operation is named "test" (line 37) but the portType operation is named "get" (line 28). WSDL binding operations must reference valid portType operations by name.

If this mismatch is intentional for testing parser validation, please disregard. Otherwise:

Proposed fix
-        <operation name="test">
-            <soap:operation soapAction="test"/>
+        <operation name="get">
+            <soap:operation soapAction="get"/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/test/resources/ws/import/message-references-import.wsdl` around
lines 37 - 38, The binding declares an operation named "test" but the portType
defines the operation as "get", causing a name mismatch; update the binding
<operation name="test"> to use the portType operation name "get" (or
alternatively rename the portType operation to "test" if that was intended) and
ensure the corresponding soap:operation soapAction is updated to match the
chosen operation name so the binding correctly references the portType
operation.
core/src/test/resources/ws/import/message-references-import.wsdl-23-25 (1)

23-25: ⚠️ Potential issue | 🟡 Minor

Undefined element reference m:Response.

The GetResponse message references m:Response, but the imported messages.xsd defines m:getResponse, not m:Response. This will cause schema validation to fail.

If this is intentional for testing error scenarios, please disregard. Otherwise, the element reference should be corrected.

Proposed fix
     <message name="GetResponse">
-        <part name="parameters" element="m:Response"/>
+        <part name="parameters" element="m:getResponse"/>
     </message>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/test/resources/ws/import/message-references-import.wsdl` around
lines 23 - 25, The WSDL message GetResponse references a non-existent element
m:Response; update the part element reference in the GetResponse message to the
correct element defined in messages.xsd (m:getResponse) so the part attribute
uses the existing element name (modify the <message name="GetResponse"> part
element reference from m:Response to m:getResponse).
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/ProtocolOperation.java-1-16 (1)

1-16: ⚠️ Potential issue | 🟡 Minor

Missing license header.

This file is missing the Apache 2.0 license header that is present in other new files added in this PR (e.g., Address.java, OperationTest.java).

📄 Proposed fix to add license header
+/* Copyright 2026 predic8 GmbH, www.predic8.com
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+
 package com.predic8.membrane.core.util.wsdl.parser;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/ProtocolOperation.java`
around lines 1 - 16, The file ProtocolOperation.java is missing the Apache 2.0
license header; add the same standard Apache 2.0 header used in other new files
(e.g., Address.java, OperationTest.java) at the top of the file before the
package declaration so the class ProtocolOperation and its constructor/methods
(ProtocolOperation(WSDLParserContext, Node) and getSoapAction()) have the
required license comment header.
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Part.java-28-37 (1)

28-37: ⚠️ Potential issue | 🟡 Minor

Add @Nullable annotations to public QName accessor methods.

Lines 28 and 32 declare non-nullable QName return types but delegate to a method marked @Nullable at line 36. The public API contract should align with the implementation.

Recommended fix
-    public QName getTypeQName() {
+    public `@Nullable` QName getTypeQName() {
         return getAttributeQName("type");
     }

-    public QName getElementQName() {
+    public `@Nullable` QName getElementQName() {
         return getAttributeQName("element");
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Part.java`
around lines 28 - 37, The public accessors getTypeQName and getElementQName
currently declare non-nullable QName returns but delegate to the `@Nullable`
getAttributeQName; update their signatures to return `@Nullable` QName (i.e.
annotate both getTypeQName and getElementQName with the same `@Nullable` used on
getAttributeQName) so the public API matches implementation, and add any
required import for the chosen `@Nullable` annotation if missing.
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Port.java-27-29 (1)

27-29: ⚠️ Potential issue | 🟡 Minor

getFirst() may throw NoSuchElementException if no address element exists.

If the WSDL port lacks an <address> child element (e.g., abstract WSDL or malformed document), instantiateElements(...).getFirst() will throw an unchecked exception. Consider defensive handling similar to getBinding().

🛡️ Proposed defensive handling
     public Address getAddress() {
-        return instantiateElements(element,"address",Address.class).getFirst();
+        var addresses = instantiateElements(element, "address", Address.class);
+        if (addresses.isEmpty()) {
+            throw new WSDLParserException("No address found for port: " + getName());
+        }
+        return addresses.getFirst();
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Port.java`
around lines 27 - 29, The getAddress() method currently calls
instantiateElements(element, "address", Address.class).getFirst() which can
throw NoSuchElementException when no <address> child exists; update getAddress()
to defensively handle the empty case like getBinding() does by checking the
instantiated list for emptiness and returning null (or an appropriate absent
value) instead of calling getFirst() directly so missing address elements don't
cause unchecked exceptions.
core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java-178-184 (1)

178-184: ⚠️ Potential issue | 🟡 Minor

Consider defensive null-check for soapProxy.getWsdl().

If soapProxy.getWsdl() returns null, setWsdl(null) will be called at line 183, which clears all paths and adds null to documentsToProcess. This could cause issues downstream.

🛡️ Proposed defensive check
     private void getWSDLFromEmbeddingSOAPProxy() {
         if (soapProxy == null) {
             throw new ConfigurationException("<wsdlPublisher> can only be used within a <soapProxy> or needs to declare <wsdlPublisher wsdl='...'>");
         }
         wsdl = soapProxy.getWsdl();
+        if (wsdl == null) {
+            throw new ConfigurationException("<wsdlPublisher> requires <soapProxy wsdl='...'> to be set");
+        }
         setWsdl(wsdl);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java`
around lines 178 - 184, getWSDLFromEmbeddingSOAPProxy() currently calls
soapProxy.getWsdl() and unconditionally passes the result to setWsdl(), which
can clear paths and add null into documentsToProcess; add a defensive
null-check: after obtaining wsdl = soapProxy.getWsdl(), if wsdl is null throw a
ConfigurationException (or log and return) with a clear message that the
embedding <soapProxy> has no WSDL, otherwise call setWsdl(wsdl). Update the
method to reference soapProxy and getWsdl() and ensure setWsdl() is only called
with a non-null wsdl to avoid corrupting documentsToProcess.
🧹 Nitpick comments (12)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)

27-30: Consider adding null-safety for public API.

Both path and replacementName parameters could cause issues if null: matcher(null) throws NullPointerException, and formatted(null) embeds the literal string "null" in the output.

🛡️ Optional: Add null checks
 public static String rewriteRelativeWsdlPath(String path, String replacementName) {
+    if (path == null || replacementName == null) {
+        throw new IllegalArgumentException("path and replacementName must not be null");
+    }
     return relativePathPattern
             .matcher(path)
             .replaceAll(quoteReplacement("./%s?".formatted(replacementName)));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java` around
lines 27 - 30, rewriteRelativeWsdlPath currently calls matcher(path) and
formatted(replacementName) without guarding against nulls; add null-safety at
the start of the public method by validating inputs (e.g., use
Objects.requireNonNull(path, "path must not be null") and either
requireNonNull(replacementName, "replacementName must not be null") or coerce
replacementName to "" when null) so matcher(...) never receives null and
formatted(...) does not produce the literal "null"; keep the rest of the method
(relativePathPattern.matcher(...).replaceAll(quoteReplacement(...))) unchanged
and throw clear IllegalArgumentException/NullPointerException messages if you
choose to reject nulls.
core/src/test/java/com/predic8/membrane/core/interceptor/schemavalidation/SOAPUtilTest.java (1)

127-129: Prefer classpath resource loading over filesystem-relative paths in tests.

Line 127–129 makes tests dependent on working directory layout. Loading from classpath is more stable across IDE/Maven/CI runs.

♻️ Proposed refactor
-    private Message getMessage(String path) throws Exception {
-        return ok().contentType(TEXT_XML).body(new FileInputStream(path), true).build();
-    }
+    private Message getMessage(String resourcePath) throws IOException {
+        InputStream in = SOAPUtilTest.class.getClassLoader().getResourceAsStream(resourcePath);
+        assertNotNull(in, "Missing test resource: " + resourcePath);
+        return ok().contentType(TEXT_XML).body(in, true).build();
+    }

Also update call sites to classpath-relative values, e.g.:

  • wsdlValidator/soapFaultFromSpec.xml
  • wsdlValidator/soapFaultCustom.xml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/test/java/com/predic8/membrane/core/interceptor/schemavalidation/SOAPUtilTest.java`
around lines 127 - 129, The test's getMessage method currently opens files via
new FileInputStream(path) which makes tests reliant on the working directory;
change getMessage to load the test file from the classpath (e.g., use
getClass().getResourceAsStream(path) or
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) and
pass that InputStream into ok().contentType(TEXT_XML).body(...).build(); then
update all call sites that pass filesystem-relative strings to use
classpath-relative resource paths such as "wsdlValidator/soapFaultFromSpec.xml"
and "wsdlValidator/soapFaultCustom.xml" so resources are resolved consistently
in IDE/Maven/CI.
core/src/test/resources/ws/include/xsd/inc/MessageStructureTypes2.xsd (1)

1-8: Consider using the imported namespace in du to strengthen parser coverage.

Right now the import is present but unused; adding one dt:* reference makes this fixture validate cross-namespace resolution end-to-end.

Proposed test-fixture refinement
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns:dt="http://example.com/test/data-types"
            targetNamespace="http://example.com/test"
            elementFormDefault="qualified">
@@
-  <xs:element name="du"/>
+  <xs:element name="du">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="dt:B5"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/test/resources/ws/include/xsd/inc/MessageStructureTypes2.xsd` around
lines 1 - 8, The XSD imports the data-types namespace but never uses it; update
MessageStructureTypes2.xsd so the imported namespace is referenced by declaring
a prefix (e.g., xmlns:dt="http://example.com/test/data-types") and change the
xs:element named "du" to reference a type or element from that namespace (for
example set du to type="dt:SomeType" or include a child element from the dt:
namespace) so cross-namespace resolution is exercised; locate the xs:element
name="du" and the xs:import statement and add the xmlns:dt declaration and the
dt: reference there.
core/src/test/resources/ws/include/include.xsd (1)

6-16: Optional cleanup: remove commented-out schema directives in fixture.

Keeping only active declarations makes this resource easier to read and maintain.

Suggested cleanup
-<!--            <xs:include schemaLocation="./xsd/messages.xsd"/>-->
             <xs:include schemaLocation="xsd/inc/MessageStructureTypes2.xsd"/>
-<!--            <xs:import namespace="http://example.com/test/messages" schemaLocation="./xsd/messages.xsd"/>-->
@@
-            <xs:element name="test">
-            </xs:element>
+            <xs:element name="test"/>
@@
-            <xs:element name="testResponse">
-            </xs:element>
+            <xs:element name="testResponse"/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/test/resources/ws/include/include.xsd` around lines 6 - 16, Remove
the commented-out schema directives to clean up the fixture: delete the
commented lines containing "<!-- <xs:include
schemaLocation="./xsd/messages.xsd"/> -->" and "<!-- <xs:import
namespace="http://example.com/test/messages"
schemaLocation="./xsd/messages.xsd"/> -->" so only the active xs:include
(schemaLocation="xsd/inc/MessageStructureTypes2.xsd") and the xs:element
definitions "test" and "testResponse" remain, improving readability and
maintainability.
pom.xml (1)

273-287: Align the XMLUnit module versions.

xmlunit-core is now managed at 2.10.0, but xmlunit-matchers stays at 2.9.1. xmlunit-matchers 2.10.0 is published, and that release targets xmlunit-core 2.10.0, so this leaves the parent POM with an avoidable mixed XMLUnit test stack. (repo.maven.apache.org)

Suggested fix
 			<dependency>
 				<groupId>org.xmlunit</groupId>
 				<artifactId>xmlunit-matchers</artifactId>
-				<version>2.9.1</version>
+				<version>2.10.0</version>
 			</dependency>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pom.xml` around lines 273 - 287, The POM has mixed XMLUnit versions:
xmlunit-core is 2.10.0 while xmlunit-matchers remains 2.9.1; update the
xmlunit-matchers dependency entry (artifactId: xmlunit-matchers) to use version
2.10.0 so both modules align with xmlunit-core, then run the build/tests to
verify compatibility.
core/src/test/java/com/predic8/membrane/core/interceptor/schemavalidation/SOAPFaultTest.java (1)

39-39: LGTM with minor style inconsistency.

The var usage is fine, but note that testSkipFaults (line 47) and testSkipFault2 (line 55) still use explicit ValidatorInterceptor type. Consider applying var consistently across all test methods if that's the intended style direction.

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/test/java/com/predic8/membrane/core/interceptor/schemavalidation/SOAPFaultTest.java`
at line 39, Replace the explicit local variable type with "var" in the test
methods that still declare a ValidatorInterceptor explicitly (look for local
variables named like the interceptor in testSkipFaults and testSkipFault2) so
that they match the style used when assigning createValidatorInterceptor(false);
i.e., change "ValidatorInterceptor i = ..." to "var i = ..." in those test
methods.
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/WSDLParserException.java (1)

17-20: Add a cause constructor to preserve parse failure context.

Current API only supports message text; wrapping underlying exceptions will lose stack provenance unless callers chain manually.

♻️ Suggested update
 public class WSDLParserException extends RuntimeException {
     public WSDLParserException(String message) {
         super(message);
     }
+
+    public WSDLParserException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/WSDLParserException.java`
around lines 17 - 20, WSDLParserException currently only has a String
constructor so underlying parse exceptions lose stack/context; add overloaded
constructors to preserve causes: implement WSDLParserException(String message,
Throwable cause) that calls super(message, cause) and optionally
WSDLParserException(Throwable cause) that calls super(cause) (and keep the
existing WSDLParserException(String) for compatibility) so callers can
wrap/paraphrase parse failures without losing the original exception.
core/src/test/java/com/predic8/membrane/core/ws/WSDLIncludeImportTest.java (1)

102-104: Prefer explicit null-check for test resource lookup.

Line 103 can throw an unhelpful NPE if the resource path changes; Objects.requireNonNull(...) gives clearer failure diagnostics.

Suggested test-hardening diff
-        var validator = new WSDLValidator(new ResolverMap(),
-                WSDLIncludeImportTest.class.getResource("/ws/include/include.wsdl").toString(),
+        var validator = new WSDLValidator(new ResolverMap(),
+                Objects.requireNonNull(
+                        WSDLIncludeImportTest.class.getResource("/ws/include/include.wsdl"),
+                        "Missing test resource /ws/include/include.wsdl"
+                ).toString(),
                 "TestService",
                 (msg, exc) -> log.info("Validation failure: {}", msg), true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/test/java/com/predic8/membrane/core/ws/WSDLIncludeImportTest.java`
around lines 102 - 104, Wrap the test resource lookup in an explicit null-check
using Objects.requireNonNull to avoid an ambiguous NPE: call
Objects.requireNonNull(WSDLIncludeImportTest.class.getResource("/ws/include/include.wsdl"),
"resource '/ws/include/include.wsdl' not found") and then call toString() for
the WSDLValidator constructor; also add the java.util.Objects import if missing.
This change targets the WSDLIncludeImportTest test where WSDLValidator(...) is
constructed.
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/schema/Import.java (1)

52-62: Consider consolidating duplicate empty-check logic.

hasSchemaLocation() (lines 52-54) and the condition in getSchema() (line 58) perform the same check. You could reuse hasSchemaLocation() in the override.

♻️ DRY improvement
     `@Override`
     protected Schema getSchema(WSDLParserContext ctx) {
-        if (schemaLocation == null || schemaLocation.isEmpty()) {
+        if (!hasSchemaLocation()) {
             return null;
         }
         return super.getSchema(ctx);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/schema/Import.java`
around lines 52 - 62, The null/empty check for schemaLocation is duplicated;
update getSchema(WSDLParserContext ctx) to call the existing hasSchemaLocation()
instead of repeating the condition: if hasSchemaLocation() returns false, return
null, otherwise delegate to super.getSchema(ctx). Keep the existing
hasSchemaLocation() method as the single source of truth for the empty-check so
future changes only need to be made in one place.
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/schema/AbstractIncludeImport.java (1)

49-51: Wrap exceptions with more context for debugging.

Rethrowing a generic RuntimeException loses information about which schema location failed to resolve. Consider including the schemaLocation in the exception message.

♻️ Proposed improvement
         } catch (Exception e) {
-            throw new RuntimeException(e);
+            throw new RuntimeException("Failed to resolve schema at location: " + schemaLocation, e);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/schema/AbstractIncludeImport.java`
around lines 49 - 51, The catch block in AbstractIncludeImport currently
rethrows a generic RuntimeException losing context; update the catch to throw a
new RuntimeException that includes the schemaLocation (and any identifying info)
in the message and pass the original exception as the cause (e.g., throw new
RuntimeException("Failed to resolve schemaLocation: "+ schemaLocation, e)); this
keeps the original stacktrace and makes it clear which schema failed to resolve.
core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/BindingStyle.java (1)

1-6: Missing copyright header.

Other new files in this PR include the Apache 2.0 license header. This file should have the same header for consistency.

📝 Add license header
+/* Copyright 2026 predic8 GmbH, www.predic8.com
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+
 package com.predic8.membrane.core.util.wsdl.parser;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/BindingStyle.java`
around lines 1 - 6, Add the standard Apache 2.0 license header to the top of
BindingStyle.java (the file in package
com.predic8.membrane.core.util.wsdl.parser) so it matches other new files in the
PR; insert the same multi-line Apache 2.0 copyright/license block used elsewhere
in the repo above the package declaration in BindingStyle.java.
core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java (1)

153-166: Keep context on these error logs.

Both branches log with an empty message, which makes search, aggregation, and alerting much harder in production. A short static prefix is enough.

💡 Suggested change
-            log.error("", e);
+            log.error("Could not read message body during validation.", e);
@@
-            log.error("", e);
+            log.error("Validator execution failed.", e);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java`
around lines 153 - 166, The empty log.error calls in the ReadingBodyException
catch and the generic Exception catch around validator.validateMessage remove
context; change them to include a short static prefix (e.g.
"ValidatorInterceptor: could not read message body" in the ReadingBodyException
block and "ValidatorInterceptor: validation failed" in the
validator.validateMessage catch) while still passing the exception object to
log.error; update the log.error invocations near the ReadingBodyException
handler and the catch(Exception e) after validator.validateMessage() to use
these descriptive messages so the internal(...).detail(...).exception(e) flow
remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/AbstractXMLSchemaValidator.java`:
- Around line 68-74: The init() loop currently calls createValidators()
repeatedly which rebuilds SchemaFactory and recompiles all schemas for each pool
entry; change initialization to compile and cache Schema objects once (using
SchemaFactory.newSchema(source)) and then populate the validators queue by
creating fresh Validator instances from the cached Schema(s)
(Schema.newValidator()) instead of recompiling; update createValidators() (or
add a helper) so it reuses the cached Schema instances to produce Validators,
and ensure any SchemaFactory/Scheme compilation logic lives in a single
initialization step and that validators is filled with Validators created from
those cached Schema objects.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/WSDLMessageElementExtractor.java`:
- Around line 61-65: The current early-return in getTypesByStyle suppresses
serviceName-based validation and style detection when Definitions.getServices()
is empty, forcing all PortTypes into the document bucket; change getTypesByStyle
to not short-circuit on empty services but instead call
getPortTypesByStyle(definitions, serviceName) so style detection runs even for
service-less WSDLs (e.g., find RPC bindings via bindings/portTypes), and update
downstream handling so Message::getPart() is only used for document-style
messages while RPC-style messages are handled with their specific part/parameter
extraction logic (adjust code paths in getPortTypesByStyle and any callers that
assume document-only message parsing).

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/WSDLSchemaExtractor.java`:
- Around line 63-74: The extracted Document from extractSchema lacks an explicit
base URI; update extractSchema(Element originalSchema, List<Attr>
definitionNamespaces) to accept a base URI parameter (e.g. String location) and
call schema.setDocumentURI(location) before returning (retain
addMissingNamespaceDeclarations(copiedSchema,...)). Also update all callers of
extractSchema to pass the WSDL/schema source location (the same value currently
passed to DOMSource.setSystemId in AbstractXMLSchemaValidator.createValidator())
so xsd:import/include resolution no longer relies solely on downstream
DOMSource.setSystemId.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/WSDLValidator.java`:
- Around line 106-129: The response-element whitelist is being applied to SOAP
faults (so declared WSDL faults fail); guard the response-element check to skip
it for faults by changing the condition in WSDLValidator to only run when the
message is a Response AND the validation result is not a fault: i.e. update the
branch that uses message instanceof Response /
isPossibleResponseElement(result.soapElement()) to also require
!result.isFault() (or otherwise short-circuit when result.isFault()), leaving
request-element checks and schema validation unchanged; reference symbols:
skipFaults, result.isFault(), message instanceof Response,
isPossibleResponseElement(...), responseElements.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/XMLSchemaValidator.java`:
- Around line 52-54: The getSchemas() method in XMLSchemaValidator currently
returns null which causes a NPE when AbstractXMLSchemaValidator.init() →
createValidators() calls .size(); change getSchemas() to return an empty List
(e.g., Collections.emptyList() or new ArrayList<>()) instead of null so callers
can safely call size() and iterate; update the XMLSchemaValidator.getSchemas()
implementation accordingly.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/soap/WebServiceExplorerInterceptor.java`:
- Around line 166-175: The operations table code in
WebServiceExplorerInterceptor that maps om -> om.getMessage().getPart() assumes
document-style messages and calls p.getElementQName().toString(), which throws
for RPC messages (elementQName may be null and messages can have multiple
parts); fix by iterating the actual parts collection (use
om.getMessage().getParts() or equivalent) instead of getPart(), for each Part p
build a safe representation that checks p.getElementQName() and falls back to
p.getTypeQName() and p.getName() (avoid calling toString() on a possibly null
QName), and write that representation to the table so RPC multi-part/type-based
signatures are preserved (update the input/output/fault loops that reference
Part p and replace the map/getPart usage accordingly).
- Around line 116-120: The code currently always picks the first WSDL
service/port via service.getPorts().getFirst() which breaks multi-service/port
WSDLs and can throw if that service has no ports; change the selection to locate
the correct service/port instead of hardcoding the first one: when you parse
Definitions.parse(...) iterate over definitions.getServices() to find a service
that matches the proxy's configured service name/namespace or at least has
non-empty ports, then from that service pick a port that best matches the proxy
endpoint (e.g., by port name, binding/endpoint address or other proxy selection
criteria); if no exact match exists, fall back to the first service that
contains ports and the first non-empty port, preserving the later empty-port
fallback logic. Ensure you replace uses of getFirst() (both for service and
port) and update variables service, port and ports accordingly.

In `@core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java`:
- Around line 181-185: getLocation currently always uses
service.getPorts().getFirst() and ignores the proxy's portName and doesn't
handle zero ports; update
getLocation(com.predic8.membrane.core.util.wsdl.parser.Service) to first check
if service.getPorts() is empty and throw a ConfigurationException with a clear
message, then if a portName (the proxy's configured portName) is set, find the
port with that name (e.g., iterate service.getPorts() to match port.getName())
and use its address location, otherwise fall back to the first port; replace the
direct getFirst() call with this selection logic and throw the existing
ConfigurationException if the chosen port has no `@location`.

In `@core/src/main/java/com/predic8/membrane/core/util/SOAPUtil.java`:
- Line 137: The current debug call log.debug("Analyzing SOAP message: {}", msg)
logs the full Message (including headers/body) and may leak sensitive SOAP
payloads; change the call to a static message such as log.debug("Analyzing SOAP
message") and remove passing the Message object (reference: the log.debug
invocation in SOAPUtil.java and the Message instance named msg) so no
Message.toString() is emitted to logs.

In `@core/src/main/java/com/predic8/membrane/core/util/URIUtil.java`:
- Around line 153-176: getNormalizedAbsolutePathOrUri currently treats inputs
with '?' '#' or starting with '//' as URIs and calls URI.create(location) which
can throw or return a relative URI; change this branch to first try creating a
URI and if creation fails or uri.isAbsolute() is false, fall back to treating it
as a filesystem path by calling normalizeInternal(location); if URI creation
succeeds and uri.isAbsolute() then return uri.normalize().toString(); ensure you
reference the existing normalizeInternal(...) method and the URI_SCHEME_PATTERN
logic so the code first attempts URI parsing but gracefully catches
IllegalArgumentException or non-absolute URIs and returns
normalizeInternal(location) instead.

In `@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Binding.java`:
- Around line 66-69: The code in Binding.getPortType() only compares the local
name from getAttribute("type") which breaks when different namespaces use the
same local name and also will NPE if the attribute is missing; change this to
(1) validate that getAttribute("type") is present and throw a
WSDLParserException with a clear message if it is null/empty, (2) parse the
attribute into a full QName by resolving its prefix to a namespace URI (e.g.
split "prefix:local" or "local" and use the binding/context namespace resolution
helper to get the namespace URI) and create a javax.xml.namespace.QName (or
equivalent) with namespace URI + local part, and (3) match against port types by
comparing both namespaceURI and localPart (e.g.
pt.getQName().equals(parsedQName) or
pt.getName().equals(parsedQName.getLocalPart()) &&
pt.getNamespaceURI().equals(parsedQName.getNamespaceURI())) instead of using
getLocalName(getAttribute("type")); keep use of WSDLParserException for
missing/no-match cases.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Definitions.java`:
- Around line 65-68: The parse() method currently calls getTypes()
unconditionally which makes WSDLs without a <types> block fail early; change
parse() to be tolerant by checking whether getTypes() (or getTypes().element) is
present before calling instantiateXSDElements and importEmbeddedSchemas: only
call instantiateXSDElements(getTypes().element, "schema", Schema.class) and
importEmbeddedSchemas() when getTypes() is non-null (or its element is
non-null), otherwise leave schemas empty/null and continue parsing
targetNamespace, bindings and services; update any code that assumes schemas was
initialized to handle the absent case.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Operation.java`:
- Around line 60-62: The current getMessage() in Operation uses only the local
name (via WSDLParserUtil.getLocalName) which can mis-resolve imported messages
and silently ignore undeclared prefixes; change it to resolve the full QName
from the raw attribute string returned by getAttribute("message"), validate that
any prefix is declared (fail with WSDLParserException if not), extract namespace
URI and local part, and call the definitions-level lookup that accepts
namespace+localName (or otherwise locate by QName) instead of
ctx.definitions().findMessage(localName); update Operation.getMessage() to
perform this QName resolution and throw WSDLParserException on
missing/undeclared prefix or when the fully-qualified message is not found.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/WSDLParserContext.java`:
- Around line 28-30: WSDLParserContext.basePath currently mutates the shared
visitedLocations list before creating the new WSDLParserContext, which can
retroactively change older contexts and break immutable lists; fix by creating a
defensive copy of visitedLocations (e.g., new ArrayList<>(visitedLocations)),
add the new basePath to that copy, and pass the copy into the WSDLParserContext
constructor so each derived context has its own traversal state without mutating
the original list.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/WSDLParserUtil.java`:
- Around line 25-28: The DOM parser in WSDLParserUtil.parse still allows DOCTYPE
and external entity resolution; update the DocumentBuilderFactory and
DocumentBuilder configuration to harden against XXE: enable secure processing
(XMLConstants.FEATURE_SECURE_PROCESSING) on the factory, disable DOCTYPE and
external entity access (features/properties for
"http://apache.org/xml/features/disallow-doctype-decl",
"http://xml.org/sax/features/external-general-entities",
"http://xml.org/sax/features/external-parameter-entities", and set
"http://javax.xml.XMLConstants/property/accessExternalDTD" and
"http://javax.xml.XMLConstants/property/accessExternalSchema" to ""), and ensure
the created DocumentBuilder does not expand external entities (e.g.,
setExpandEntityReferences(false) or equivalent) before calling parse(is); apply
these changes inside the parse method around
DocumentBuilderFactory.newInstance(), dbf.setNamespaceAware(true), and
newDocumentBuilder().parse(is).

In `@core/src/test/java/com/predic8/membrane/core/util/URIUtilTest.java`:
- Around line 241-244: The test method normalizesFileUri should expect the
RFC-compliant URI with three slashes; update the assertion in normalizesFileUri
to expect "file:///test.xml" instead of "file:/test.xml" so
getNormalizedAbsolutePathOrUri(...) matches Java's URI.normalize().toString()
behavior.

In
`@core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorTest.java`:
- Around line 41-45: The test methods (e.g., wsdl()) currently only call
relocator.relocate(...) and print os.toString(UTF_8), so they don't assert
behavior; restore meaningful assertions by checking the relocated output and
state: use Relocator.relocate(getFile("/blz-service.wsdl")) and then assert on
relocator's results (e.g., call relocator.isWsdlFound() if still available or
otherwise inspect the relocated output buffer/string via the os.toString(UTF_8)
result) to verify expected content (presence of relocated URLs, expected WSDL
elements, or counts); remove the System.out.println noise and replace it with
assertTrue/assertEquals/assertThat checks that validate the relocation behavior
(apply the same pattern to the other test method that used isWsdlFound()).

In
`@core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorWADLTest.java`:
- Around line 1-91: Uncomment the RelocatorWADLTest class and its methods and
either restore it as a runnable test or explicitly disable it: add JUnit 5
annotations (`@BeforeEach` on setUp, `@Test` on testWADLRelocate) and either remove
comments so the test runs, or annotate the class or testWADLRelocate with
`@Disabled`("explain why disabled") (import org.junit.jupiter.api.Disabled).
Ensure the NamespaceContext, Relocator, writer, xpath setup in setUp remains
intact and the helper assertAttribute is visible; keep references to Relocator,
testWADLRelocate, setUp, and assertAttribute so the test compiles and the intent
(or explicit disable reason) is clear.

In `@core/src/test/resources/ws/include/multiple.wsdl`:
- Around line 23-31: The nested xs:element "test" currently sits directly under
xs:element "testResponse" which is invalid; modify the element declaration for
"testResponse" so that its child "test" is defined inside an xs:complexType
containing an xs:sequence (i.e., move the xs:element name="test" into an
xs:complexType/xs:sequence block) ensuring the inner element is wrapped properly
and retains its existing content (the xs:complexType with xs:sequence and
xs:element ref="tns:a").

---

Outside diff comments:
In `@annot/pom.xml`:
- Around line 48-63: The Log4j dependencies log4j-slf4j2-impl and log4j-core in
the annot module are missing test scope: update the dependency entries for
artifactId "log4j-slf4j2-impl" and "log4j-core" to include <scope>test</scope>
so they are only used for tests in the annot module (leave other dependencies
like jackson-databind and jackson-annotations unchanged); ensure you modify the
dependency declarations for those two artifactIds in the pom so they are
test-scoped.

In `@core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java`:
- Around line 43-45: The public constructor currently narrows the API by taking
OutputStreamWriter; revert it to accept java.io.Writer instead (change
Relocator(OutputStreamWriter osw, String protocol, String host, int port, String
contextPath, PathRewriter pathRewriter) to Relocator(Writer writer, ...)), and
pass that Writer into
XMLOutputFactory.newInstance().createXMLEventWriter(writer) so StringWriter and
other Writer implementations continue to work (ensure signature visibility
remains public and update any direct references/tests such as
RelocatorWADLTest).

---

Minor comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java`:
- Around line 178-184: getWSDLFromEmbeddingSOAPProxy() currently calls
soapProxy.getWsdl() and unconditionally passes the result to setWsdl(), which
can clear paths and add null into documentsToProcess; add a defensive
null-check: after obtaining wsdl = soapProxy.getWsdl(), if wsdl is null throw a
ConfigurationException (or log and return) with a clear message that the
embedding <soapProxy> has no WSDL, otherwise call setWsdl(wsdl). Update the
method to reference soapProxy and getWsdl() and ensure setWsdl() is only called
with a non-null wsdl to avoid corrupting documentsToProcess.

In `@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Part.java`:
- Around line 28-37: The public accessors getTypeQName and getElementQName
currently declare non-nullable QName returns but delegate to the `@Nullable`
getAttributeQName; update their signatures to return `@Nullable` QName (i.e.
annotate both getTypeQName and getElementQName with the same `@Nullable` used on
getAttributeQName) so the public API matches implementation, and add any
required import for the chosen `@Nullable` annotation if missing.

In `@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/Port.java`:
- Around line 27-29: The getAddress() method currently calls
instantiateElements(element, "address", Address.class).getFirst() which can
throw NoSuchElementException when no <address> child exists; update getAddress()
to defensively handle the empty case like getBinding() does by checking the
instantiated list for emptiness and returning null (or an appropriate absent
value) instead of calling getFirst() directly so missing address elements don't
cause unchecked exceptions.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/ProtocolOperation.java`:
- Around line 1-16: The file ProtocolOperation.java is missing the Apache 2.0
license header; add the same standard Apache 2.0 header used in other new files
(e.g., Address.java, OperationTest.java) at the top of the file before the
package declaration so the class ProtocolOperation and its constructor/methods
(ProtocolOperation(WSDLParserContext, Node) and getSoapAction()) have the
required license comment header.

In `@core/src/test/resources/ws/import/message-references-import.wsdl`:
- Around line 37-38: The binding declares an operation named "test" but the
portType defines the operation as "get", causing a name mismatch; update the
binding <operation name="test"> to use the portType operation name "get" (or
alternatively rename the portType operation to "test" if that was intended) and
ensure the corresponding soap:operation soapAction is updated to match the
chosen operation name so the binding correctly references the portType
operation.
- Around line 23-25: The WSDL message GetResponse references a non-existent
element m:Response; update the part element reference in the GetResponse message
to the correct element defined in messages.xsd (m:getResponse) so the part
attribute uses the existing element name (modify the <message
name="GetResponse"> part element reference from m:Response to m:getResponse).

---

Nitpick comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/schemavalidation/ValidatorInterceptor.java`:
- Around line 153-166: The empty log.error calls in the ReadingBodyException
catch and the generic Exception catch around validator.validateMessage remove
context; change them to include a short static prefix (e.g.
"ValidatorInterceptor: could not read message body" in the ReadingBodyException
block and "ValidatorInterceptor: validation failed" in the
validator.validateMessage catch) while still passing the exception object to
log.error; update the log.error invocations near the ReadingBodyException
handler and the catch(Exception e) after validator.validateMessage() to use
these descriptive messages so the internal(...).detail(...).exception(e) flow
remains unchanged.

In `@core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java`:
- Around line 27-30: rewriteRelativeWsdlPath currently calls matcher(path) and
formatted(replacementName) without guarding against nulls; add null-safety at
the start of the public method by validating inputs (e.g., use
Objects.requireNonNull(path, "path must not be null") and either
requireNonNull(replacementName, "replacementName must not be null") or coerce
replacementName to "" when null) so matcher(...) never receives null and
formatted(...) does not produce the literal "null"; keep the rest of the method
(relativePathPattern.matcher(...).replaceAll(quoteReplacement(...))) unchanged
and throw clear IllegalArgumentException/NullPointerException messages if you
choose to reject nulls.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/BindingStyle.java`:
- Around line 1-6: Add the standard Apache 2.0 license header to the top of
BindingStyle.java (the file in package
com.predic8.membrane.core.util.wsdl.parser) so it matches other new files in the
PR; insert the same multi-line Apache 2.0 copyright/license block used elsewhere
in the repo above the package declaration in BindingStyle.java.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/schema/AbstractIncludeImport.java`:
- Around line 49-51: The catch block in AbstractIncludeImport currently rethrows
a generic RuntimeException losing context; update the catch to throw a new
RuntimeException that includes the schemaLocation (and any identifying info) in
the message and pass the original exception as the cause (e.g., throw new
RuntimeException("Failed to resolve schemaLocation: "+ schemaLocation, e)); this
keeps the original stacktrace and makes it clear which schema failed to resolve.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/schema/Import.java`:
- Around line 52-62: The null/empty check for schemaLocation is duplicated;
update getSchema(WSDLParserContext ctx) to call the existing hasSchemaLocation()
instead of repeating the condition: if hasSchemaLocation() returns false, return
null, otherwise delegate to super.getSchema(ctx). Keep the existing
hasSchemaLocation() method as the single source of truth for the empty-check so
future changes only need to be made in one place.

In
`@core/src/main/java/com/predic8/membrane/core/util/wsdl/parser/WSDLParserException.java`:
- Around line 17-20: WSDLParserException currently only has a String constructor
so underlying parse exceptions lose stack/context; add overloaded constructors
to preserve causes: implement WSDLParserException(String message, Throwable
cause) that calls super(message, cause) and optionally
WSDLParserException(Throwable cause) that calls super(cause) (and keep the
existing WSDLParserException(String) for compatibility) so callers can
wrap/paraphrase parse failures without losing the original exception.

In
`@core/src/test/java/com/predic8/membrane/core/interceptor/schemavalidation/SOAPFaultTest.java`:
- Line 39: Replace the explicit local variable type with "var" in the test
methods that still declare a ValidatorInterceptor explicitly (look for local
variables named like the interceptor in testSkipFaults and testSkipFault2) so
that they match the style used when assigning createValidatorInterceptor(false);
i.e., change "ValidatorInterceptor i = ..." to "var i = ..." in those test
methods.

In
`@core/src/test/java/com/predic8/membrane/core/interceptor/schemavalidation/SOAPUtilTest.java`:
- Around line 127-129: The test's getMessage method currently opens files via
new FileInputStream(path) which makes tests reliant on the working directory;
change getMessage to load the test file from the classpath (e.g., use
getClass().getResourceAsStream(path) or
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) and
pass that InputStream into ok().contentType(TEXT_XML).body(...).build(); then
update all call sites that pass filesystem-relative strings to use
classpath-relative resource paths such as "wsdlValidator/soapFaultFromSpec.xml"
and "wsdlValidator/soapFaultCustom.xml" so resources are resolved consistently
in IDE/Maven/CI.

In `@core/src/test/java/com/predic8/membrane/core/ws/WSDLIncludeImportTest.java`:
- Around line 102-104: Wrap the test resource lookup in an explicit null-check
using Objects.requireNonNull to avoid an ambiguous NPE: call
Objects.requireNonNull(WSDLIncludeImportTest.class.getResource("/ws/include/include.wsdl"),
"resource '/ws/include/include.wsdl' not found") and then call toString() for
the WSDLValidator constructor; also add the java.util.Objects import if missing.
This change targets the WSDLIncludeImportTest test where WSDLValidator(...) is
constructed.

In `@core/src/test/resources/ws/include/include.xsd`:
- Around line 6-16: Remove the commented-out schema directives to clean up the
fixture: delete the commented lines containing "<!-- <xs:include
schemaLocation="./xsd/messages.xsd"/> -->" and "<!-- <xs:import
namespace="http://example.com/test/messages"
schemaLocation="./xsd/messages.xsd"/> -->" so only the active xs:include
(schemaLocation="xsd/inc/MessageStructureTypes2.xsd") and the xs:element
definitions "test" and "testResponse" remain, improving readability and
maintainability.

In `@core/src/test/resources/ws/include/xsd/inc/MessageStructureTypes2.xsd`:
- Around line 1-8: The XSD imports the data-types namespace but never uses it;
update MessageStructureTypes2.xsd so the imported namespace is referenced by
declaring a prefix (e.g., xmlns:dt="http://example.com/test/data-types") and
change the xs:element named "du" to reference a type or element from that
namespace (for example set du to type="dt:SomeType" or include a child element
from the dt: namespace) so cross-namespace resolution is exercised; locate the
xs:element name="du" and the xs:import statement and add the xmlns:dt
declaration and the dt: reference there.

In `@pom.xml`:
- Around line 273-287: The POM has mixed XMLUnit versions: xmlunit-core is
2.10.0 while xmlunit-matchers remains 2.9.1; update the xmlunit-matchers
dependency entry (artifactId: xmlunit-matchers) to use version 2.10.0 so both
modules align with xmlunit-core, then run the build/tests to verify
compatibility.

Comment thread core/src/test/java/com/predic8/membrane/core/util/URIUtilTest.java
Comment thread core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorWADLTest.java Outdated
Comment thread core/src/test/resources/ws/include/multiple.wsdl
@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Reviews resumed.

predic8 added 3 commits March 13, 2026 11:38
…d simplify test setup

- Replaced `ServiceProxy` with `APIProxy` for target configuration.
- Improved test readability by using string-based SOAP request in place of external XML files.
- Streamlined setup and teardown with updated Router lifecycle methods.
- Enhanced base path handling in `WSDLParserContext` to avoid alterations in original visited locations.
- Simplified schema parsing logic in `Definitions` with conditional `instantiateChild`.
- Updated `WSDLValidator` to correctly handle fault cases in response element validation.
- Added WSDL namespace detection in `Relocator` and respective tests in `RelocatorTest`.
- Restored and partially reintroduced `RelocatorWADLTest` with Apache License header.
@rrayst rrayst merged commit 5b50668 into 6.X Mar 15, 2026
3 checks passed
@rrayst rrayst deleted the new-wsdl-parser-from-7-4 branch March 15, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants