Skip to content

Comments

Escaping For setBody#2810

Open
predic8 wants to merge 26 commits intomasterfrom
compute-url-expression-at-http-client-interceptor
Open

Escaping For setBody#2810
predic8 wants to merge 26 commits intomasterfrom
compute-url-expression-at-http-client-interceptor

Conversation

@predic8
Copy link
Member

@predic8 predic8 commented Feb 20, 2026

Summary by CodeRabbit

  • New Features

    • Auto-select JSON and XML escaping based on content type, with a safe fallback and warning when unrecognized.
    • Expression results used to set message bodies now accept non-string values (converted to string) and preserve content-type when present.
    • Exposed a protected extension point to instantiate expressions with proper escaping behavior.
  • Tests

    • Added tests for escaping and null-value insertion behavior; improved test logging to show request/response on failures.
  • Documentation

    • Added a license header to a test file.

…URL handling and modify target configurations

- Introduced `computeDestinationExpressions` to streamline target URL modification logic.
- Improved `DispatchingInterceptor` handling of base path resolution with illegal characters.
- Enhanced `urlEncode` and `pathSeg` utility functions for safety and clarity.
- Refactored `HTTPClientInterceptor` to adjust the target flow and error messages.
- Added extensive URI tests, including custom-parsed and relative path resolution scenarios.
- Updated `applyTargetModifications` for streamlined behavior during request processing.
…t URLs

- Introduced `TemplateUtil` with a method to check for template markers.
- Enhanced `TemplateExchangeExpression` to support URL encoding for dynamic templates.
- Updated `Target` to skip unnecessary evaluation for URLs without template markers.
- Added extensive tests to verify correct URL encoding across various languages (Groovy, SpEL, XPath, JSONPath).
… target URLs

- Documented the change to URL encode expressions inside `${}` in target URLs.
- Updated tests to improve validation coverage and logging for clearer output.
- Introduced a `templateExpressionCache` in `Target` to avoid redundant parsing and compilation of frequently used expressions.
- Improved token parsing and evaluation logic in `TemplateExchangeExpression`, enhancing clarity and performance.
- Renamed test helper method `extracted` to `testExpression` for better readability.
- Updated test cases across multiple classes to cover new enhancements and ensure consistent behavior.
…simplify logic

- Eliminated `templateExpressionCache` to reduce complexity and improve maintainability.
- Updated `computeDestinationExpressions` to use `Collectors.toList()` for a mutable list.
- Simplified `evaluateTemplate` by removing cache-related logic and comments on minor performance differences.
…n `Target`

- Added `Escaping` enum with options `NONE`, `URL`, and `SEGMENT` to enhance placeholder escaping in URLs.
- Updated `Target` to include configurable escaping behavior and a helper method `getEscapingFunction()`.
- Extended test cases to validate new escaping options in various scenarios.
- Updated `URI` to leverage `var` for better readability and added JavaDoc for `resolve` method.
- Improved `ResolverMap` handling of URI schemes, including `classpath:` and `internal:`.
- Added new tests in `HTTPClientInterceptorTest` for complete path computation, including URL encoding.
…e template evaluation

- Added `UriIllegalCharacterDetector` for validating URI components with RFC 3986 compliance and optional extensions.
- Updated `Target` to skip template evaluation for URLs without placeholders and log warnings for insecure configurations.
- Enhanced `TemplateUtil.containsTemplateMarker` with null safety.
- Improved `RewriteInterceptor` to handle query parsing errors with more informative logging.
- Refactored tests and added new ones to validate changes.
- Refactored `removeLastSegment` method for concise logic using `Math.max()` to avoid redundant checks.
- Replaced `assertEquals(false, ...)` with `assertFalse(...)` for improved readability in tests.
- Cleaned up unused imports in `ResolverMapCombineTest`.
- Replaced `pathSeg` method with `pathEncode` for improved naming clarity and functionality in line with RFC 3986.
- Introduced `IPv6Util` for robust validation of IPv6 address text, ensuring only allowed characters are accepted.
- Refactored `Target` to include URL encoding strategy through a dedicated `escapingFunction` and removed redundant logic.
- Streamlined URI combination logic in `ResolverMap` with utility methods for handling slashes and file URIs.
- Added extensive tests covering URL path encoding, IPv6 address validation, and robustification of URI logic for edge cases.
… and utilities

- Adjusted visibility modifiers of constants to `final` for better immutability (`URITest`).
- Reordered equality assertion arguments for better readability (`TargetTest`).
- Replaced redundant comments with concise `<p/>` tags in JavaDocs for uniformity.
- Refactored tests to leverage `assertNull` for null comparisons (`FileUtilTest`).
- Removed unused method `stripIpv6BracketsIfNeeded` and redundant imports for cleaner code.
- Enhanced URI combination logic and streamlined utility imports (`DispatchingInterceptor`).
…comprehensive RFC 3986 compliance tests

- Added `URIFactory` to support flexible URI creation with options for illegal character handling and backslash escaping.
- Implemented extensive
… parsing

- Added edge case assertions for parsing IPv6 with empty ports.
- Introduced additional checks for IPv4 host and port parsing scenarios.
- Renamed test methods to reflect broader case coverage.
…Target` and `CallInterceptor`

- Replaced `evaluateExpressions` with `urlIsTemplate` for better semantics and clarity.
- Improved `Target` and `CallInterceptor` to skip URL evaluation when no template markers are present.
- Introduced stricter validation for configurations involving template markers and illegal characters.
- Updated relevant tests to validate changes and added new test cases for URL template evaluation.
…evaluation

- Introduced JSON escaping support for `setBody` based on `contentType`.
- Enhanced `ExchangeExpression` to centralize router retrieval logic.
- Updated tests to include validation logging for transformation scenarios.
- Fixed minor formatting inconsistencies and improved code readability.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

SetBodyInterceptor now constructs TemplateExchangeExpression via a new protected getExchangeExpression() that selects an escaping function from the request/response Content-Type (with fallback); EscapingUtil gains JSON/XML escaping and MIME lookup; ExchangeExpression centralizes nullable router resolution; tests add null-value cases and RestAssured failure logging.

Changes

Cohort / File(s) Summary
SetBodyInterceptor
core/src/main/java/com/predic8/membrane/core/interceptor/lang/SetBodyInterceptor.java
Added protected getExchangeExpression() to build TemplateExchangeExpression with language, expression, nullable router and content-type-based escaping; evaluation now accepts Object and converts to string when setting body; logs and falls back to NONE escaping if lookup fails.
EscapingUtil
core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java
Added JSON and XML escaping kinds and public static Optional<Function<String,String>> getEscapingFunction(String mimeType) to map MIME types to escaper functions (JSON -> CommonBuiltInFunctions::toJSON, XML -> StringEscapeUtils::escapeXml11).
ExchangeExpression
core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java
Introduced private getRouter(Interceptor) annotated @Nullable and updated static factory calls to use it for null-safe router resolution.
Tests & Distribution
core/src/test/java/.../SetBodyInterceptorTest.java, core/src/test/java/.../TemplateInterceptorTest.java, core/src/test/java/.../NormalizeXMLForJsonUtilTest.java, distribution/src/test/java/.../*.java
Added tests for null JSONPath/Groovy insertion and JSON escaping paths; added Apache-2.0 header to one test file; added .log().ifValidationFails() to tutorial RestAssured assertions; minor imports/formatting updates.

Sequence Diagram

sequenceDiagram
    participant SetBodyInterceptor as SetBodyInterceptor
    participant EscapingUtil as EscapingUtil
    participant CommonFuncs as CommonBuiltInFunctions
    participant StringEscaper as StringEscapeUtils
    participant ExchangeExpr as ExchangeExpression
    participant TemplateExpr as TemplateExchangeExpression

    SetBodyInterceptor->>EscapingUtil: getEscapingFunction(contentType)
    alt mime is JSON
        EscapingUtil->>CommonFuncs: resolve toJSON
        CommonFuncs-->>EscapingUtil: jsonEscaper(func)
    else mime is XML
        EscapingUtil->>StringEscaper: resolve escapeXml11
        StringEscaper-->>EscapingUtil: xmlEscaper(func)
    else no mapping
        EscapingUtil-->>SetBodyInterceptor: Optional.empty()
    end
    SetBodyInterceptor->>ExchangeExpr: getRouter(interceptor)
    ExchangeExpr-->>SetBodyInterceptor: router (nullable)
    SetBodyInterceptor->>TemplateExpr: create(expression, language, router, escapingFunc)
    TemplateExpr-->>SetBodyInterceptor: TemplateExchangeExpression instance
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • rrayst

Poem

🐇 I nibble bytes and plant a seed,
JSON blooms where nulls concede,
Routers found and templates spun,
Escapes applied till work is done,
Hop, test, commit — a patch well-bred.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Escaping For setBody' directly and concisely describes the main change: adding escaping functionality to the SetBodyInterceptor. It aligns with the core modifications across multiple files that introduce JSON/XML escaping support and escaping function resolution.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch compute-url-expression-at-http-client-interceptor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@membrane-ci-server
Copy link

This pull request needs "/ok-to-test" from an authorized committer.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java (1)

49-53: getEscapingFunction(String mimeType) only handles JSON — consider documenting the extension pattern.

Currently this method returns Optional.empty() for all non-JSON MIME types (including XML, HTML, etc.). This means setBody with contentType="application/xml" will fall back to NONE escaping, which could lead to injection of special XML characters. This is acceptable as a first step, but worth noting in the Javadoc that additional MIME types (e.g., XML) may need escaping support in the future.

🤖 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/uri/EscapingUtil.java`
around lines 49 - 53, Update the Javadoc for getEscapingFunction(String
mimeType) to explicitly state that it currently only returns an escaping
function for JSON (via the JSON constant) and returns Optional.empty() for all
other MIME types (so callers fall back to NONE), and note that additional MIME
types such as XML and HTML may require escaping in the future; also mention the
intended extension pattern (add isXml/isHtml predicates and corresponding
escaping functions and return them from getEscapingFunction) and reference the
getEscapingFunction method and the JSON/ NONE escaping constants so maintainers
know where to extend behavior.
🤖 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/lang/SetBodyInterceptor.java`:
- Around line 94-100: The warning in getExchangeExpression() is logged even when
contentType is null; change the behavior so the warn() call inside the
getEscapingFunction().orElseGet(...) is only executed when contentType is
non-null (i.e., log only if a user explicitly configured a contentType but no
escaping strategy exists). Update the
TemplateExchangeExpression.newInstance(...) call path in getExchangeExpression()
to check contentType != null before calling log.warn and otherwise return
getEscapingFunction(NONE) silently; reference getExchangeExpression(),
TemplateExchangeExpression.newInstance, getEscapingFunction(contentType),
contentType and NONE to locate the change.

---

Nitpick comments:
In `@core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java`:
- Around line 49-53: Update the Javadoc for getEscapingFunction(String mimeType)
to explicitly state that it currently only returns an escaping function for JSON
(via the JSON constant) and returns Optional.empty() for all other MIME types
(so callers fall back to NONE), and note that additional MIME types such as XML
and HTML may require escaping in the future; also mention the intended extension
pattern (add isXml/isHtml predicates and corresponding escaping functions and
return them from getEscapingFunction) and reference the getEscapingFunction
method and the JSON/ NONE escaping constants so maintainers know where to extend
behavior.

- Introduced XML escaping using `StringEscapeUtils::escapeXml11`.
- Updated `getEscapingFunction` to handle XML content type.
- Added `XML` escaping type to `Escaping` enum.
- Enhanced utility imports and updated dependencies for XML handling.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java (1)

36-52: Javadoc doesn't document the new JSON and XML enum members.

The Javadoc block at lines 36–45 describes only NONE, URL, and SEGMENT. Consider adding descriptions for JSON and XML to keep the documentation consistent.

📝 Suggested Javadoc addition
      * - {`@code` SEGMENT}: Encodes strings as safe URI path segments, ensuring they do not introduce
      *   path separators, query delimiters, or other unsafe characters, as per RFC 3986.
+     * - {`@code` JSON}: Escapes strings for safe inclusion in a JSON context.
+     * - {`@code` XML}: Escapes strings for safe inclusion in an XML context using XML 1.1 rules.
      */
🤖 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/uri/EscapingUtil.java`
around lines 36 - 52, The Javadoc for the Escaping enum currently documents
NONE, URL and SEGMENT but omits the new JSON and XML constants; update the
Javadoc comment for the Escaping enum to add brief descriptions for JSON (escape
strings for safe inclusion in JSON values, e.g., quote/backslash/control-char
escaping) and XML (escape strings for safe inclusion in XML content/attributes,
e.g., entity-encoding for <, >, &, quotes) so each enum member (Escaping.NONE,
Escaping.URL, Escaping.SEGMENT, Escaping.JSON, Escaping.XML) is documented
consistently.
🤖 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/util/uri/EscapingUtil.java`:
- Around line 69-70: EscapingUtil currently maps JSON ->
CommonBuiltInFunctions::toJSON which quotes string inputs and can produce
double-quoted JSON or a literal "null" when serialization fails; inspect
TemplateExchangeExpression usage in SetBodyInterceptor to determine whether
templates expect expr to produce a fully quoted JSON value (e.g., "field":
${expr}) or a raw unquoted string (e.g., "field": "${expr}"). If templates
expect raw escaped strings, change the JSON mapping to use
StringEscapeUtils::escapeJson (or implement an unquoting wrapper) instead of
toJSON; otherwise keep toJSON but modify CommonBuiltInFunctions.toJSON to (a)
avoid returning null on failure (throw or return a safe value) and (b) only call
objectMapper.writeValueAsString for non-String objects while for String inputs
either return the quoted form intentionally or provide an alternative API;
update EscapingUtil mapping accordingly and add tests that cover both string and
non-string inputs to TemplateExchangeExpression to prevent double-quoting.

---

Nitpick comments:
In `@core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java`:
- Around line 36-52: The Javadoc for the Escaping enum currently documents NONE,
URL and SEGMENT but omits the new JSON and XML constants; update the Javadoc
comment for the Escaping enum to add brief descriptions for JSON (escape strings
for safe inclusion in JSON values, e.g., quote/backslash/control-char escaping)
and XML (escape strings for safe inclusion in XML content/attributes, e.g.,
entity-encoding for <, >, &, quotes) so each enum member (Escaping.NONE,
Escaping.URL, Escaping.SEGMENT, Escaping.JSON, Escaping.XML) is documented
consistently.

@christiangoerdes
Copy link
Collaborator

/ok-to-test

christiangoerdes and others added 3 commits February 20, 2026 11:23
…InterceptorTest`

- Added tests to verify behavior for null values in JSONPath and Groovy expressions.
- Enhanced `SetBodyInterceptorTest` with additional scenarios for content escaping.
- Updated imports for improved code readability and consistency.
…lient-interceptor' into compute-url-expression-at-http-client-interceptor
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java (1)

56-63: Inconsistent spacing inside Optional.of(…) calls.

Both calls on lines 58 and 61 have a spurious space after the opening parenthesis: Optional.of( getEscapingFunction(...)). Standard Java style keeps these together.

📝 Proposed fix
-        if (isJson(mimeType)) {
-            return Optional.of( getEscapingFunction(JSON));
-        }
-        if (isXML(mimeType)) {
-            return Optional.of( getEscapingFunction(XML));
-        }
+        if (isJson(mimeType)) {
+            return Optional.of(getEscapingFunction(JSON));
+        }
+        if (isXML(mimeType)) {
+            return Optional.of(getEscapingFunction(XML));
+        }
🤖 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/uri/EscapingUtil.java`
around lines 56 - 63, The Optional.of calls in getEscapingFunction(String
mimeType) have inconsistent spacing (e.g., Optional.of(
getEscapingFunction(...))). In the getEscapingFunction method, remove the
spurious space after the opening parenthesis so both calls are formatted as
Optional.of(getEscapingFunction(JSON)) and
Optional.of(getEscapingFunction(XML)); keep other logic (isJson, isXML)
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/util/uri/EscapingUtil.java`:
- Around line 40-47: The Javadoc for EscapingUtil has the URL bullet broken by
misplaced JSON and XML bullet points; edit the comment in EscapingUtil (the
enum/constant descriptions for NONE, URL, JSON, XML, SEGMENT) so that the URL
entry is a contiguous sentence: move the {`@code` JSON} and {`@code` XML} bullet
lines out of the middle of the URL description and place them after the {`@code`
SEGMENT} entry, ensuring the URL description continues "replacing spaces and
other special characters with their percent-encoded counterparts (e.g., SPACE ->
+)." and that the {`@code` JSON} and {`@code` XML} bullets follow the {`@code`
SEGMENT} bullet.

In
`@core/src/test/java/com/predic8/membrane/core/interceptor/lang/SetBodyInterceptorTest.java`:
- Around line 65-95: The two tests escapeNull and escapeNulGroovy mix
differences in expression languages with escaping behavior; fix by making their
intent explicit and independent: for escapeNull (method escapeNull) either set
sbi.setContentType(APPLICATION_JSON_UTF8) so it actually exercises JSON escaping
path in SetBodyInterceptor (and then update the assertion to the correct
JSON-escaped value), or rename the test to something like
nullWithNoContentTypeBecomesEmptyAndBreaksJson and update the comment to
document this is a deliberate regression anchor; for escapeNulGroovy, remove the
hedging comment, decide and assert the intended canonical behavior (update the
assertion to the confirmed correct JSON representation for a null value when
using GROOVY and APPLICATION_JSON_UTF8), and ensure both tests call
sbi.init(...) and sbi.handleRequest(exc) as they already do so the only
differences are language and sbi.setContentType(...) to isolate the escaping
pipeline from the expression language.
- Line 83: Rename the test method escapeNulGroovy in class
SetBodyInterceptorTest to escapeNullGroovy (fixing the missing "l"); update the
method declaration and any references or annotations (e.g., `@Test` usage or
calls) to the new name so the test runner and any reflective lookups continue to
work; ensure imports/compilation remain intact after the rename.

---

Duplicate comments:
In `@core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java`:
- Line 71: The JSON escaper mapping in EscapingUtil currently uses
CommonBuiltInFunctions::toJSON which serialises values (adding surrounding
quotes for plain strings) causing double-quoting in templates; change the JSON
mapping to use StringEscapeUtils.escapeJson (or an equivalent non-serialising
JSON-string-escaping function) instead of CommonBuiltInFunctions::toJSON, update
the inline comment to reflect the chosen approach, and add/adjust unit tests or
template examples to assert that plain string inputs are escaped but not wrapped
in extra quotes; reference CommonBuiltInFunctions::toJSON,
StringEscapeUtils.escapeJson and the JSON case in EscapingUtil when making the
change.

---

Nitpick comments:
In `@core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java`:
- Around line 56-63: The Optional.of calls in getEscapingFunction(String
mimeType) have inconsistent spacing (e.g., Optional.of(
getEscapingFunction(...))). In the getEscapingFunction method, remove the
spurious space after the opening parenthesis so both calls are formatted as
Optional.of(getEscapingFunction(JSON)) and
Optional.of(getEscapingFunction(XML)); keep other logic (isJson, isXML)
unchanged.

… in `SetBodyInterceptorTest`

- Refactored tests to consolidate null value handling for JSONPath and Groovy.
- Enhanced `SetBodyInterceptor` to handle `Object` evaluation results, ensuring compatibility and proper type handling.
- Updated helper methods to restructure and reuse test setup across scenarios.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java (1)

43-54: Align enum member order with the Javadoc bullet order.

The Javadoc lists NONE → URL → JSON → XML → SEGMENT, but the enum declares NONE → URL → SEGMENT → JSON → XML. No behavioral impact since ordinal() is never used, but the mismatch makes the doc harder to cross-reference.

♻️ Proposed fix
     public enum Escaping {
         NONE,
         URL,
+        JSON,
+        XML,
         SEGMENT,
-        JSON,
-        XML
     }
🤖 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/uri/EscapingUtil.java`
around lines 43 - 54, The enum declaration order in EscapingUtil.Escaping does
not match the Javadoc bullet order; update the Escaping enum so its members
appear in the same sequence as the Javadoc (NONE, URL, JSON, XML, SEGMENT) by
reordering the constants in the Escaping enum declaration in EscapingUtil.java
to match the documentation.
core/src/test/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptorTest.java (1)

276-280: setJsonSample() is duplicated verbatim in SetBodyInterceptorTest.Null and TemplateInterceptorTest.Null.

Consider extracting it to a shared test-fixture utility (e.g. TestExchanges.jsonBodyWithNullField()) to avoid having two copies drift independently.

🤖 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/templating/TemplateInterceptorTest.java`
around lines 276 - 280, The method setJsonSample() duplicated in
TemplateInterceptorTest.Null and SetBodyInterceptorTest.Null should be extracted
to a shared test fixture to avoid drift: create a utility class (e.g.
TestExchanges) with a method jsonBodyWithNullField() that returns the same
Exchange currently built by setJsonSample() and update both
TemplateInterceptorTest and SetBodyInterceptorTest to call
TestExchanges.jsonBodyWithNullField() instead of their local setJsonSample()
implementations; ensure the new utility references the same builder chain
(post("/foo").json("{\"a\":null}").buildExchange()) and update imports/tests
accordingly.
core/src/main/java/com/predic8/membrane/core/interceptor/lang/SetBodyInterceptor.java (1)

72-77: result.toString() will produce broken JSON/XML for structured expression results.

The comment // Hope that all possibles return types are covered (note: "possibles" typo) acknowledges this branch is under-specified. If a Groovy expression returns a Map or List, toString() produces JVM output like {a=1, b=2}, not valid JSON. Given that contentType can be application/json, this path can silently corrupt the body. Consider using Jackson serialization or at minimum documenting that the caller is responsible for ensuring the expression returns a String.

🤖 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/lang/SetBodyInterceptor.java`
around lines 72 - 77, The branch in SetBodyInterceptor that falls back to
result.toString() corrupts structured results (Map/List) for JSON/XML content
types; change it so that when result is not a String you detect the message
content type (e.g., application/json or application/xml) and serialize
structured objects properly (use a shared Jackson ObjectMapper to
writeValueAsBytes(result) for JSON, or an appropriate XML serializer for XML),
and only use result.toString().getBytes(UTF_8) as a last resort (or document
caller responsibility); update the code paths around the local variable result
and msg.setBodyContent(...) accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/lang/SetBodyInterceptor.java`:
- Around line 97-103: The warning in SetBodyInterceptor.getExchangeExpression
fires for null contentType because getEscapingFunction(contentType) returns
Optional.empty(); change the logic to only log when a non-null contentType is
provided but unrecognized: call getEscapingFunction(contentType) into a
variable, if contentType != null and the Optional is empty then log.warn
mentioning contentType, then pass the Optional.orElseGet(() ->
getEscapingFunction(NONE).get()) (or equivalent) into
TemplateExchangeExpression.newInstance; refer to
SetBodyInterceptor.getExchangeExpression, getEscapingFunction, contentType, NONE
and TemplateExchangeExpression.newInstance to locate and update the code.

In `@core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java`:
- Around line 71-72: The JSON branch in EscapingUtil currently references
CommonBuiltInFunctions::toJSON which uses objectMapper.writeValueAsString and
therefore wraps string inputs (e.g., the literal "null") in quotes; switch the
JSON escaping to avoid quoting string values by either (a) using
StringEscapeUtils::escapeJson for string inputs and keeping
CommonBuiltInFunctions::toJSON for non-strings, or (b) replace the JSON mapper
with a function that detects an input of type String and returns an unquoted
escaped value (and only uses objectMapper for real objects), so that
EscapingUtil (the JSON case) preserves the literal "null" expected by
SetBodyInterceptorTest.Null and TemplateInterceptorTest.Null.

---

Nitpick comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/lang/SetBodyInterceptor.java`:
- Around line 72-77: The branch in SetBodyInterceptor that falls back to
result.toString() corrupts structured results (Map/List) for JSON/XML content
types; change it so that when result is not a String you detect the message
content type (e.g., application/json or application/xml) and serialize
structured objects properly (use a shared Jackson ObjectMapper to
writeValueAsBytes(result) for JSON, or an appropriate XML serializer for XML),
and only use result.toString().getBytes(UTF_8) as a last resort (or document
caller responsibility); update the code paths around the local variable result
and msg.setBodyContent(...) accordingly.

In `@core/src/main/java/com/predic8/membrane/core/util/uri/EscapingUtil.java`:
- Around line 43-54: The enum declaration order in EscapingUtil.Escaping does
not match the Javadoc bullet order; update the Escaping enum so its members
appear in the same sequence as the Javadoc (NONE, URL, JSON, XML, SEGMENT) by
reordering the constants in the Escaping enum declaration in EscapingUtil.java
to match the documentation.

In
`@core/src/test/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptorTest.java`:
- Around line 276-280: The method setJsonSample() duplicated in
TemplateInterceptorTest.Null and SetBodyInterceptorTest.Null should be extracted
to a shared test fixture to avoid drift: create a utility class (e.g.
TestExchanges) with a method jsonBodyWithNullField() that returns the same
Exchange currently built by setJsonSample() and update both
TemplateInterceptorTest and SetBodyInterceptorTest to call
TestExchanges.jsonBodyWithNullField() instead of their local setJsonSample()
implementations; ensure the new utility references the same builder chain
(post("/foo").json("{\"a\":null}").buildExchange()) and update imports/tests
accordingly.

rrayst
rrayst previously approved these changes Feb 20, 2026
- Added `.log().ifValidationFails()` to improve debugging of failing test scenarios.
@predic8 predic8 requested a review from rrayst February 20, 2026 12:43
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.

3 participants