refactor(generation): the model-to-code pipeline is Java only - #6707
Conversation
| // A model or template that is not there, a template declaring no sources, an unsupported | ||
| // template, a model the template cannot compile (an unparseable mapping criteria): all | ||
| // things the caller asked for wrongly, reported rather than generated incompletely. | ||
| logger.warn("Failed to generate [{}] of project [{}] with template [{}]", path, project, parameters.getTemplate(), e); |
| modelGenerationService.generate(workspaceName, projectName, path, templateId, parameters); | ||
| entry.put("generated", Boolean.TRUE); | ||
| } catch (IOException | RuntimeException e) { | ||
| LOGGER.error("Failed to generate code from [{}/{}] with template [{}]", projectName, path, templateId, e); |
| String text = str(column, "scale"); | ||
| if (text != null && NUMERIC.matcher(text) | ||
| .matches()) { | ||
| double value = Double.parseDouble(text); |
On the CodeQL runI went through all 19 alerts. Four are this PR's to answer; the rest are pre-existing flows the migration made visible. Fixed (pushed in a914273):
Left alone deliberately — the other 14 Reaching them needs a caller already authenticated as One thing the noise did surface, worth its own issue: |
Completes GENERATION_UTILS_JAVA_PLAN.md PRs 2 and 3: every consumer now
generates through the Java pipeline, and the JavaScript one is deleted.
- POST /services/ide/generate/model/{workspace}/{project}?path= on
GenerationEndpoint, body {template, parameters} - the contract the
JavaScript endpoint had, so every caller was a URL swap.
- The GenerateService provider builds both its URLs from
/services/ide/generate, so editor-entity, editor-form-builder,
editor-report and view-projects followed with no change of their own.
- The intent Generate is ONE call: IntentGenerationService runs the
.settings recipes itself after writing the model files, and each
codeGenerations entry comes back carrying its own outcome (generated,
plus error when it failed). A failure is isolated to its entry - the
model files are already on disk, so a template that cannot render is a
partial result to report, not a reason to fail the whole Generate. The
replay loops in editor-intent and in the Builder pipeline are gone.
- template-mapping-java's generate() was a compiler rather than
marshalling, and was the one template the Java pipeline refused by name;
it is now MappingCompiler (+ MappingCompilerTest), so deleting the
JavaScript path does not silently take .mapping generation with it.
- Deleted generate.mjs, generateUtils.js and parameterUtils.js, and the
generate() export of all nine template modules. Their getTemplate()
descriptors stay, and so does the read-only templates.js listing them:
the descriptors are still JavaScript, so a Java list service over them
would add a second GraalJS path rather than remove one (plan §7.3).
- GenerationParityIT had no oracle left once the second pipeline went, so
it is now ModelGenerationIT, asserting what that oracle protected: every
template renders, renders the same thing twice, produces its descriptor
free of keys an engine added to the parameter graph, and really merges a
cross-project entity extension. A mapping case joined it.
Verified: full reactor build; 410 unit tests in the touched modules;
ModelGenerationIT 13/13; IntentEngineIT (generate, glue, report-file,
setField) 4/4; IntentEditorLoadsIT + IntentBuilderShellIT 4/4;
formatter:validate and javadoc -P release clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Of the 19 CodeQL alerts on the migration, four are this PR's to answer; the rest are pre-existing flows the migration made analyzable (the same user data reached the same ide-workspace log lines through generate.mjs, where taint tracking could not follow it through GraalJS). - JavaScriptJson wrote an integral double with a (long) cast, which reads as an unbounded narrowing of request data even though the branch above bounds it. Math.round behind a named MAX_INTEGRAL says "the integral value" instead, and saturates rather than wrapping if that guard is ever relaxed. Identical output - JavaScriptJsonTest pins it. - The three log statements this PR owns sanitize their request-derived values with the sanitizeForLog idiom JavaEndpoint already uses, so a crafted workspace, project or model path cannot forge a log line. - MappingCompiler read a text scale through Double.parseDouble behind a regex; a digits-only match plus Integer.parseInt in a try says the same thing without the fragile pattern. Left alone deliberately: the 14 log-injection alerts in ide-workspace (PublisherService, ActionsService, ProjectActionsPublisherHandler). They are three files this PR does not touch, reachable only by a caller who is already authenticated as DEVELOPER or ADMINISTRATOR and can write workspace files directly - worth their own change rather than sprawl here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
a914273 to
ca479ec
Compare
Completes
GENERATION_UTILS_JAVA_PLAN.mdPRs 2 and 3. PR 1 landed the Java port plus a byte-for-byte parity harness with both paths live and no consumer switched; this switches every consumer to the Java pipeline and deletes the JavaScript one.What moves
POST /services/ide/generate/model/{workspace}/{project}?path=<model>on the existingGenerationEndpoint, body{template, parameters}. The plan's{*path}was dropped in favour of the?path=query the JavaScript endpoint already used, so every caller was a base-URL swap. It answers201as before, and maps an absent model/template, a template with no sources, an unsupported template and a model a template cannot compile to400.GenerateServiceprovider now builds both its URLs from/services/ide/generate, so editor-entity, editor-form-builder, editor-report and view-projects follow with no change of their own.IntentGenerationServiceruns the.settingsrecipes itself after writing the model files, and eachcodeGenerationsentry comes back carrying its own outcome (generated, pluserror). A failure is isolated to its entry: the models are already on disk, so a template that cannot render is a partial result to report, not a reason to fail the whole Generate. The replay loops in editor-intent and in the Builder's publish pipeline are gone; both read the report.template-mapping-javais ported — itsgenerate()was a compiler (criteria parsed into typed Java comparisons, a value expression per source kind, the mapper class name), and it was the one template the Java pipeline refused by name. It is nowMappingCompiler. Without this, deleting the JavaScript path would have silently taken.mappinggeneration with it.What is deleted
generate.mjs,generateUtils.js(1,896 lines) andparameterUtils.js(649 lines), plus thegenerate()export of all nine template modules — theirgetTemplate()descriptors stay. Comments across the repo that pointed at the deleted files now name the Java classes that replaced them.Deliberately kept: the read-only
service-template/api/templates.jsthat lists the templates. The plan defaulted to porting it, but the premise changed: template descriptors are still JavaScript modules (plan §1.1) and the Java pipeline reads them throughGenerationService.getTemplateMetadata, which boots a JavaScript context per template — so a Java list service over JavaScript descriptors would add a second path to that boot rather than remove one. It goes when the descriptors do. Reasoning recorded in the plan's new §7.3.Tests
GenerationParityITcompared the two pipelines byte for byte; with one pipeline left there is no oracle, so it becomesModelGenerationITand asserts what that oracle protected: every template renders, renders the same thing twice, produces its.gendescriptor free of keys an engine added to the parameter graph (the §6.4 Mustache-mutation finding, which would otherwise accumulate in a committed file), and really merges a cross-project entity extension. A mapping case joined it with the compiler port.Verified locally:
mvn -T 1C clean install -P quick-build(311 modules, fat jar)MappingCompilerTest)ModelGenerationIT(13 cases)IntentEngineIT— generate / glue / report-file / setFieldIntentEditorLoadsIT+IntentBuilderShellIT(browser)formatter:validate,javadoc -P releaseon touched modulesNot covered by a run: the four AngularJS editors' Generate goes through the provider function this PR re-points, and their coverage lives in the full UI suite rather than the smoke set. The change there is a URL swap onto an endpoint with the same request and response contract, but the nightly is what will exercise it.
🤖 Generated with Claude Code