Skip to content

templates: seven more authored strings reach a generated Java literal escaped, through one shared escape (#7295) - #7341

Merged
delchev merged 2 commits into
masterfrom
issue-7295-java-literal-escape
Sep 12, 2026
Merged

templates: seven more authored strings reach a generated Java literal escaped, through one shared escape (#7295)#7341
delchev merged 2 commits into
masterfrom
issue-7295-java-literal-escape

Conversation

@delchev

@delchev delchev commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Cause

#7262 routed four message families (checks, guards, unique, refuse) through JavaLiterals.escape, and its own body said: "Every other authored string the templates write into a Java string literal was still interpolated verbatim." That was still true at seven more sites:

authored source template site
entity label: pattern literal segments + formats Repository.java.template label.append("${part.text}")
setField step value: SetField.java.template updateProperty(..., "${value}")
report parameter initial: reportFileEntity.java.template value(filter, ..., "${parameter.initial}")
field description: Entity.java.template @Documentation("${property.description}")
number: { series: ... } Repository.java.template + Numbering.java.template allocator calls
seeded status names, joined id=name, Repository.java.template "${lifecycleStatusNames}".split(",")
cron, destination, path Job / InboundFile / InboundMessage / Outbound / Webhook templates

A description: Customer's "trade" name, a setField value with a quote or a report initial: O'Neil "the" note ends the literal it is written into. The client Java batch is all-or-nothing, so one authored quote fails the javac of every generated class of the module — the #7241 / #7154 class of defect.

Change

Each site renders from an escaped twin derived once, where every other model value is derived — so a hand-authored .edm / .glue gets the same treatment as an intent-generated one:

  • ModelParameterProcessordescriptionJavaLiteral, numberSeriesJavaLiteral, and per label part textJavaLiteral / formatJavaLiteral.
  • GlueGenerator — one copyJavaLiterals(...) for a setter's value, a numbering series / perDefault, a schedule and inbound-file cron, an inbound-message and outbound destination, a webhook path. A key the descriptor does not carry is removed rather than emptied, so a template's #if reads its absence exactly as before.
  • the report adapter — initialJavaLiteral.

The raw values stay for the surfaces that render them as text (a form's description paragraph, the diagram, the editor).

The seeded status names were the one site an escape alone could not fix. They travelled as a single id=name, join the generated repository split apart at class-init time, so a comma in a name shifted every entry after it — silently. They are now carried structurally (lifecycleStatusNameList, a structured .edm attribute transform-edm.js parses back) and emitted as one escaped names.put(...) per pair. A .model written before this still carries the join and is read back by the parameter pass, so nothing regenerates differently for a name that never held a separator.

...and the helper stopped multiplying

Every hand-rolled copy of the loop now calls JavaLiterals.escape (or JsLiterals.escape for its JavaScript twin): NotificationSupport.quote, ScheduleSupport, IntegrationSupport, four in GlueIntentGenerator, MappingCompiler.javaString, and widgetPatternJava / widgetPatternJs / widgetOptionsFilterValueJs in ModelParameterProcessor.

The copies were not identical, which is the argument for the shared one: one dropped a carriage return, several escaped neither the newline nor the control characters, and a lone CR used to survive raw into a mapping literal and break its line.

Verification

  • IntentEmissionCoverageIT — the fixture now carries a quote in a label pattern (the "{note}" ({Person.name}) {period|yyyy MMMM}), a field description, a setField value and a new report's parameter initial, so the generated module is javac'd and published with them. The assertions name the escaped value each site wrote, and the runtime Name assertions read the quotes back off the stored display name. Green (270 s).
  • ModelGenerationIT + IntentEngineIT — 81 tests, green.
  • ide-template + engine-intent unit suites green, with new coverage for each derivation and for the structured-vs-joined status names.
  • mvn formatter:validate green with the cache wiped; the release javadoc profile builds both modules clean.

Not verified: the full IT suite, and no PostgreSQL run — nothing here touches SQL.

Fixes #7295

🤖 Generated with Claude Code

delchev and others added 2 commits September 11, 2026 15:38
… escaped, through one shared escape (#7295)

#7262 routed four message families through JavaLiterals.escape and its body said
every other authored string was still interpolated verbatim. It was, at seven
more sites: an entity `label:` pattern's literal segments and formats, a
`setField` step's `value:`, a report parameter's `initial:`, a field
`description:` (the entity's @documentation argument), a `number:` series name,
the seeded status names a lifecycle refusal quotes, and the `cron` / `destination`
/ `path` a job, a listener and a webhook declare. A `description: Customer's
"trade" name` or a `setField` value with a quote ends the literal it is written
into and fails the javac of the WHOLE generated module - the client Java batch is
all-or-nothing, so one authored quote takes every generated class with it.

Each site now renders from an escaped twin derived once, where every other model
value is derived: ModelParameterProcessor for the property and label values,
GlueGenerator for the glue descriptors, the report adapter for a parameter's
initial. The raw values stay for the surfaces that render them as text.

The seeded status names were the one site an escape alone could not fix: they
travelled as a single `id=name,` join that the generated repository split apart
at class-init time, so a comma in a name shifted every entry after it. They are
now carried structurally (`lifecycleStatusNameList`, a structured .edm attribute
transform-edm parses back) and emitted one escaped put() per pair; a .model
written before this still carries the join and is read back, so nothing
regenerates differently for a name that never held a separator.

And the helper stopped multiplying: every hand-rolled copy of the loop -
NotificationSupport, ScheduleSupport, IntegrationSupport, four in
GlueIntentGenerator, MappingCompiler, and widgetPatternJava/widgetPatternJs in
ModelParameterProcessor - now calls JavaLiterals.escape (or JsLiterals.escape).
The copies were not identical: one dropped a carriage return, several escaped
neither the newline nor the control characters, and a lone CR used to survive raw
into a mapping literal and break its line.

Verified: IntentEmissionCoverageIT's fixture carries a quote in a label pattern,
a field description, a setField value and a report parameter initial, so the
generated module is javac'd and published with them, and the assertions name the
escaped value each site wrote; the runtime label assertions read the quotes back
off the stored display name. ide-template + engine-intent unit suites, plus
ModelGenerationIT and IntentEngineIT (81 tests), green. formatter:validate green
with the cache wiped; the release javadoc profile builds both modules clean.

Fixes #7295

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eral-escape

# Conflicts:
#	components/ide/ide-template/src/main/java/org/eclipse/dirigible/components/ide/template/service/model/GlueGenerator.java
@delchev
delchev merged commit e635e16 into master Sep 12, 2026
9 of 10 checks passed
@delchev
delchev deleted the issue-7295-java-literal-escape branch September 12, 2026 05:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant