Skip to content

Commit 34ac3ae

Browse files
akoclaude
andcommitted
fix: Java action imports, DROP/RENAME source file handling (issue #127)
- Extract import lines from $$ block into Java file-level import section instead of placing them inside executeAction() (fixes AI-generated code) - DROP JAVA ACTION now deletes the .java source file from javasource/ - RENAME JAVA ACTION: new MDL syntax wired through full pipeline (grammar, visitor, executor, backend, writer); also renames .java file - Add DeleteJavaSourceFile and RenameJavaSourceFile to JavaBackend interface - Fix outdated Core.retrieveXPathQuery -> Core.createXPathQuery in skill doc - Add doctype-test examples for import extraction, rename, and drop Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 53ca249 commit 34ac3ae

16 files changed

Lines changed: 385 additions & 22 deletions

File tree

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public IMendixObject executeAction() throws Exception
123123
| `Core.delete(context, object)` | Delete object |
124124
| `Core.rollback(context, object)` | Discard uncommitted changes |
125125
| `Core.retrieveId(context, id)` | Retrieve by GUID |
126-
| `Core.retrieveXPathQuery(context, xpath)` | Query with XPath |
126+
| `Core.createXPathQuery(xpath).execute(context)` | Query with XPath |
127127
| `Core.microflowCall(name).execute(context)` | Call microflow |
128128

129129
### Reading and Writing Attributes
@@ -146,8 +146,8 @@ order.setValue(context, "ProcessedDate", new java.util.Date());
146146

147147
```java
148148
// set association (reference)
149-
IMendixObject customer = Core.retrieveXPathQuery(context,
150-
"//Sales.Customer[CustomerCode = 'CUST001']").get(0);
149+
IMendixObject customer = Core.createXPathQuery("//Sales.Customer[CustomerCode = 'CUST001']")
150+
.execute(context).get(0);
151151
order.setValue(context, "Sales.Order_Customer", customer.getId());
152152

153153
// get associated object
@@ -162,8 +162,8 @@ if (customerId != null) {
162162

163163
```java
164164
// retrieve list
165-
list<IMendixObject> orders = Core.retrieveXPathQuery(context,
166-
"//Sales.Order[status = 'Pending']");
165+
list<IMendixObject> orders = Core.createXPathQuery("//Sales.Order[status = 'Pending']")
166+
.execute(context);
167167

168168
// Process list
169169
java.math.BigDecimal total = java.math.BigDecimal.ZERO;
@@ -1068,7 +1068,7 @@ int offset = 0;
10681068
int batchSize = 1000;
10691069
list<IMendixObject> batch;
10701070
do {
1071-
batch = Core.retrieveXPathQuery(context, xpath, batchSize, offset, null);
1071+
batch = Core.createXPathQuery(xpath).setAmount(batchSize).setOffset(offset).execute(context);
10721072
// Process batch
10731073
offset += batchSize;
10741074
} while (batch.size() == batchSize);
@@ -1187,7 +1187,7 @@ Core.commit(context, obj);
11871187
Core.delete(context, obj);
11881188

11891189
// query
1190-
list<IMendixObject> results = Core.retrieveXPathQuery(context, "//Module.Entity[attr = 'value']");
1190+
list<IMendixObject> results = Core.createXPathQuery("//Module.Entity[attr = 'value']").execute(context);
11911191

11921192
// log
11931193
Core.getLogger("ModuleName").info("message");

docs/01-project/MDL_QUICK_REFERENCE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,9 @@ Module.OrderResponse_CustomerInfo/Module.CustomerInfo as customer {
784784
| Create Java action | `create java action Module.Name(params) returns type as $$ ... $$;` | Inline Java code |
785785
| Create with type params | `create java action Module.Name(EntityType: entity <pEntity>, Obj: pEntity) ...;` | Generic type parameters |
786786
| Create exposed action | `... exposed as 'caption' in 'Category' as $$ ... $$;` | Toolbox-visible in Studio Pro |
787-
| Drop Java action | `drop java action Module.Name;` | Delete a Java action |
787+
| Rename Java action | `rename java action Module.Old to New;` | Renames BSON unit and .java source file |
788+
| Rename Java action (dry run) | `rename java action Module.Old to New dry run;` | Preview reference changes without modifying |
789+
| Drop Java action | `drop java action Module.Name;` | Deletes MPR unit and .java source file |
788790
| Call from microflow | `$Result = call java action Module.Name(Param = value);` | Inside BEGIN...END |
789791

790792
**Parameter Types:** `string`, `integer`, `long`, `decimal`, `boolean`, `datetime`, `Module.Entity`, `list of Module.Entity`, `enum Module.EnumName`, `enumeration(Module.EnumName)`, `stringtemplate(sql)`, `stringtemplate(Oql)`, `entity <pEntity>` (type parameter declaration), bare `pEntity` (type parameter reference).

mdl-examples/doctype-tests/07-java-action-examples.mdl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,54 @@ end;
17441744

17451745
-- MARK: Summary
17461746

1747+
-- MARK: Level 9 - Imports in $$ block and DROP/RENAME
1748+
1749+
-- ============================================================================
1750+
-- LEVEL 9: Import extraction, DROP, and RENAME
1751+
-- ============================================================================
1752+
-- Import statements placed inside the $$ block are automatically extracted
1753+
-- and placed in the Java file's import section (issue #127). This is the
1754+
-- natural style for AI-generated Java action code.
1755+
1756+
-- ----------------------------------------------------------------------------
1757+
-- 9.1: Java action with imports inside the $$ block
1758+
-- ----------------------------------------------------------------------------
1759+
-- All import lines are moved to the file-level import section automatically.
1760+
-- The executeAction() method body receives only the non-import lines.
1761+
1762+
create java action JaTest.ParseCSV(CsvText: string not null) returns string
1763+
as $$
1764+
import java.io.BufferedReader;
1765+
import java.io.StringReader;
1766+
BufferedReader reader = new BufferedReader(new StringReader(CsvText));
1767+
String firstLine = reader.readLine();
1768+
reader.close();
1769+
return firstLine != null ? firstLine : "";
1770+
$$;
1771+
1772+
create java action JaTest.ComputeHash(Input: string not null) returns string
1773+
as $$
1774+
import java.security.MessageDigest;
1775+
import java.nio.charset.StandardCharsets;
1776+
import java.util.HexFormat;
1777+
MessageDigest digest = MessageDigest.getInstance("SHA-256");
1778+
byte[] hash = digest.digest(Input.getBytes(StandardCharsets.UTF_8));
1779+
return HexFormat.of().formatHex(hash);
1780+
$$;
1781+
1782+
-- ----------------------------------------------------------------------------
1783+
-- 9.2: RENAME JAVA ACTION — renames BSON document and .java source file
1784+
-- ----------------------------------------------------------------------------
1785+
1786+
rename java action JaTest.ParseCSV to ReadCsvFirstLine;
1787+
1788+
-- ----------------------------------------------------------------------------
1789+
-- 9.3: DROP JAVA ACTION — removes MPR unit and .java source file
1790+
-- ----------------------------------------------------------------------------
1791+
1792+
drop java action JaTest.ReadCsvFirstLine;
1793+
drop java action JaTest.ComputeHash;
1794+
17471795
-- ============================================================================
17481796
-- Java Action Feature Summary
17491797
-- ============================================================================

mdl-examples/doctype-tests/25-rename-examples.mdl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,19 @@ rename entity RenameTest.Customer to client;
2424
-- Rename association
2525
rename association RenameTest.Order_Customer to Order_Client;
2626

27+
-- Rename java action (also renames the .java source file on disk)
28+
create java action RenameTest.OldHelper() returns string
29+
as $$
30+
return "hello";
31+
$$;
32+
33+
rename java action RenameTest.OldHelper to NewHelper;
34+
35+
-- Dry run: preview what references would change without modifying anything
36+
rename java action RenameTest.NewHelper to AnotherName dry run;
37+
2738
-- Clean up
39+
drop java action RenameTest.NewHelper;
2840
drop association RenameTest.Order_Client;
2941
drop entity RenameTest.client;
3042
drop entity RenameTest.Order;

mdl/ast/ast_rename.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ package ast
66
//
77
// RENAME ENTITY Module.OldName TO NewName [DRY RUN];
88
// RENAME MODULE OldName TO NewName [DRY RUN];
9+
// RENAME JAVA ACTION Module.OldName TO NewName [DRY RUN];
10+
// ... and microflow, nanoflow, page, enumeration, association, constant
911
type RenameStmt struct {
10-
ObjectType string // "ENTITY", "MODULE"
12+
ObjectType string // lowercase type key, e.g. "entity", "module", "javaaction"
1113
Name QualifiedName // Current name (Module.Entity or Module for modules)
1214
NewName string // New simple name (just the name, not qualified)
1315
DryRun bool // If true, report references without modifying

mdl/backend/java.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ type JavaBackend interface {
1818
CreateJavaAction(ja *javaactions.JavaAction) error
1919
UpdateJavaAction(ja *javaactions.JavaAction) error
2020
DeleteJavaAction(id model.ID) error
21-
WriteJavaSourceFile(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType) error
21+
WriteJavaSourceFile(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType, extraImports []string, extraCode string) error
22+
DeleteJavaSourceFile(moduleName, actionName string) error
23+
RenameJavaSourceFile(moduleName, oldName, newName string) error
2224
ReadJavaSourceFile(moduleName, actionName string) (string, error)
2325
}

mdl/backend/mock/backend.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ type MockBackend struct {
212212
CreateJavaActionFunc func(ja *javaactions.JavaAction) error
213213
UpdateJavaActionFunc func(ja *javaactions.JavaAction) error
214214
DeleteJavaActionFunc func(id model.ID) error
215-
WriteJavaSourceFileFunc func(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType) error
215+
WriteJavaSourceFileFunc func(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType, extraImports []string, extraCode string) error
216+
DeleteJavaSourceFileFunc func(moduleName, actionName string) error
217+
RenameJavaSourceFileFunc func(moduleName, oldName, newName string) error
216218
ReadJavaSourceFileFunc func(moduleName, actionName string) (string, error)
217219

218220
// WorkflowBackend

mdl/backend/mock/mock_java.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,23 @@ func (m *MockBackend) DeleteJavaAction(id model.ID) error {
6464
return nil
6565
}
6666

67-
func (m *MockBackend) WriteJavaSourceFile(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType) error {
67+
func (m *MockBackend) WriteJavaSourceFile(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType, extraImports []string, extraCode string) error {
6868
if m.WriteJavaSourceFileFunc != nil {
69-
return m.WriteJavaSourceFileFunc(moduleName, actionName, javaCode, params, returnType)
69+
return m.WriteJavaSourceFileFunc(moduleName, actionName, javaCode, params, returnType, extraImports, extraCode)
70+
}
71+
return nil
72+
}
73+
74+
func (m *MockBackend) DeleteJavaSourceFile(moduleName, actionName string) error {
75+
if m.DeleteJavaSourceFileFunc != nil {
76+
return m.DeleteJavaSourceFileFunc(moduleName, actionName)
77+
}
78+
return nil
79+
}
80+
81+
func (m *MockBackend) RenameJavaSourceFile(moduleName, oldName, newName string) error {
82+
if m.RenameJavaSourceFileFunc != nil {
83+
return m.RenameJavaSourceFileFunc(moduleName, oldName, newName)
7084
}
7185
return nil
7286
}

mdl/backend/mpr/backend.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -584,8 +584,14 @@ func (b *MprBackend) UpdateJavaAction(ja *javaactions.JavaAction) error {
584584
func (b *MprBackend) DeleteJavaAction(id model.ID) error {
585585
return b.writer.DeleteJavaAction(id)
586586
}
587-
func (b *MprBackend) WriteJavaSourceFile(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType) error {
588-
return b.writer.WriteJavaSourceFile(moduleName, actionName, javaCode, params, returnType)
587+
func (b *MprBackend) WriteJavaSourceFile(moduleName, actionName string, javaCode string, params []*javaactions.JavaActionParameter, returnType javaactions.CodeActionReturnType, extraImports []string, extraCode string) error {
588+
return b.writer.WriteJavaSourceFile(moduleName, actionName, javaCode, params, returnType, extraImports, extraCode)
589+
}
590+
func (b *MprBackend) DeleteJavaSourceFile(moduleName, actionName string) error {
591+
return b.writer.DeleteJavaSourceFile(moduleName, actionName)
592+
}
593+
func (b *MprBackend) RenameJavaSourceFile(moduleName, oldName, newName string) error {
594+
return b.writer.RenameJavaSourceFile(moduleName, oldName, newName)
589595
}
590596

591597
// ReadJavaSourceFile delegates to writer because the mpr SDK places this

mdl/executor/cmd_javaactions.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ func execDropJavaAction(ctx *ExecContext, s *ast.DropJavaActionStmt) error {
270270
if err := ctx.Backend.DeleteJavaAction(ja.ID); err != nil {
271271
return mdlerrors.NewBackend("delete java action", err)
272272
}
273+
if err := ctx.Backend.DeleteJavaSourceFile(modName, ja.Name); err != nil {
274+
return mdlerrors.NewBackend("delete java source file", err)
275+
}
273276
fmt.Fprintf(ctx.Output, "Dropped java action: %s.%s\n", s.Name.Module, s.Name.Name)
274277
return nil
275278
}
@@ -416,7 +419,7 @@ func execCreateJavaAction(ctx *ExecContext, s *ast.CreateJavaActionStmt) error {
416419

417420
// Write Java source file if code is provided
418421
if s.JavaCode != "" {
419-
if err := ctx.Backend.WriteJavaSourceFile(moduleName, s.Name.Name, s.JavaCode, ja.Parameters, ja.ReturnType); err != nil {
422+
if err := ctx.Backend.WriteJavaSourceFile(moduleName, s.Name.Name, s.JavaCode, ja.Parameters, ja.ReturnType, s.Imports, s.ExtraCode); err != nil {
420423
return mdlerrors.NewBackend("write java source file", err)
421424
}
422425
}

0 commit comments

Comments
 (0)