Skip to content

templates: escape an authored check/guard/unique/refuse message into the Java literal it lands in (#7241) - #7262

Merged
iliyan-velichkov merged 3 commits into
masterfrom
issue-7241-escape-authored-messages
Sep 10, 2026
Merged

templates: escape an authored check/guard/unique/refuse message into the Java literal it lands in (#7241)#7262
iliyan-velichkov merged 3 commits into
masterfrom
issue-7241-escape-authored-messages

Conversation

@iliyan-velichkov

Copy link
Copy Markdown
Contributor

Cause

#7205 (#7154) introduced JavaLiterals.escape / defaultValueExpression and wired it into exactly one site — the authored dataDefaultValue. Every other authored string the templates write into a Java string literal was still interpolated verbatim, so a " or a \ in one ended that literal and failed javac for the whole generated module, not merely the class carrying the message:

template literal
template-application-dao-java Repository.java.template throw new ValidationException("${guard.message}") and the three "${check.message}" document gates
template-application-rest-java Entity{,My,Partner}Controller.java.template the three row-check "${check.message}" refusals and messages.put("${uniqueConstraint.name}"…, "${uniqueConstraint.message}")
template-application-events-java Generate.java.template "${itemRefuse} (${fromItemEntity} " + unqualified + ")"

A message in the shape the DSL's own issues suggest — message: 'A "due" date is never before the invoice date' — therefore took every entity of the module down, at publish, in the Problems view, and nothing in the parser refused it.

Change

ModelParameterProcessor already walks the checks it splits into rowChecks / guardChecks / documentChecks; it now puts an escaped twin on each check map (messageJavaLiteral) and on each unique constraint (messageJavaLiteral + nameJavaLiteral), and GlueGenerator does the same for itemRefuse (itemRefuseJavaLiteral). The templates read the twin at the Java sites only — the raw value stays in place for the surfaces that render it as text, which is why the twin was preferred over escaping in place (uniqueConstraint.name is also written into the .schema JSON). A holder carrying no message is left without a twin rather than an empty one, exactly as dataDefaultValueJavaLiteral is: the key's absence is what a template reads.

The .edm XML (escapeXmlText / escapeXml) and the .model JSON (JsonHelper.toJson) already escape these values, so the defect and the fix are confined to the Java emission.

Verification

  • mvn -T 1C formatter:validate over the reactor with every formatter-maven-cache.properties deleted first — BUILD SUCCESS.
  • mvn -pl components/ide/ide-template -am test — green, including two new ModelParameterProcessorTest cases: one pinning the escaped twins of a row check, a guard, a document check and a unique key (quote and backslash), one pinning that a holder with no message gets no twin.
  • IntentEmissionCoverageIT — green. Its fixture now carries a quote in all five families: a document check (itemsMin), a row check (compare), a unique key, a guard and a create-from refuse:. The IT generates, publishes, compiles and runs the module, and asserts both halves: the escaped form in the emitted source, and the authored form in the runtime message the caller is answered with (.body("message", containsString(…)) on the two 400s).
  • The pin bites: with the DAO template reverted to ${check.message} the IT fails on the new assertion; restored, it is green again.
  • mvn -P release … javadoc build on components/ide/ide-template — BUILD SUCCESS.

Not verified: the rest of the integration suite, and the PostgreSQL leg.

Siblings, not addressed here: #7206 (the .schema JSON), #7207 (JS).

Fixes #7241

🤖 Generated with Claude Code

iliyan-velichkov and others added 3 commits September 9, 2026 17:13
…the Java literal it lands in (#7241)

#7205 (#7154) added JavaLiterals.escape and wired it into exactly one site - the authored
dataDefaultValue. Every other authored string the templates write into a Java string literal
was still interpolated verbatim, so a quote or a backslash in one ended that literal and failed
javac for the WHOLE generated module, not just the class carrying the message: the repository's
guard and document checks, the row checks and unique-key messages of all three controllers, and
a create-from's items refusal. A message in the shape the DSL's own examples suggest - `A "due"
date is never before the invoice date` - therefore took every entity of the module down, at
publish, in the Problems view.

ModelParameterProcessor now puts an escaped twin on every check map it already walks
(messageJavaLiteral, reaching the row / guard / document lists alike) and on each unique
constraint (messageJavaLiteral + nameJavaLiteral), and GlueGenerator does the same for
itemRefuse; the raw value stays for the surfaces that render it as text, and only the Java sites
read the twin. A holder carrying no message is left without a twin, as the default-value literal
is - the key's absence is what a template reads. The .edm XML and the .model JSON already escape
these values, so the fix is confined to the Java emission.

Verified: mvn formatter:validate over the reactor with the caches wiped; the ide-template unit
suite (two new ModelParameterProcessorTest cases pinning the twins and their absence);
IntentEmissionCoverageIT, whose fixture now carries a quote in a document check, a row check, a
unique key, a guard and an items refusal - it generates, compiles and RUNS the module, and
asserts both the escaped form in the emitted source and the authored form in the runtime message
the caller is answered with. With one template site reverted to the raw value the IT fails on
that assertion, so the pin bites. The release-profile javadoc build passes on ide-template.

Not verified: the rest of the integration suite, and PostgreSQL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… twin (#7241)

Two template ITs build the parameter map by hand rather than through
ModelParameterProcessor, so they kept the pre-#7241 shape and rendered an
empty message at the Java site:

- PersonalSurfaceCreateValidationTemplateIT's row check now carries
  `messageJavaLiteral` alongside the raw message.
- UniqueFieldConflictControllerTemplateIT's composite key now carries
  `nameJavaLiteral` + `messageJavaLiteral`, and its authored message
  QUOTES the field it is about - the shape the defect is about. That test
  compiles and runs the rendered mapping, so the fixture is a real pin,
  not a restatement: with the controller template reverted to
  `${uniqueConstraint.message}` the extracted mapping fails to compile,
  and with the twin restored it is green again.

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

# Conflicts:
#	tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/IntentEmissionCoverageIT.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

2 participants