Skip to content

Commit a2ff0e7

Browse files
authored
Merge pull request #1692 from ako/fix/1451-java-action-call-parameters
fix: Java/JavaScript action signatures and template/document arguments written wrong (#1451, #935)
2 parents c7de926 + a919a99 commit a2ff0e7

52 files changed

Lines changed: 2273 additions & 60 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"area": "mdl/executor", "date": "2026-10-25", "symptom": "`call java action BusinessEvents.PublishBusinessEvent_V2(Subject = 'Order shipped', BusinessEvent = $Event)` and `call java action AgentEditorCommons.Agent_CallDocument_WithoutHistory(Agent = 'M.MyAgent', …)` pass `check --references` and exec; mx check reports CE0115 \"The arguments that are passed to Java action '…' do not match the expected parameters and need to be refreshed\" at each call. `describe java action` showed the agent parameter as `Agent: String not null`; `describe microflow` printed a template value as its text only", "cause": "addCallJavaActionAction (mdl/executor/cmd_microflows_builder_calls.go) gave only entity-type and Microflow parameters their own value; a text-template parameter (CodeActions$StringTemplateParameterType) and a custom-document parameter (CodeActions$CustomBlobDocumentParameterType) fell to the default Microflows$BasicCodeActionParameterValue with the argument's source text. The document parameter TYPE also read back as a String (codeActionParamTypeFromGen had no case for it), and MDL had no way to write a template's {n} arguments at all", "file": "`mdl/executor/java_action_call_values.go` (javaActionTemplateValue, templateArgumentType + flowExprTypes, javaActionDocumentValue, javaActionCallValueErrors, MDL-JA02), called from `addCallJavaActionAction` and `validate.go` (validateFlowBodyReferences); `mdl/backend/modelsdk/microflow_write.go` / `microflow_read_actions.go` (PrimitiveTypedTemplateArgument, CustomBlobDocumentCodeActionParameterValue), `java_read.go` / `java_write.go` (CustomBlobDocumentType), `cmd_microflows_format_action.go` (describeTypedTemplate); grammar `callArgument … templateParams?` + visitor; tests `mdl/executor/cmd_microflows_builder_java_template_1451_test.go`, `mdl/backend/modelsdk/java_action_call_values_1451_test.go`, `mdl/visitor/visitor_java_action_template_1451_test.go`; fixtures `mdl-examples/bug-tests/java-action-1451-template-parameter.mdl`, `java-action-1451-expression-with-params.fail.mdl`", "insight": "**No Studio Pro reference exists here** (searched every .mpr/.mxunit/.mpk on the machine: 0 StringTemplateParameterValue, 0 CustomBlobDocumentParameterType outside module definitions; the Studio Pro MCP tunnel was down), so the shapes come from generated/metamodel and were *measured* against mxbuild 11.13 by hand-patching the unit (a throwaway Go probe over the v1 Unit table). What the probes settled, none of it guessable: a TypedTemplate argument is Microflows$PrimitiveTypedTemplateArgument{Expression, Type}; **Type is checked against the expression** (CE0117 for String-typed Integer, Integer-typed String, and for any Type on an enumeration expression — an enum is not one of the five); an absent Type reads as String; {1} with no argument is CE0720; Long attributes take Integer; `[%CurrentDateTime%]` takes DateTime — and exprcheck's inferKind calls every token a String, so use its argKind (now InferArgumentKind), which the built-in-function check already special-cased. The runtime hands Type to Java (ITemplateParameter.getParameterType), so the type is semantics, not decoration. For the document value mxbuild reports a wrong-type document as CE0115 and a missing one as CE1613 — check --references resolves agent-editor documents for that reason. The REST-body rule (#1444) carries over: a non-literal is '{1}' with the expression; but **describe must print `$X`, not `'{1}' with ({1} = $X)`**, because the declared-match pass (flow_declared_match) cannot know which CallArgument is a template, so only the short form re-execs as 'Unchanged' — except when the one argument is itself a string literal, which would read back as the text. A pre-fix build is no control for a script-created action: `create java action … StringTemplate(Text)` wrote a String parameter (separate fix), so the control is fixed-build action + pre-fix microflow (CE0115 x2), and the BusinessEvents module (CE0115 per call -> 0 errors)", "refs": ["ako/mxcli#1451", "mendixlabs/mxcli#1554", "ako/mxcli#1444", "mendixlabs/mxcli#1210"], "ce": ["CE0115", "CE0117", "CE0720", "CE1613"], "rules": ["MDL-JA02"], "test": "TestCallJavaAction_TemplateParameterWithArguments, TestCallJavaAction_TemplateParameterPlainString, TestCallJavaAction_TemplateParameterExpression, TestCallJavaAction_DocumentParameter, TestCallJavaAction_TemplateAndDocumentRefusals, TestCallJavaAction_TemplateAndDocumentDescribeRoundTrip, TestValidate_JavaActionTemplateAndDocumentArguments, TestJavaActionCallToGen_TemplateAndDocumentValues, TestJavaActionCallFromGen_TemplateAndDocumentValuesRoundTrip, TestJavaActionParamType_CustomBlobDocumentRoundTrips, TestCallJavaActionTemplateArgument, TestTemplateArgumentRefusedOutsideCallJavaAction"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"area": "mdl/executor", "date": "2026-10-25", "symptom": "`create java action M.J (Subject: StringTemplate(Text))` — the form describe prints for a text-template parameter — writes a String parameter; describe of the new action prints `Subject: String`. A describe -> exec of a module's action (BusinessEvents.PublishBusinessEvent_V2) silently turns its template parameter into a String. The generated .java typed it java.lang.String", "cause": "astDataTypeToJavaActionParamType had no case for ast.TypeStringTemplate and returned its default StringType; sdk/javaactions/source.go mapped StringTemplateParameterType to java.lang.String, pinned by a golden (JA_Tpl) that had itself been measured on an action this bug had created with String parameters", "file": "`mdl/executor/cmd_javaactions.go` (astDataTypeToJavaActionParamType), `sdk/javaactions/source.go` (javaParamType), golden `sdk/javaactions/testdata/mxbuild/JA_Tpl.java.golden`; test `mdl/executor/cmd_javaactions_string_template_param_test.go`", "insight": "**A golden is only as good as the model it was measured on**: JA_Tpl.java.golden recorded `java.lang.String Q` because mxbuild generated it for the String parameter mxcli had wrongly written. Check a golden's provenance before trusting it as the spec. The real type is `com.mendix.systemwideinterfaces.javaactions.parameters.IStringTemplate`, fully qualified and not imported — seen in the source mxbuild generated for BusinessEvents 3.12's PublishBusinessEvent_V2, and re-measured on 11.13.0: after a `--target=deploy` build mxcli's file is byte-identical to mxbuild's, and a file edited back to java.lang.String is rewritten to IStringTemplate by the build (the control that shows the build regenerates rather than keeps the file). Found while fixing ako/mxcli#1451, whose check-side template validation reads the declared type from the script and would otherwise disagree with exec", "refs": ["ako/mxcli#1451", "ako/mxcli#934"], "ce": ["CE0115"], "test": "TestParamType_StringTemplateIsATemplate, TestGenerateSource_RegeneratesWhatMxbuildWrote"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"area": "mdl/executor", "date": "2026-10-25", "symptom": "`create java action M.JA (C: M.Color) returns Boolean` with M.Color an enumeration passes `check --references` and `exec`; mxbuild then reports CE1613 \"The selected entity 'M.Color' no longer exists\" for the parameter (and for `returns M.Color`). Same for JavaScript actions and for a System enumeration (`System.DeviceType`). A bare name that is neither an entity nor an enumeration (`M.NoSuchThing`) also passed both and failed the same way. Only `C: enum M.Color` worked; describe of a correct action prints `Enum M.Color`, so a bare name in describe output is the symptom", "cause": "In a code-action signature a bare `Module.Name` parses as TypeEnumeration with ExplicitEnum=false (the TypeEnumeration/TypeEntity ambiguity), and `astDataTypeToJavaActionParamType` / `…ReturnType` turned every such name into a CodeActions$EntityType. A comment there said callers 'resolve it via resolveCodeActionParamType' — a function that never existed in the repo. Flows had the entity-then-enumeration fallback (buildMicroflowFromStmt, settleSystemEnumeration); Java and JavaScript actions never got it, and check had no signature pass for them at all", "file": "`mdl/executor/code_action_signature_types.go` (`settleCodeActionSignature`, called from `execCreateJavaAction` and `execCreateJavaScriptAction` before anything is written; `codeActionSignatureErrors`, wired into `validateWithContext` for CreateJavaActionStmt / CreateJavaScriptActionStmt); stale comment fixed in `mdl/executor/cmd_javaactions.go`; tests `mdl/executor/cmd_javaactions_bare_enum_935_test.go`; fixture `mdl-examples/bug-tests/java-action-935-bare-enumeration-type.mdl`", "insight": "**A comment naming a function is a claim — grep for the function.** The converter's comment made the bug look handled; `grep -rn resolveCodeActionParamType` returns only the comment. Settle the name BEFORE the converter (retype an enumeration as an explicit one) rather than teaching the converter to look things up: the converter has no context, and the existing explicit-enum path then does the write. Decide System names from `meta.SystemEnumerations` (systemEnumerations) — System entities are not in the project, so 'not an entity' is not evidence there. Keep check and exec on the same verdict: exec settles with the backend, check uses declaredTypeResolver (which also sees names the script creates), and neither resolves a `list of` element, because exec never refused one. Measured on a blank 11.13.0 app: the bug-test script gives CE1613 x5 with a pre-fix build (Java param, Java return, System enum param, JS param, JS return) and 0 errors fixed; describe -> exec reports 'already in sync'. The generated .java takes the enum as `String _c` and converts with `Color.valueOf`, i.e. the source generator already handled EnumerationType once the model said so", "refs": ["ako/mxcli#935", "ako/mxcli#680"], "ce": ["CE1613"], "test": "TestCreateJavaAction_BareEnumerationNameIsAnEnumeration, TestCreateJavaAction_BareNameThatIsNeitherIsRefused, TestCreateJavaScriptAction_BareEnumerationNameIsAnEnumeration, TestCreateJavaScriptAction_BareNameThatIsNeitherIsRefused, TestValidate_CodeActionSignatureTypes"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"area": "mdl/executor", "date": "2026-10-25", "symptom": "`create java action M.J () returns StringTemplate(Text)` passes check and exec and writes a Boolean action (describe: `returns Boolean`); so did `returns Binary`, `returns AutoNumber` and `returns entity <T>`, for Java and JavaScript actions alike", "cause": "astDataTypeToJavaActionReturnType ended in `default: // Default to Boolean type (most common for Java actions)`, so every kind it did not handle became a CodeActions$BooleanType. The intended default (no `returns` clause, Studio Pro's Boolean) and the unhandled kinds shared one branch", "file": "`mdl/executor/cmd_javaactions.go` (astDataTypeToJavaActionReturnType now returns an error; TypeUnknown = omitted is the only Boolean default), `mdl/executor/validate_code_action_return_type.go` (codeActionReturnTypeRefusal, javaActionReturnTypeError = check's call into the same converter, MDL-JA03), wired in validate_program.go and validateJavaScriptActionTypes; test `mdl/executor/cmd_javaactions_return_type_test.go`; fixture `mdl-examples/bug-tests/java-action-1451-return-string-template.fail.mdl`", "insight": "**A converter's `default:` that returns a plausible value is a silent write** (cf. the read-side lie in the #1210 finding). Split the deliberate default from the fall-through: here the deliberate one is TypeUnknown (no `returns`), everything else must error. Make check call the converter itself (javaActionReturnTypeError mirrors exec's type-parameter shortcuts, then asks the converter) rather than keep a second list of supported kinds that can drift. Whether a StringTemplate return is possible was measured, not assumed: generated/metamodel types JavaAction.ActionReturnType (storage JavaReturnType) as CodeActions$Type, whose implementers exclude StringTemplateParameterType, and a v1 unit patched to carry one makes `mx check` 11.13 fail to LOAD the project (InvalidOperationException: no constructor of StringTemplateParameterType taking a JavaAction) — while describe, through codeActionReturnTypeFromGen's own String default, printed `returns String` for it", "refs": ["ako/mxcli#1451"], "rules": ["MDL-JA03"], "test": "TestCreateJavaAction_UnreturnableTypeIsRefusedAtExec, TestCreateJavaAction_OmittedReturnTypeIsBoolean, TestValidate_UnreturnableTypeIsReportedAtCheck"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"area": "mdl/executor", "date": "2026-10-25", "symptom": "`create javascript action M.JSA (S: StringTemplate(Text))` passes check and exec. On main the parameter is silently written as a String (describe: `S: String`); after the Java-action StringTemplate fix it was written as a CodeActions$StringTemplateParameterType into the JavaScript action. mx check 11.13 reports 0 errors for both", "cause": "The grammar's dataType accepts StringTemplate(...) for Java and JavaScript actions alike, and both create handlers share astDataTypeToJavaActionParamType; nothing said a text template is a Java action type only", "file": "`mdl/executor/validate_javascript_action_types.go` (`unsupportedJavaScriptActionTypes`, the one decision; `validateJavaScriptActionTypes` = MDL-JSA01 in the no-project tier via validate_program.go); exec refuses in `execCreateJavaScriptAction`; test `mdl/executor/cmd_javascript_actions_string_template_test.go`; fixture `mdl-examples/bug-tests/javascript-action-1451-string-template.fail.mdl`", "insight": "**Fixing a shared converter widens what every caller accepts.** Teaching astDataTypeToJavaActionParamType StringTemplate for Java actions also made JavaScript actions write one — the twin of the twin-builder lesson (#1137) in the other direction: when a converter is shared, ask which caller must refuse the new case. mx check is no gate here (0 errors on main and on the branch), so the refusal has to be mxcli's; it needs no project, so it lives in the no-project tier and exec's pre-flight refuses it before anything is written. Document(...) has no MDL spelling, so the parser already refuses it for either kind of action. The return type is refused too: the return converter's default turned StringTemplate into Boolean", "refs": ["ako/mxcli#1451"], "rules": ["MDL-JSA01"], "test": "TestCreateJavaScriptAction_StringTemplateIsRefusedAtExec, TestCreateJavaScriptAction_StringTemplateIsRefusedAtCheck"}

‎.claude/skills/mendix/business-events/SKILL.md‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ description: "Define event-driven APIs over Kafka with Mendix business event ser
1515
| 102-117 | Message Definition Syntax |
1616
| 118-125 | Service Properties |
1717
| 126-132 | Operations |
18-
| 133-169 | Publishing Events from Microflows |
19-
| 170-182 | Checklist |
18+
| 133-179 | Publishing Events from Microflows |
19+
| 180-192 | Checklist |
2020

2121
<!-- /skill-index -->
2222
# Business Events
@@ -143,10 +143,20 @@ create microflow Module.ACT_PublishCustomerChanged
143143
begin
144144
$event = create Module.PBE_CustomerChangedEvent (CustomerId = $CustomerId);
145145
commit $event;
146-
call java action BusinessEvents.PublishBusinessEvent_V2(EventObject = $event);
146+
call java action BusinessEvents.PublishBusinessEvent_V2(
147+
Subject = 'Customer {1} changed' with ({1} = $CustomerId),
148+
BusinessEvent = $event
149+
);
147150
end;
148151
```
149152

153+
`PublishBusinessEvent_V2` takes two parameters: `Subject`, a **text template**
154+
(`StringTemplate(Text)`), and `BusinessEvent`, the event object. `Subject` is
155+
written like a log message — a string, or `'… {1} …' with ({1} = …)`; each
156+
argument must be a String, Integer, Decimal, Boolean or DateTime value (wrap an
157+
enumeration in `getCaption(…)`). `describe java action` shows the parameters of
158+
any action before you call it.
159+
150160
### Available Java Actions (from BusinessEvents module)
151161

152162
| Java Action | Description |
@@ -164,7 +174,7 @@ end;
164174
2. Create entities prefixed with `PBE_` that **extend `BusinessEvents.PublishedBusinessEvent`**
165175
3. Entity attributes must **exactly match** the message attributes (no extra attributes on the entity)
166176
4. In microflows, create an instance of the event entity, populate its attributes, commit it
167-
5. Call `BusinessEvents.PublishBusinessEvent_V2` passing the entity instance
177+
5. Call `BusinessEvents.PublishBusinessEvent_V2` with a `Subject` template and the entity instance as `BusinessEvent`
168178
6. For subscribe operations, link a handler microflow in the service definition
169179

170180
## Checklist

‎.claude/skills/mendix/java-actions/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ from describe output has changed an action's export level to Public. Check it ag
254254
| `decimal` | Decimal number |
255255
| `boolean` | True/false |
256256
| `datetime` | Date and time |
257-
| `Module.Entity` | Entity reference |
257+
| `Module.Entity` | Entity reference — or an enumeration, when `Module.Entity` names one (the project decides; a name that is neither is refused) |
258258
| `list of Module.Entity` | List of entities |
259259
| `stringtemplate(sql)` | SQL/OQL query template with parameters |
260260
| `stringtemplate(text)` | Text template with parameters |

‎.claude/skills/mendix/java-actions/reference/writing-java.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ still compiles after a full build regenerates it.
3232
| `entity <pEntity>` | `java.lang.String` | The entity's qualified name. |
3333
| `pEntity` | `IMendixObject` | No proxy: the type is only known at runtime. |
3434
| `list of pEntity` | `java.util.List<IMendixObject>` | |
35-
| `stringtemplate(sql)` / `stringtemplate(text)` | `java.lang.String` | |
35+
| `stringtemplate(sql)` / `stringtemplate(text)` | `com.mendix.systemwideinterfaces.javaactions.parameters.IStringTemplate` | Fully qualified, not imported. `replacePlaceholders(...)` fills the `{n}`; each `ITemplateParameter` carries its value and type. A call passes `'text {1}' with ({1} = …)` |
3636
| `Microflow` | `java.lang.String` | The microflow's qualified name. |
3737

3838
Return types: an entity, `pEntity` or `System.FileDocument` return is

‎.claude/skills/mendix/write-microflows/reference/integration.md‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,44 @@ $Tool = call java action MCPServer.AddTool(
297297
`DESCRIBE JAVA ACTION` prints such a parameter's type as the bare word
298298
`Microflow` (`Nanoflow` for JavaScript actions), and that spelling is what
299299
`CREATE JAVA ACTION` accepts, so the round-trip is stable.
300+
301+
## Text-Template and Document Java-Action Parameters
302+
303+
Two more parameter types take something other than an expression. Check the
304+
action's signature with `DESCRIBE JAVA ACTION` first.
305+
306+
A **text template** — `StringTemplate(Text)` or `StringTemplate(Sql)`, such as
307+
`BusinessEvents.PublishBusinessEvent_V2`'s `Subject` — is written like a log
308+
message: a string is the template text, and `with ({1} = …)` fills its
309+
placeholders. Any other expression becomes the template `'{1}'` with that
310+
expression as its argument.
311+
312+
```mdl
313+
call java action BusinessEvents.PublishBusinessEvent_V2(
314+
Subject = 'Order {1} shipped ({2} items)' with ({1} = $Order/Number, {2} = $Order/Lines),
315+
BusinessEvent = $Event
316+
);
317+
```
318+
319+
Each argument is stored with the type of its result, and mxbuild checks the
320+
two match (CE0117). The five types a template takes are String, Integer,
321+
Decimal, Boolean and DateTime. An enumeration is refused, so pass
322+
`getCaption($Order/Status)` or `getKey(…)` instead.
323+
324+
A **document** parameter — `DESCRIBE JAVA ACTION` prints its type as
325+
`Document(<type>)`, for example `Document(agenteditor.agent)` for
326+
AgentEditorCommons' `Agent` — takes the document's qualified name, never an
327+
expression:
328+
329+
```mdl
330+
$Response = call java action AgentEditorCommons.Agent_CallDocument_WithoutHistory(
331+
Agent = MyModule.PaymentReminderAgent,
332+
OptionalContextObject = $Invoice
333+
);
334+
```
335+
336+
`check --references` reports a missing agent-editor document; mxbuild reports
337+
one as CE1613, and a document of another type as CE0115. `CREATE JAVA ACTION`
338+
cannot declare a document parameter, so `describe` output for such an action
339+
does not re-execute: the parser stops at `Document(…)` instead of rewriting
340+
the parameter as a String.

0 commit comments

Comments
 (0)