Skip to content

YAML Tutorial#2285

Merged
predic8 merged 20 commits into
masterfrom
yaml-tutorial
Nov 11, 2025
Merged

YAML Tutorial#2285
predic8 merged 20 commits into
masterfrom
yaml-tutorial

Conversation

@predic8
Copy link
Copy Markdown
Member

@predic8 predic8 commented Nov 9, 2025

Summary by CodeRabbit

  • New Features

    • Expanded Getting Started and Advanced tutorials (many new YAML examples), plus helper CLI scripts for tutorials.
    • Template/scripting enhancements: method and path exposed to scripts/templates; richer schema/annotation model with enum support and new schema factories.
  • Bug Fixes

    • Improved templating error reporting for missing properties/methods.
    • More predictable boolean conversion in conditionals.
    • Clearer messages for invalid enum values.
  • Documentation

    • Updated tutorials, READMEs and roadmap.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 9, 2025

Walkthrough

Adds explicit TemplateExecutionException propagation and handling in templating, extends scripting bindings with request method/path, refactors Kubernetes schema models to use generic AbstractSchema with enum support, enhances YAML enum validation, adjusts logging/error paths, and adds many tutorial configs and startup scripts.

Changes

Cohort / File(s) Summary
Templating & Scripting
core/src/main/java/com/predic8/membrane/core/interceptor/templating/AbstractTemplateInterceptor.java, core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java, core/src/main/java/com/predic8/membrane/core/lang/ScriptingUtils.java
process(...) now declares throws TemplateExecutionException; TemplateInterceptor gains dedicated TemplateExecutionException handling (builds ProblemDetails, inspects root causes MissingPropertyException / MissingMethodException and ABORTs); ScriptingUtils adds method and path bindings when a request exists.
Kubernetes schema model & factories
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/AbstractSchema.java, .../BasicSchema.java, .../SchemaArray.java, .../SchemaObject.java, .../SchemaString.java, .../SchemaFactory.java
Adds enumValues (getter + fluent setter) to AbstractSchema; introduces BasicSchema; SchemaArray/SchemaObject updated to use AbstractSchema<?> generics; SchemaObject adds additionalProperties(boolean) and enum-aware JSON serialization; SchemaString now extends BasicSchema; SchemaFactory gains helpers (basic, from, array).
Json / K8s schema generators
annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java, annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/K8sJsonSchemaGenerator.java
Replaced inline concrete SchemaObject construction with factory/generic usage (SchemaFactory.from()), added helper createProperty(...), migrated to AbstractSchema<?> wildcard generics, and propagated enum metadata into generated schemas.
Annotation model: Attribute & Element
annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java, annot/src/main/java/com/predic8/membrane/annot/model/ElementInfo.java
AttributeInfo: adds enum detection and enumValues extraction, new getters for enum lists, richer type analysis mapping XSD types and enum-like booleans; ElementInfo: minor API/behavioral cleanups (final fields, getMain/getXSDTypeName/getId/equality tweaks).
YAML parsing & enum validation
core/src/main/java/com/predic8/membrane/core/kubernetes/GenericYamlParser.java, core/src/main/java/com/predic8/membrane/core/kubernetes/WrongEnumConstantException.java
GenericYamlParser: enum handling now uppercases/normalizes and may throw WrongEnumConstantException for invalid constants; introduces getAClass(...) helper and list parsing refinements. Adds new WrongEnumConstantException with formatted message and valid options.
BeanCache & OpenAPI refactors
core/src/main/java/com/predic8/membrane/core/kubernetes/BeanCache.java, core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java, core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java, core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java
BeanCache: handles ConfigurationException explicitly, delegates root-cause handling, and adjusts logger usage; OpenAPIPublisherInterceptor: constructor Javadoc and log-level tweak; OpenAPIRecordFactory: per-file parsing refactor and private helpers now declare IOException; OpenAPISpec: minor enum formatting fix.
Rewrite interceptor parsing refactor
core/src/main/java/com/predic8/membrane/core/interceptor/rewrite/RewriteInterceptor.java
Extracted parseDo(String) helper to centralize mapping of do_ values (uses US locale lower-casing, explicit mappings, IllegalArgumentException for unknowns).
SpEL boolean logic & tests
core/src/main/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpression.java, core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java, core/src/test/java/com/predic8/membrane/core/interceptor/flow/IfInterceptorSpELTest.java
toBoolean() visibility widened and parsing adjusted (empty/"false"/"no"/"0" => false; other non-null strings => true); added unit test for conversions; minor test renaming and throws removal.
Tutorials, docs & scripts
distribution/tutorials/**/*, distribution/tutorials/getting-started/{membrane.sh,membrane.cmd}, distribution/tutorials/getting-started/data/{order.json,person.json}, docs/ROADMAP.md
Adds many tutorial YAMLs (getting-started, advanced, json), README updates, sample JSON data, and shell/batch startup scripts that locate MEMBRANE_HOME by traversing parent directories; docs updated to note ScriptingUtils binding behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant TemplateInterceptor
    participant AbstractTemplateInterceptor
    participant TemplatingEngine

    Client->>TemplateInterceptor: request -> handleInternal(exchange, flow)
    TemplateInterceptor->>AbstractTemplateInterceptor: delegate handling
    AbstractTemplateInterceptor->>TemplatingEngine: process(exchange, flow)
    alt TemplateExecutionException thrown
        TemplatingEngine-->>TemplateInterceptor: TemplateExecutionException (with root cause)
        TemplateInterceptor->>TemplateInterceptor: inspect root cause
        alt MissingPropertyException
            TemplateInterceptor-->>Client: ABORT + ProblemDetails (property)
        else MissingMethodException
            TemplateInterceptor-->>Client: ABORT + ProblemDetails (method)
        else other
            TemplateInterceptor-->>Client: ABORT + ProblemDetails (exception attached)
        end
    else other Exception
        TemplatingEngine-->>TemplateInterceptor: Exception
        TemplateInterceptor-->>Client: ABORT (generic)
    end
Loading
sequenceDiagram
    participant Script
    participant ScriptingUtils
    participant BindingContext

    Script->>ScriptingUtils: setupBindings(exchange, flow)
    ScriptingUtils->>BindingContext: put "exc"/"exchange", "flow"
    alt exchange.request != null
        ScriptingUtils->>BindingContext: put "method" (request.method)
        ScriptingUtils->>BindingContext: put "path" (request.uri)
    end
    BindingContext-->>Script: bindings ready
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus review on:

  • Schema model/generator generic migration and enum propagation.
  • AttributeInfo analyze() correctness for enums and enum-like booleans.
  • GenericYamlParser enum normalization and WrongEnumConstantException usage.
  • TemplateInterceptor TemplateExecutionException handling paths and ProblemDetails construction.
  • BeanCache error-handling changes that can affect lifecycle/termination.

Possibly related PRs

Suggested reviewers

  • rrayst
  • t-burch

Poem

🐇 I hopped through code with nimble paws,

Templates report their little flaws.
Enums now speak with clearer names,
Scripts know paths and startup games.
Tutorials bloom — a rabbit applauds. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.03% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'YAML Tutorial' is vague and does not clearly convey the specific changes made. While tutorials are added, the title lacks specificity about the scope or nature of the changes. Consider a more descriptive title that summarizes the primary change, such as 'Add YAML tutorial files for getting started and advanced topics' or 'Add comprehensive tutorial configuration examples'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch yaml-tutorial

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
Copy Markdown

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

Copy link
Copy Markdown
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: 5

🧹 Nitpick comments (2)
distribution/tutorials/getting-started/data/person.json (1)

2-3: Use camelCase for property names to follow JSON conventions.

The property names "firstname" and "lastname" use all lowercase, which deviates from standard JSON naming conventions. Consider using "firstName" and "lastName" instead for consistency with typical JavaScript/JSON practices.

Apply this diff to fix the property names:

 {
-  "firstname": "Olivia",
-  "lastname": "Garcia",
+  "firstName": "Olivia",
+  "lastName": "Garcia",
   "address":{
     "street": "Main Street 217",
     "city": "Boston"
   }
 }
distribution/tutorials/getting-started/40-Template.yaml (1)

1-21: Potential duplication with 50-Jsonpath.yaml.

This file and 50-Jsonpath.yaml appear to demonstrate nearly identical functionality—both render plain text templates with method, path, and date on port 2000. Consider either:

  1. Making them demonstrate different aspects of templating (e.g., one for plain text, another for different template features)
  2. Removing the duplicate if both serve the same purpose
  3. If 50-Jsonpath.yaml is meant to demonstrate JSONPath, update its content accordingly
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d676ec7 and f3ebeb3.

📒 Files selected for processing (15)
  • core/src/main/java/com/predic8/membrane/core/interceptor/templating/AbstractTemplateInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/ScriptingUtils.java (1 hunks)
  • distribution/tutorials/getting-started/00-First-API.yaml (1 hunks)
  • distribution/tutorials/getting-started/05-Logging.yaml (1 hunks)
  • distribution/tutorials/getting-started/07-Message-Flow.yaml (1 hunks)
  • distribution/tutorials/getting-started/10-Basic-Path-Routing.yaml (1 hunks)
  • distribution/tutorials/getting-started/20-Short-Circuit.yaml (1 hunks)
  • distribution/tutorials/getting-started/30-SetHeader.yaml (1 hunks)
  • distribution/tutorials/getting-started/40-Template.yaml (1 hunks)
  • distribution/tutorials/getting-started/50-Jsonpath.yaml (1 hunks)
  • distribution/tutorials/getting-started/60-Json-Template.yaml (1 hunks)
  • distribution/tutorials/getting-started/README.md (1 hunks)
  • distribution/tutorials/getting-started/data/order.json (1 hunks)
  • distribution/tutorials/getting-started/data/person.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java (1)
core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (1)
  • ExceptionUtil (16-39)
🪛 LanguageTool
distribution/tutorials/getting-started/README.md

[locale-violation] ~7-~7: In American English, “take a look” is more commonly used.
Context: ... # Basic # To get a basic understanding have a look at the following tutorials: # # Advance...

(HAVE_A_LOOK)


[grammar] ~14-~14: Ensure spelling is correct
Context: ... tutorials: # # Advanced: # # - Header - Espression Language SPEL - Properties - Templating...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~20-~20: Ensure spelling is correct
Context: ...- JSONPath - Advanced Routing - Routing Rewritting - Routing Redirect - CORS XML Tutorial S...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
distribution/tutorials/getting-started/README.md

3-3: Multiple headings with the same content

(MD024, no-duplicate-heading)


4-4: Multiple headings with the same content

(MD024, no-duplicate-heading)


5-5: Multiple headings with the same content

(MD024, no-duplicate-heading)


8-8: Multiple headings with the same content

(MD024, no-duplicate-heading)


10-10: Multiple headings with the same content

(MD024, no-duplicate-heading)


11-11: Multiple headings with the same content

(MD024, no-duplicate-heading)


34-34: Bare URL used

(MD034, no-bare-urls)


36-36: Bare URL used

(MD034, no-bare-urls)


38-38: Bare URL used

(MD034, no-bare-urls)


40-40: Bare URL used

(MD034, no-bare-urls)


42-42: Bare URL used

(MD034, no-bare-urls)


44-44: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (5)
distribution/tutorials/getting-started/data/order.json (1)

1-20: LGTM!

The JSON structure is well-formed with clear data for tutorial purposes.

core/src/main/java/com/predic8/membrane/core/lang/ScriptingUtils.java (1)

56-57: LGTM!

The new "method" and "path" bindings provide useful context for template-based responses and follow the existing binding pattern.

distribution/tutorials/getting-started/30-SetHeader.yaml (1)

1-20: LGTM!

The YAML configuration correctly demonstrates header manipulation with both static and dynamic values using the new ${method} binding.

distribution/tutorials/getting-started/20-Short-Circuit.yaml (1)

1-21: LGTM!

The configuration clearly demonstrates the short-circuit pattern with appropriate status code (503) and maintenance message.

distribution/tutorials/getting-started/07-Message-Flow.yaml (1)

1-61: Well-structured tutorial demonstrating message flow and script bindings.

This tutorial effectively demonstrates:

  • Multi-document YAML configuration with request and response flow separation
  • Template variable bindings (${path}, ${statusCode}) that integrate with the scripting context enhancements
  • Clear documentation and usage instructions for users

The configuration is properly formatted and provides an excellent complement to the other tutorials.

Comment thread distribution/tutorials/getting-started/00-First-API.yaml Outdated
Comment thread distribution/tutorials/getting-started/50-Jsonpath.yaml Outdated
Comment thread distribution/tutorials/getting-started/60-Json-Template.yaml Outdated
Comment thread distribution/tutorials/getting-started/README.md Outdated
Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (2)
distribution/tutorials/getting-started/README.md (2)

34-44: Wrap bare URLs in Markdown link syntax.

Bare URLs should be formatted as Markdown links for better presentation and accessibility:

-https://api.ipify.org/?format=json
+[https://api.ipify.org/?format=json](https://api.ipify.org/?format=json)

-https://dummyjson.com/quotes
+[https://dummyjson.com/quotes](https://dummyjson.com/quotes)

-https://api.agify.io/?name=thomas
+[https://api.agify.io/?name=thomas](https://api.agify.io/?name=thomas)

-https://httpbin.org/status/500
+[https://httpbin.org/status/500](https://httpbin.org/status/500)

-https://httpbin.org/delay/5
+[https://httpbin.org/delay/5](https://httpbin.org/delay/5)

-https://httpbin.org/xml
+[https://httpbin.org/xml](https://httpbin.org/xml)

7-7: Minor phrasing improvement for American English.

Change "have a look" to "take a look" for more natural American English phrasing:

-# To get a basic understanding have a look at the following tutorials:
+# To get a basic understanding take a look at the following tutorials:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3ebeb3 and 8eb4ccc.

📒 Files selected for processing (4)
  • distribution/tutorials/getting-started/00-First-API.yaml (1 hunks)
  • distribution/tutorials/getting-started/60-Json-Template.yaml (1 hunks)
  • distribution/tutorials/getting-started/README.md (1 hunks)
  • distribution/tutorials/getting-started/data/person.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • distribution/tutorials/getting-started/00-First-API.yaml
🧰 Additional context used
🪛 LanguageTool
distribution/tutorials/getting-started/README.md

[locale-violation] ~7-~7: In American English, “take a look” is more commonly used.
Context: ... # Basic # To get a basic understanding have a look at the following tutorials: # # Advance...

(HAVE_A_LOOK)

🪛 markdownlint-cli2 (0.18.1)
distribution/tutorials/getting-started/README.md

3-3: Multiple headings with the same content

(MD024, no-duplicate-heading)


4-4: Multiple headings with the same content

(MD024, no-duplicate-heading)


5-5: Multiple headings with the same content

(MD024, no-duplicate-heading)


8-8: Multiple headings with the same content

(MD024, no-duplicate-heading)


10-10: Multiple headings with the same content

(MD024, no-duplicate-heading)


11-11: Multiple headings with the same content

(MD024, no-duplicate-heading)


34-34: Bare URL used

(MD034, no-bare-urls)


36-36: Bare URL used

(MD034, no-bare-urls)


38-38: Bare URL used

(MD034, no-bare-urls)


40-40: Bare URL used

(MD034, no-bare-urls)


42-42: Bare URL used

(MD034, no-bare-urls)


44-44: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (1)
distribution/tutorials/getting-started/data/person.json (1)

1-8: LGTM!

Valid JSON data file with appropriate example data for the templating tutorials.

Comment thread distribution/tutorials/json/60-Json-Template.yaml
Comment thread distribution/tutorials/getting-started/README.md Outdated
Copy link
Copy Markdown
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: 8

Caution

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

⚠️ Outside diff range comments (1)
annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1)

89-108: Missing FLOAT handling regresses existing setters.

The new switch omits TypeKind.FLOAT, so any setter with a float parameter now falls into the default branch and triggers the “Not implemented” ProcessingException. We already map "xsd:float" in getSchemaType, so please restore explicit handling for FLOAT (mirroring the previous behavior) to avoid breaking annotation processing on float attributes.

Suggested fix:

-        switch (ve.asType().getKind()) {
-            case INT, LONG:
+        switch (ve.asType().getKind()) {
+            case INT, LONG:
             xsdType = "spel_number";
             return;
         case DOUBLE:
             xsdType = "xsd:double";
             return;
+        case FLOAT:
+            xsdType = "xsd:float";
+            return;
🧹 Nitpick comments (4)
distribution/tutorials/getting-started/README.md (2)

24-26: Convert unformatted section titles to Markdown headings.

Lines 24 and 26 ("XML Tutorial" and "SOAP Tutorial") should use proper Markdown heading syntax for consistency with the rest of the document.

-XML Tutorial
+## XML Tutorial
-SOAP Tutorial
+## SOAP Tutorial

34-44: Wrap bare URLs in Markdown link syntax.

Lines 34, 36, 38, 40, 42, and 44 contain bare URLs. Per Markdown best practices (MD034), these should be wrapped in Markdown link syntax for proper formatting and accessibility.

-https://api.ipify.org/?format=json
+- [https://api.ipify.org/?format=json](https://api.ipify.org/?format=json)
-https://dummyjson.com/quotes
+- [https://dummyjson.com/quotes](https://dummyjson.com/quotes)
-https://api.agify.io/?name=thomas
+- [https://api.agify.io/?name=thomas](https://api.agify.io/?name=thomas)
-https://httpbin.org/status/500
+- [https://httpbin.org/status/500](https://httpbin.org/status/500)
-https://httpbin.org/delay/5
+- [https://httpbin.org/delay/5](https://httpbin.org/delay/5)
-https://httpbin.org/xml
+- [https://httpbin.org/xml](https://httpbin.org/xml)
core/src/main/java/com/predic8/membrane/core/interceptor/rewrite/RewriteInterceptor.java (2)

71-82: Consider documenting the "redirect" alias.

The method accepts "redirect" as an alias for "redirect-temporary" (line 78), but this is not documented in the JavaDoc for setDo() at lines 126-130. If this alias is intentional for backward compatibility or convenience, please update the documentation to reflect this accepted value.

Apply this diff to update the documentation:

         /**
          * @description What to do: "rewrite", "redirect-temporary" or "redirect-permanent".
+         * Note: "redirect" is accepted as an alias for "redirect-temporary".
          * @default rewrite (default) or redirect (if "to" contains "://")
          * @example redirect-temporary
          */

80-80: Consider using original parameter value in error message.

The error message uses what (the lowercased version) instead of the original do_ parameter. Using the original value would provide clearer feedback to users about what they actually provided.

Apply this diff:

-                default -> throw new IllegalArgumentException("Unknown value '%s' for rewriter/@do.".formatted(what));
+                default -> throw new IllegalArgumentException("Unknown value '%s' for rewriter/@do.".formatted(do_));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb4ccc and 4e778d9.

📒 Files selected for processing (25)
  • annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (8 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/K8sJsonSchemaGenerator.java (1 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/AbstractSchema.java (3 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/BasicSchema.java (1 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaArray.java (2 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaFactory.java (1 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaObject.java (2 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaString.java (1 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (6 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/model/ElementInfo.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/rewrite/RewriteInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/kubernetes/GenericYamlParser.java (6 hunks)
  • core/src/main/java/com/predic8/membrane/core/kubernetes/WrongEnumConstantException.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/ScriptingUtils.java (1 hunks)
  • distribution/tutorials/advanced/30-PathParameters.yaml (1 hunks)
  • distribution/tutorials/advanced/40-Path-Parameter-Routing.yaml (1 hunks)
  • distribution/tutorials/advanced/50-Path-Rewriting.yaml (1 hunks)
  • distribution/tutorials/advanced/60-Redirects.yaml (1 hunks)
  • distribution/tutorials/advanced/README.md (1 hunks)
  • distribution/tutorials/getting-started/07-Message-Flow.yaml (1 hunks)
  • distribution/tutorials/getting-started/08-Message-Flow2.yaml (1 hunks)
  • distribution/tutorials/getting-started/60-Json-Template.yaml (1 hunks)
  • distribution/tutorials/getting-started/80-OpenAPI.yaml (1 hunks)
  • distribution/tutorials/getting-started/README.md (1 hunks)
  • docs/ROADMAP.md (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • distribution/tutorials/advanced/README.md
  • distribution/tutorials/advanced/60-Redirects.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/tutorials/getting-started/07-Message-Flow.yaml
  • distribution/tutorials/getting-started/60-Json-Template.yaml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-19T11:12:26.787Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2156
File: core/src/main/java/com/predic8/membrane/core/openapi/validators/QueryParameterValidator.java:129-131
Timestamp: 2025-09-19T11:12:26.787Z
Learning: Request.get().path() in com.predic8.membrane.core.openapi.model.Request preserves the query string portion of the path, so URIFactory.createWithoutException(request.getPath()).getQuery() correctly extracts query parameters.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/lang/ScriptingUtils.java
📚 Learning: 2025-10-23T13:04:11.388Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2240
File: annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java:210-215
Timestamp: 2025-10-23T13:04:11.388Z
Learning: In JsonSchemaGenerator.java, when allowForeign is true for non-list child elements, use a property named "ref" (not "$ref") with type "string" to provide IDE completion hints for Spring bean references while avoiding JSON Schema keyword collision.

Applied to files:

  • annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/K8sJsonSchemaGenerator.java
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaObject.java
🧬 Code graph analysis (3)
annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (1)
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaFactory.java (1)
  • SchemaFactory (5-60)
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/K8sJsonSchemaGenerator.java (1)
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaFactory.java (1)
  • SchemaFactory (5-60)
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaObject.java (1)
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaFactory.java (1)
  • SchemaFactory (5-60)
🪛 markdownlint-cli2 (0.18.1)
distribution/tutorials/getting-started/README.md

3-3: Multiple headings with the same content

(MD024, no-duplicate-heading)


4-4: Multiple headings with the same content

(MD024, no-duplicate-heading)


5-5: Multiple headings with the same content

(MD024, no-duplicate-heading)


8-8: Multiple headings with the same content

(MD024, no-duplicate-heading)


10-10: Multiple headings with the same content

(MD024, no-duplicate-heading)


11-11: Multiple headings with the same content

(MD024, no-duplicate-heading)


34-34: Bare URL used

(MD034, no-bare-urls)


36-36: Bare URL used

(MD034, no-bare-urls)


38-38: Bare URL used

(MD034, no-bare-urls)


40-40: Bare URL used

(MD034, no-bare-urls)


42-42: Bare URL used

(MD034, no-bare-urls)


44-44: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (18)
distribution/tutorials/getting-started/08-Message-Flow2.yaml (3)

1-1: Verify schema path for IDE validation outside build process.

The schema reference path includes target/classes/, which is a generated directory typically not committed to the repository. This may prevent YAML language servers from validating the file correctly outside the build environment.

Can you verify that this schema path works for IDE validation and, if not, confirm whether there's an alternative schema reference (like a distribution artifact or published schema) that should be used for tutorial files?


35-40: Clarify response flow execution order in comments.

The comment states the response flow is "executed...from bottom to top", but the YAML entries are listed in order (6, 5, 4). Confirm whether the actual execution reverses the YAML order or if the comment should clarify that the response phase itself occurs bottom-up in the gateway's request/response lifecycle (while YAML order remains top-to-bottom).


28-43: YAML structure and syntax look good.

The tutorial is well-structured with clear comments, proper variable interpolation (${path}, ${statusCode}), and good pedagogical flow comparing two message-flow implementations.

distribution/tutorials/getting-started/80-OpenAPI.yaml (1)

16-16: Address the TODO comment.

The TODO marker on the location field suggests the configuration may not be finalized. Verify that the path ../../distribution/conf/fruitshop-api.yml is correct and then remove the TODO comment.

distribution/tutorials/getting-started/README.md (1)

1-12: Fix malformed Markdown heading structure.

Lines 3–5 and 8, 10–11 contain empty or duplicate heading markers, violating Markdown best practices. The heading hierarchy should be consolidated with distinct content for each heading, as flagged in previous reviews.

Consider restructuring as follows:

-# 
-# Membrane API Gateway Tutorials
-#
-#
-#
-# Basic
-# To get a basic understanding take a look at the following tutorials:
-#
-# Advanced:
-#
-#
+# Membrane API Gateway Tutorials
+
+## Basic
+
+To get a basic understanding take a look at the following tutorials:
+
+## Advanced
core/src/main/java/com/predic8/membrane/core/interceptor/rewrite/RewriteInterceptor.java (2)

34-34: LGTM: Proper locale-aware import.

The static import of Locale.US is appropriate for the case-insensitive string comparison in parseDo, ensuring consistent behavior across different system locales.


67-67: LGTM: Clean refactoring.

Delegating to parseDo(do_) improves code organization by extracting the parsing logic into a dedicated helper method.

docs/ROADMAP.md (1)

33-35: LGTM! Clear documentation of breaking change.

The documentation clearly describes the breaking change in ScriptingUtils variable bindings for Groovy scripting. The note about the difference from SpEL is helpful for users migrating or comparing the two approaches.

distribution/tutorials/advanced/30-PathParameters.yaml (1)

1-18: LGTM! Well-structured path parameters tutorial.

The tutorial clearly demonstrates path parameter extraction and usage. The example includes:

  • Clear path template with named parameters
  • Template interpolation showing how to access the parameters
  • Helpful curl command for testing
distribution/tutorials/advanced/40-Path-Parameter-Routing.yaml (1)

8-16: Good demonstration of dynamic routing with path parameters.

The tutorial effectively shows how to use path parameters in both logging and target URL construction, demonstrating a common routing pattern.

distribution/tutorials/advanced/50-Path-Rewriting.yaml (1)

8-21: Nice demonstration of path rewriting with before/after logging.

The tutorial effectively shows the path transformation by logging both the original and rewritten paths, making it easy to understand the rewriting behavior.

core/src/main/java/com/predic8/membrane/core/lang/ScriptingUtils.java (1)

57-61: Good addition of method and path bindings with appropriate null safety.

The null check is sensible given test scenarios. The implementation enables the ${method} and ${path} template variables used in the tutorials.

Note: The "path" binding uses getUri() which, based on the codebase patterns, includes the query string portion. This is likely intentional for template simplicity, but consider documenting this behavior if users might expect only the path component without query parameters.

annot/src/main/java/com/predic8/membrane/annot/model/ElementInfo.java (1)

94-96: ****

The original review conflates unrelated concerns and mischaracterizes the code.

The method is correctly named getXSDTypeName because it genuinely serves both purposes: generating XSD type names (used in Schemas.java for xsd:complexType and xsd:element declarations) and JSON Schema definition names (used in JsonSchemaGenerator.java and K8sJsonSchemaGenerator.java for #/$defs/ references). The comment explaining the dot-to-underscore transformation is necessary context, not evidence of inconsistency.

The naming collision concern is theoretical. The change replaces dots with underscores in fully-qualified class names. For collisions to occur, the codebase would need two different class names differing only in dot placement—e.g., com.predic8.interceptor_ws.addressing.Parser versus com.predic8.interceptor.ws_addressing.Parser. The codebase standardizes on package names like ws_addressing (underscores already present) with no evidence of such pathological overlaps. Given Java naming conventions, this is not a practical risk.

The change is a legitimate fix: it makes generated schemas compatible with JSON Schema parsers that reject dots in identifiers, which is the stated justification in the code comment.

Likely an incorrect or invalid review comment.

core/src/main/java/com/predic8/membrane/core/kubernetes/GenericYamlParser.java (2)

137-148: Excellent enum parsing with proper error handling.

The changes improve enum parsing robustness:

  • Uses Locale.ROOT for locale-independent case conversion
  • Wraps IllegalArgumentException in the custom WrongEnumConstantException for clearer error messages
  • Properly declares checked exception in method signature

127-127: No issues found - Java 21 is confirmed for the core module.

The parent pom.xml specifies javac.source and javac.target as Java 21, which the core module inherits. The use of List.getFirst() on line 127 is fully compatible with the project's Java 21 target version.

annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (3)

42-42: LGTM! Well-implemented duplicate prevention.

The topLevelAdded tracking mechanism correctly prevents duplicate top-level parser definitions. The map is properly cleared in assemble() (line 78) for reusability, and the check at line 120 ensures parsers are only created once per child name.

Also applies to: 120-120, 124-124


166-180: Good refactoring to centralize property creation.

Extracting createProperty improves maintainability and makes the enum handling logic more explicit.


90-90: Reference format is correct and consistent with codebase naming conventions.

The underscore format in com_predic8_membrane_core_config_spring_ApiParser matches the output of getXSDTypeName(), which explicitly converts package dots to underscores. This is intentional—JSON Schema parsers do not accept names like a.b.c. The hardcoded reference aligns with how all other references are dynamically generated throughout the codebase.

Comment thread annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java Outdated
Comment thread annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java Outdated
Comment thread distribution/tutorials/advanced/40-Path-Parameter-Routing.yaml
Comment thread distribution/tutorials/advanced/50-Path-Rewriting.yaml
Comment thread distribution/tutorials/getting-started/80-OpenAPI.yaml Outdated
Copy link
Copy Markdown
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/openapi/serviceproxy/OpenAPIRecordFactory.java (1)

152-161: Verify the necessity of reading the resource twice.

The refactored getOpenAPI method reads the OpenAPI resource twice:

  1. Line 160: parseFromLocation calls OpenAPIParser.readLocation() to parse the OpenAPI
  2. Line 154: getInputStreamForLocation retrieves the content again to read it as a JsonNode

While functionally correct, this double I/O could impact performance, especially for remote resources.

Consider whether both reads are necessary, or if the JsonNode could be obtained from the OpenAPI object or cached from a single read. If both are required, consider adding a comment explaining why.

If this pattern is acceptable for your use case, this is just a minor optimization suggestion and can be safely ignored.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10c5dc6 and 00bf3c9.

📒 Files selected for processing (5)
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/K8sJsonSchemaGenerator.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/kubernetes/BeanCache.java (5 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java (7 hunks)
  • distribution/tutorials/getting-started/80-OpenAPI.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/tutorials/getting-started/80-OpenAPI.yaml
  • annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/K8sJsonSchemaGenerator.java
🧰 Additional context used
🧬 Code graph analysis (2)
core/src/main/java/com/predic8/membrane/core/kubernetes/BeanCache.java (1)
core/src/main/java/com/predic8/membrane/core/exceptions/SpringConfigurationErrorHandler.java (1)
  • SpringConfigurationErrorHandler (30-197)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java (1)
core/src/main/java/com/predic8/membrane/core/util/URIUtil.java (1)
  • URIUtil (28-146)
🔇 Additional comments (5)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java (4)

40-40: LGTM! Necessary import for URI utility functions.

The static import is required for the new convertPath2FilePathString usage at line 166.


89-89: LGTM! Log level adjustment reduces noise.

Changing from info to debug for individual spec parsing events is appropriate, as this can generate excessive logs when processing multiple specs.


163-169: LGTM! Correct URI conversion logic.

The method correctly identifies when a path needs conversion to a file URI by checking for existing protocol prefixes. The implementation aligns with the URIUtil utility functions.


140-140: No action required - exception handling verified.

The verification confirms that the IOException propagation is correctly handled. The only call site at line 90 is wrapped in a try-catch block that catches Exception, which properly handles IOException as a subclass. Since this is a private method and the caller correctly handles the exception, the code changes are appropriate.

core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java (1)

189-189: LGTM! Appropriate log level adjustment.

Changing from info to debug for this trace-level logging reduces noise for routine Swagger UI requests. All existing instantiations of OpenAPIPublisherInterceptor already use the parameterized constructor accepting a Map<String, OpenAPIRecord>, so the removal of the no-arg constructor does not break any code in the codebase.

Copy link
Copy Markdown
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: 5

♻️ Duplicate comments (1)
distribution/tutorials/json/60-Json-Template.yaml (1)

30-36: Remove trailing comma from array items to ensure valid JSON output.

The template generates invalid JSON due to the trailing comma after the closing brace on line 35. When the template renders, the last object in the positions array will have a trailing comma, which is not valid in strict JSON parsers.

Apply this diff to fix the trailing comma issue:

                  <% for (item in property.items) { %>
                  {
                    "product": "<%= item.article %>",
                    "quantity": <%= item.quantity %>,
                    "amount": <%= item.quantity * item.price %>
-                 },
+                 }<%= item != property.items[-1] ? ',' : '' %>
                  <% } %>

Or alternatively, restructure to avoid the issue:

                  "positions": [
-                 <% for (item in property.items) { %>
+                 <%
+                   def first = true
+                   for (item in property.items) {
+                     if (!first) { %>,<% }
+                     first = false
+                 %>
                  {
                    "product": "<%= item.article %>",
                    "quantity": <%= item.quantity %>,
                    "amount": <%= item.quantity * item.price %>
-                 },
+                 }
                  <% } %>
🧹 Nitpick comments (1)
core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (1)

187-198: Consider additional test cases for edge cases.

The current test coverage is good for basic scenarios. Consider adding tests for:

  1. Case variations: "False", "NO", "TRUE" (verify case-insensitive handling)
  2. Whitespace edge cases: " false ", " 0 ", " " (whitespace not trimmed in implementation)
  3. Numeric variations: "0.0", "00", "-1", "2" (only "0" is explicitly FALSE)
  4. Boolean objects: Boolean.TRUE, Boolean.FALSE (line 145-146 in implementation)
  5. Other types: Integer.valueOf(0), Integer.valueOf(1), empty List (default case returns FALSE)

Particularly important: The implementation doesn't trim whitespace, so " false " would evaluate to TRUE (not FALSE), which might be unexpected.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00bf3c9 and 5b6360c.

📒 Files selected for processing (14)
  • core/src/main/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpression.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java (2 hunks)
  • core/src/test/java/com/predic8/membrane/core/interceptor/flow/IfInterceptorSpELTest.java (2 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (2 hunks)
  • distribution/tutorials/README.md (1 hunks)
  • distribution/tutorials/advanced/65-if.yaml (1 hunks)
  • distribution/tutorials/advanced/70-Scripting-Groovy.yaml (1 hunks)
  • distribution/tutorials/getting-started/00-First-API.yaml (1 hunks)
  • distribution/tutorials/getting-started/80-OpenAPI.yaml (1 hunks)
  • distribution/tutorials/getting-started/90-OpenAPI-Validation.yaml (1 hunks)
  • distribution/tutorials/getting-started/README.md (1 hunks)
  • distribution/tutorials/getting-started/membrane.cmd (1 hunks)
  • distribution/tutorials/getting-started/membrane.sh (1 hunks)
  • distribution/tutorials/json/60-Json-Template.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/tutorials/getting-started/README.md
  • distribution/tutorials/getting-started/00-First-API.yaml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-02T18:05:47.059Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1947
File: distribution/tutorials/soap/membrane.sh:17-22
Timestamp: 2025-07-02T18:05:47.059Z
Learning: When using environment variable shortcuts like `$MEMBRANE_HOME` in shell scripts that look for installation directories, validate that required files (like `starter.jar` for Membrane) exist in the candidate directory before returning it. This prevents hard-to-diagnose runtime errors when the environment variable points to an invalid or stale location.

Applied to files:

  • distribution/tutorials/getting-started/membrane.cmd
  • distribution/tutorials/getting-started/membrane.sh
🧬 Code graph analysis (1)
core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (1)
core/src/main/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpression.java (1)
  • SpELExchangeExpression (34-160)
🪛 markdownlint-cli2 (0.18.1)
distribution/tutorials/README.md

38-38: Bare URL used

(MD034, no-bare-urls)

🪛 Shellcheck (0.11.0)
distribution/tutorials/getting-started/membrane.sh

[warning] 8-8: Remove space after = if trying to assign a value (for empty string, use var='' ... ).

(SC1007)

🔇 Additional comments (9)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java (1)

194-194: LGTM: Appropriate log level adjustment.

Changing from info to debug for API documentation requests reduces log noise while maintaining observability for troubleshooting.

core/src/test/java/com/predic8/membrane/core/interceptor/flow/IfInterceptorSpELTest.java (2)

47-49: LGTM: Clean test method rename.

The rename from simpleRequestTrue to requestTrue improves conciseness while maintaining clarity.


120-129: LGTM: Exception contract correctly narrowed.

Removing throws Exception from the method signature is appropriate and improves the method contract by making it more precise. Since the code compiles, the methods called internally (init() and handleRequest()) either don't throw checked exceptions or only throw runtime exceptions, which aligns with the exception handling refactoring described in the PR context.

core/src/main/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpression.java (1)

130-130: LGTM - Visibility widened for testability.

The visibility change from private static to static (package-private) enables direct testing, which is appropriate given the new test coverage.

core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (1)

27-28: LGTM - Clean use of Boolean constants.

Using Boolean constants improves test readability compared to primitive boolean literals.

distribution/tutorials/advanced/70-Scripting-Groovy.yaml (1)

1-51: LGTM! Clear demonstration of Groovy scripting capabilities.

The tutorial effectively demonstrates three different Groovy scripting patterns:

  • Variable interpolation and flow context
  • Dynamic destination selection with Collections API
  • Response builder pattern with fluent API

The YAML structure and Groovy syntax are correct.

distribution/tutorials/advanced/65-if.yaml (1)

1-39: LGTM! Effective demonstration of conditional flow control.

The tutorial clearly shows:

  • Default SpEL language for conditions
  • Language switching to Groovy where needed
  • Request and response phase conditional processing
  • Proper error handling with appropriate status codes

The configuration is well-structured and the examples are instructive.

distribution/tutorials/getting-started/membrane.sh (1)

1-21: LGTM! Shell script correctly locates Membrane root with proper validation.

The script implementation is sound:

  • Uses CDPATH-aware directory resolution (line 8)
  • Validates both starter.jar and run-membrane.sh exist before using a directory (lines 12-15)
  • Properly exports environment variables and delegates to the launcher
  • Provides clear error message on failure

Note: The shellcheck warning on line 8 about "space after =" is a false positive. The syntax CDPATH= cd intentionally sets CDPATH to empty for that command only, preventing CDPATH from affecting directory resolution.

Based on learnings

distribution/tutorials/getting-started/membrane.cmd (1)

1-24: LGTM! Windows batch script correctly mirrors the Unix shell script logic.

The implementation is correct:

  • Properly resolves script directory with trailing backslash handling (lines 4-5)
  • Validates both starter.jar and run-membrane.cmd exist before using a directory (line 10)
  • Correctly ascends directory hierarchy until root
  • Properly sets environment variables and delegates execution
  • Preserves exit code from the launched process
  • Provides clear error message on failure

Based on learnings

Comment thread distribution/tutorials/getting-started/80-OpenAPI.yaml Outdated
Comment thread distribution/tutorials/getting-started/90-OpenAPI-Validation.yaml Outdated
Comment thread distribution/tutorials/README.md
@rrayst
Copy link
Copy Markdown
Member

rrayst commented Nov 11, 2025

/ok-to-test

Comment thread annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java Outdated
@predic8
Copy link
Copy Markdown
Member Author

predic8 commented Nov 11, 2025

@coderabbitai plz review

Copy link
Copy Markdown
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: 4

♻️ Duplicate comments (1)
annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (1)

174-181: Keep enum casing stable.

Lowercasing the enum literals (Line 175 onward) rewrites every generated schema to use lowercase strings, breaking consumers that rely on the existing uppercase values (e.g., EUR, USD, VALID). This regression was already flagged and remains unresolved—please preserve the original casing.

-            s.enumValues(enumsAsLowerCaseList(ai));
+            s.enumValues(ai.getEnumValues());
-    private static List<String> enumsAsLowerCaseList(AttributeInfo ai) {
-        return ai.getEnumValues().stream().map(String::toLowerCase).toList();
-    }
🧹 Nitpick comments (3)
core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (1)

188-204: Excellent test coverage for boolean conversion logic!

The test comprehensively validates the toBoolean method with various input types: string literals (case variations), edge cases (null, empty), numeric strings, affirmative/negative terms, and Boolean wrappers. All assertions correctly align with the implementation behavior.

Optionally, consider adding test cases for these edge scenarios:

  • Whitespace-only strings (e.g., " ", " ")
  • Numeric types beyond strings (e.g., Integer.valueOf(0), Integer.valueOf(1))
+    assertEquals(TRUE, toBoolean(" "));      // whitespace → TRUE (not in FALSE list)
+    assertEquals(FALSE, toBoolean(0));       // numeric zero → FALSE (default case)
+    assertEquals(FALSE, toBoolean(1));       // numeric one → FALSE (default case)

Note: The current coverage is already strong; these additions would only marginally improve edge-case documentation.

distribution/tutorials/advanced/README.md (1)

1-10: Consider adding explicit references to tutorial files.

The README introduces the advanced topics well but doesn't explicitly list or link to the individual tutorial YAML files (10-PathParameters.yaml, 20-Path-Parameter-Routing.yaml, etc.). Adding file references or links would help users navigate the tutorials more easily.

Example enhancement:

 # Advanced Membrane Tutorial
 
 In this tutorial you will learn advanced features of Membrane, including:
 
+- [Path Parameters](10-PathParameters.yaml)
+- [Path Parameter Routing](20-Path-Parameter-Routing.yaml)
+- [Path Rewriting](20-Path-Rewriting.yaml)
+- [Redirects](30-Redirects.yaml)

Before starting, we recommend completing the Getting Started tutorial.


</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/70-Template.yaml (1)</summary><blockquote>

`9-13`: **Enhance tutorial with expected output.**

The test instruction "Observe the response" is somewhat vague. Consider adding a brief note about what output to expect (e.g., "Method: GET, Path: /foo, Date: ...") to make the tutorial more self-contained and help users verify correctness quickly.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: CodeRabbit UI

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 5b6360c0d671e72eb96213ceee552797bd05890a and cba8408b03163716bb3b67a4d78c22e7f23c28f0.

</details>

<details>
<summary>📒 Files selected for processing (20)</summary>

* `annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java` (9 hunks)
* `annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java` (1 hunks)
* `core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java` (2 hunks)
* `core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java` (0 hunks)
* `core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java` (2 hunks)
* `distribution/tutorials/advanced/10-PathParameters.yaml` (1 hunks)
* `distribution/tutorials/advanced/20-Path-Parameter-Routing.yaml` (1 hunks)
* `distribution/tutorials/advanced/20-Path-Rewriting.yaml` (1 hunks)
* `distribution/tutorials/advanced/30-Redirects.yaml` (1 hunks)
* `distribution/tutorials/advanced/README.md` (1 hunks)
* `distribution/tutorials/getting-started/00-First-API.yaml` (1 hunks)
* `distribution/tutorials/getting-started/10-Logging.yaml` (1 hunks)
* `distribution/tutorials/getting-started/20-Message-Flow.yaml` (1 hunks)
* `distribution/tutorials/getting-started/30-Message-Flow2.yaml` (1 hunks)
* `distribution/tutorials/getting-started/40-Basic-Path-Routing.yaml` (1 hunks)
* `distribution/tutorials/getting-started/50-Short-Circuit.yaml` (1 hunks)
* `distribution/tutorials/getting-started/60-SetHeader.yaml` (1 hunks)
* `distribution/tutorials/getting-started/70-Template.yaml` (1 hunks)
* `distribution/tutorials/getting-started/80-OpenAPI.yaml` (1 hunks)
* `distribution/tutorials/getting-started/90-OpenAPI-Validation.yaml` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary>

* core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java
* distribution/tutorials/getting-started/90-OpenAPI-Validation.yaml
* distribution/tutorials/getting-started/00-First-API.yaml

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>📚 Learning: 2025-10-23T13:04:11.388Z</summary>

Learnt from: predic8
Repo: membrane/api-gateway PR: 2240
File: annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java:210-215
Timestamp: 2025-10-23T13:04:11.388Z
Learning: In JsonSchemaGenerator.java, when allowForeign is true for non-list child elements, use a property named "ref" (not "$ref") with type "string" to provide IDE completion hints for Spring bean references while avoiding JSON Schema keyword collision.


**Applied to files:**
- `annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java`

</details>

</details><details>
<summary>🧬 Code graph analysis (3)</summary>

<details>
<summary>core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (1)</summary><blockquote>

<details>
<summary>core/src/main/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpression.java (1)</summary>

* `SpELExchangeExpression` (34-160)

</details>

</blockquote></details>
<details>
<summary>annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1)</summary><blockquote>

<details>
<summary>annot/src/main/java/com/predic8/membrane/annot/AnnotUtils.java (1)</summary>

* `AnnotUtils` (22-99)

</details>

</blockquote></details>
<details>
<summary>annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (1)</summary><blockquote>

<details>
<summary>annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaFactory.java (1)</summary>

* `SchemaFactory` (5-60)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)</summary>

* GitHub Check: Automated tests
* GitHub Check: Analyze (java)

</details>

<details>
<summary>🔇 Additional comments (13)</summary><blockquote>

<details>
<summary>core/src/test/java/com/predic8/membrane/core/lang/spel/SpELExchangeExpressionTest.java (1)</summary><blockquote>

`27-29`: **LGTM! Appropriate static imports for the new test.**

The static imports support the new `booleanConversion()` test method and align with the widened visibility of the `toBoolean` method.

</blockquote></details>
<details>
<summary>distribution/tutorials/advanced/30-Redirects.yaml (1)</summary><blockquote>

`1-28`: **Well-structured redirect tutorial with clear guidance.**

The YAML configuration demonstrates a clean redirect pattern with helpful inline instructions. The log messages and curl examples provide good guidance for users following the tutorial.

</blockquote></details>
<details>
<summary>distribution/tutorials/advanced/20-Path-Parameter-Routing.yaml (1)</summary><blockquote>

`1-14`: **Clean and focused path parameter routing tutorial.**

The configuration clearly demonstrates path parameter syntax and template substitution. The example is straightforward and easy to follow.

</blockquote></details>
<details>
<summary>distribution/tutorials/advanced/20-Path-Rewriting.yaml (1)</summary><blockquote>

`1-25`: **Effective tutorial demonstrating path rewriting with logging.**

The before/after logging pattern is pedagogically valuable for learners to observe the rewriting transformation. The inline comment about quoting special characters is helpful contextual guidance.

</blockquote></details>
<details>
<summary>distribution/tutorials/advanced/10-PathParameters.yaml (1)</summary><blockquote>

`15-25`: **Tutorial content is well-structured.**

The path parameter definition and template rendering demonstrate the concept clearly. The setup instructions with curl example are helpful for users.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/50-Short-Circuit.yaml (1)</summary><blockquote>

`1-26`: **LGTM!**

Well-structured tutorial with clear documentation, correct configuration syntax, and practical curl examples.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/20-Message-Flow.yaml (1)</summary><blockquote>

`1-28`: **LGTM!**

Clear tutorial structure with platform-specific instructions. Variable bindings `${path}` and `${statusCode}` are used as per the core changes supporting enhanced scripting context.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/30-Message-Flow2.yaml (1)</summary><blockquote>

`1-53`: **LGTM!**

Excellent tutorial progression showing request/response flow control. Metadata naming and Admin Console integration provide good learning value. Structured logging clearly demonstrates execution order.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/10-Logging.yaml (1)</summary><blockquote>

`1-30`: **Configuration and documentation are sound.**

The logging tutorial effectively demonstrates the logging plugin with clear cross-platform instructions and expected output.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/40-Basic-Path-Routing.yaml (1)</summary><blockquote>

`1-40`: **Configuration and documentation are well-structured.**

Path routing with multiple backend targets is clearly demonstrated. The use of `---` separators and ordering rules is well-documented with practical curl examples.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/60-SetHeader.yaml (1)</summary><blockquote>

`1-24`: **LGTM!**

Concise tutorial demonstrating both static and dynamic header values. The `${method}` binding is supported by the core scripting context enhancements introduced in this PR.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/80-OpenAPI.yaml (1)</summary><blockquote>

`1-26`: **LGTM!**

Past review feedback has been successfully addressed. The typo correction and filename fix are in place. Configuration correctly demonstrates loading both remote and local OpenAPI specifications. Schema path is consistent with other tutorials.

</blockquote></details>
<details>
<summary>distribution/tutorials/getting-started/70-Template.yaml (1)</summary><blockquote>

`1-27`: **No issues found with template binding availability in response phase.**

The `method` and `path` bindings are extracted from the Exchange request object at the parameter binding stage (ScriptingUtils lines 59-60), before flow-specific logic. These bindings are therefore available in both request and response phases, making the tutorial configuration correct and functional.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread distribution/tutorials/advanced/10-PathParameters.yaml
Comment thread distribution/tutorials/getting-started/10-Logging.yaml
Comment thread distribution/tutorials/getting-started/40-Basic-Path-Routing.yaml
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 11, 2025

@predic8: I'll review the changes in this PR right away!

✅ 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.

Copy link
Copy Markdown
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

♻️ Duplicate comments (2)
annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1)

140-156: Initialize enumValues for enum types with java.lang.Enum superclass.

When the setter parameter's declared type has java.lang.Enum as its superclass, the code sets isEnum = true but never initializes the enumValues field. This will cause a NullPointerException when isEnumBoolean() or getEnumValues() is subsequently called, since those methods dereference enumValues.

Apply this diff to populate enumValues before returning:

                 if (superClass.getQualifiedName().toString().equals("java.lang.Enum")) {
                     isEnum = true;
+                    enumValues = getEnumValues(e);
                     xsdType = "xsd:string"; // TODO: restriction, but be carefull about Spring EL usage, for example "#{config.XXX}"
annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (1)

174-176: Fix enum case handling inconsistency and potential breaking change.

Converting non-boolean enum values to lowercase (line 175) creates inconsistent schema generation and may break existing consumers:

  1. Inconsistency: Boolean enums get type "boolean" with no enum values, while other enums get lowercase string values. This means enum constants like VALID, INVALID appear as "valid", "invalid" in schemas.

  2. Breaking change: Existing validators and configurations expecting uppercase enum values (e.g., EUR, USD, TRUE, FALSE as seen in test data) will fail validation.

Consider preserving the original enum constant casing to maintain compatibility and consistency across all enum types.

Apply this diff to preserve original casing:

-        if (ai.isEnum(processingEnv.getTypeUtils()) && !"boolean".equals(type)) {
-            s.enumValues(ai.enumsAsLowerCaseList(processingEnv.getTypeUtils()));
-        }
+        if (ai.isEnum(processingEnv.getTypeUtils()) && !"boolean".equals(type)) {
+            s.enumValues(ai.getEnumValues(processingEnv.getTypeUtils()));
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cba8408 and d54cfb0.

📒 Files selected for processing (3)
  • annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (9 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T13:04:11.388Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2240
File: annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java:210-215
Timestamp: 2025-10-23T13:04:11.388Z
Learning: In JsonSchemaGenerator.java, when allowForeign is true for non-list child elements, use a property named "ref" (not "$ref") with type "string" to provide IDE completion hints for Spring bean references while avoiding JSON Schema keyword collision.

Applied to files:

  • annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java
🧬 Code graph analysis (2)
annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (1)
annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaFactory.java (1)
  • SchemaFactory (5-60)
annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1)
annot/src/main/java/com/predic8/membrane/annot/AnnotUtils.java (1)
  • AnnotUtils (22-99)
🔇 Additional comments (3)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java (1)

151-151: LGTM!

Removing the trailing semicolon is correct Java style for enums without additional members after the constants.

annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java (2)

166-178: Good refactoring to extract property creation logic.

The new createProperty helper method improves code organization by consolidating the schema property construction logic that was previously inline. The use of SchemaFactory.from(type) and the clear handling of enum vs. non-enum cases makes the code more maintainable.


197-268: Approve use of generic wildcards for schema flexibility.

The refactoring to use AbstractSchema<?> in method signatures (lines 197, 200, 235, 257) improves type safety and flexibility, allowing methods to work with any schema type (SchemaObject, SchemaArray, etc.) without unnecessary type constraints.

Comment thread annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java Outdated
Copy link
Copy Markdown
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: 2

♻️ Duplicate comments (1)
annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1)

140-156: Initialize enumValues when detecting enum via superclass.

This issue was flagged in a previous review but remains unaddressed. When a declared type's superclass is java.lang.Enum, the code sets isEnum = true (line 143) but never initializes the enumValues field. Subsequently, calls to getEnumValues(), isEnumBoolean(), or enumsAsLowerCaseList() will return or dereference null, causing NullPointerException.

Apply this diff to initialize enumValues:

                 if (superClass.getQualifiedName().toString().equals("java.lang.Enum")) {
                     isEnum = true;
+                    enumValues = getEnumValues(e);
                     xsdType = "xsd:string"; // TODO: restriction, but be carefull about Spring EL usage, for example "#{config.XXX}"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d54cfb0 and 8ee1f49.

📒 Files selected for processing (1)
  • annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java (1)
annot/src/main/java/com/predic8/membrane/annot/AnnotUtils.java (1)
  • AnnotUtils (22-99)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Automated tests
  • GitHub Check: Analyze (java)

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