Skip to content

refactor: migrate Xtend to Java - com.avaloq.tools.ddk.xtext.scope - #1519

Merged
joaodinissf merged 3 commits into
masterfrom
migrate/xtend-to-java/scope-step-3
Sep 8, 2026
Merged

joaodinissf merged 3 commits into
masterfrom
migrate/xtend-to-java/scope-step-3

Conversation

@joaodinissf

Copy link
Copy Markdown
Collaborator

Summary

Migrates the three remaining legacy Xtend sources of com.avaloq.tools.ddk.xtext.scope to Java 21:

  • generator/ScopeProviderX — scope/rule/injection/extension collection helpers and the isEqual dispatch family
  • generator/ScopeNameProviderGenerator — name-function bodies
  • generator/ScopeProviderGenerator — scope-provider method bodies, global caches, rule blocks

With this, the last 2017-era Xtend in the repository is gone; the remaining .xtend files are the Xbase inferrer layer in jvmmodel/, so the Xtend build infrastructure (xtend-gen, .classpath, build.properties) is untouched.

Stacked on the xtext.export migration.

Public API is unchanged. The consumers are ScopeJvmModelInferrer.xtend (configure(...), the doGet*Body/doGlobalCache*Body/scopeMethodBody/internalGetNameFunctionsBody template methods, scopeMethodName) and ScopeExpressionTranslator.xtend (allExtensions). They compile unchanged against the Java.

Faithfulness notes

  • All 15 templates keep the compiler's exact StringConcatenation call sequence. Eleven cannot be rebuilt on StringBuilder/text blocks under the migration skill's §4.8 (two-arg append(value, indent) of multi-line values, appendImmediate separator loops, whitespace-retracting newLineIfNotEmpty after indent-only lines); the other four are kept on the same idiom because sibling templates two-arg-append their output. The full append sequence was diffed mechanically against the compiler output: 407 operations, identical order and literals. StringConcatenation lives in org.eclipse.xtext.xbase.lib and needs no Xtend compiler.
  • Dispatchers keep the compiler's branch order and terminal behaviour: the 8-way isEqual(EObject, EObject) including its Void-typed null routing; scopeType, nameFunction, scopeExpression, factoryArgument, scopeExpressionPart, scopeExpressionNaming, isEmptyList with their IllegalArgumentException("Unhandled parameter types: …") terminals.
  • Collection ordering preserved (toSet → LinkedHashSet, stable sortBy, insertion-ordered filterUniqueRules): these sets drive the emitted case labels and method bodies.
  • The non-@Inject extension GenModelUtilX fields become plain private fields assigned in configure(...); signatures unchanged. org.eclipse.xtext.xbase.lib.Pair is kept where ScopeExpressionTranslator.newCompilationContext demands it.
  • error(...) and the single-global-rule guard still throw raw RuntimeException (PMD-suppressed with // NOPMD, as at the existing production sites) rather than a narrower type, to keep the thrown type identical.
  • CPD reports four intra-file duplications in the two template generators (the parallel by-reference/by-type and global-cache bodies, the FeatureCall/OperationCall name functions); they mirror the Xtend structure and are baselined with file-scoped CPD-OFF markers, as for the migrated ANTLR generators.
  • Documented, output-neutral deviations: an unreachable if (d == null) branch on a filter result dropped; nine private helpers factor out model filtering the compiler inlined; Guava/xbase.lib helper calls replaced by stdlib equivalents with the same order; type.cast instead of an unchecked cast; explicit StringBuilder capacity; configure parameters renamed for Checkstyle HiddenField; parameters documented as @param it keep that name.

Known deltas

  • The Xtend compiler stamped @XbaseGenerated on the generated dispatchers; the migrated Java does not. The annotation is runtime-retained on public methods in an exported package, so it is a reflectively observable delta — but nothing in the target platform reads it (only JvmModelGenerator emits it), and re-applying a "machine-generated" marker to hand-written code would be false.

Verification

  • Ground truth: fresh xtend-gen from a clean build of the base commit.
  • Two independent translations were produced and reconciled against the compiler output. One fidelity-relevant discrepancy surfaced and was resolved in favour of the compiler output: the other translation had narrowed the two raw RuntimeException throws to IllegalStateException, which the bytecode comparison caught. All other differences were style.
  • Bytecode comparison against the compiler's classes: public/protected API identical across all three classes; per-method string constants identical; StringConcatenation append/newLine sequences identical; dispatcher branch order identical.
  • Gates: -amd compile ✅; pmd:check checkstyle:check spotbugs:check ✅; full reactor clean verify with the CI static-analysis goals ✅ (354 tests, 0 failures, 2 skipped). No version bump needed: the bundle is already at 17.3.3, ahead of the baseline.

🤖 Generated with Claude Code

rubenporras
rubenporras previously approved these changes Sep 7, 2026
rubenporras
rubenporras previously approved these changes Sep 8, 2026
rubenporras
rubenporras previously approved these changes Sep 8, 2026
Base automatically changed from migrate/xtend-to-java/export-step-2 to master September 8, 2026 07:52
joaodinissf and others added 3 commits September 8, 2026 09:52
…/2: rename sources)

Pure `git mv` of the three generator sources from .xtend to .java with
their content unchanged, so Git's rename detection traverses the edge at
100% similarity and `git log --follow` / `git blame` keep connecting the
.java history to its Xtend past.

This commit intentionally does not compile: the renamed files still hold
Xtend syntax. The following commit rewrites them in place to Java 21.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…/2: translate to Java 21)

In-place translation of the three renamed generator sources, faithful to
the Xtend compiler's own xtend-gen output (freshly rebuilt off the base
commit and byte-verified against it before any edit).

All 15 templates keep the reference's exact StringConcatenation call
sequence (tier 4, chain retained rather than rebuilt on StringBuilder).
Eleven of them are unconvertible under rules/04-templates.md 4.8 -
two-arg append(value, indent) of provably multi-line values
(scopeRuleBlock, scopeExpression, nameFunctions, javaExpression),
appendImmediate separator loops (nameFunctions, query,
scopeExpressionPart) and whitespace-retracting newLineIfNotEmpty after
an indent-only line (doGlobalCache*, scopeExpression(ScopeDelegation)).
The remaining four are kept on the same idiom so that sibling templates
which append each other's output stay delimiter- and indent-consistent.
The full append sequence of both emitters was diffed against the
reference mechanically: 407 builder operations, identical in order,
per method, with identical literal arguments.

Per-file notes:
- ScopeProviderX: every public dispatcher keeps the reference's branch
  order and terminal behaviour, including the (Void) null routing of
  isEqual/allScopeRules/allScopes/allInjections/allExtensions and the
  IllegalArgumentException scopeType falls through to. Collection
  semantics preserved: toSet is a LinkedHashSet (filterUniqueRules, the
  name sets the case labels are emitted from), the result lists that
  removeIf/addAll run on stay mutable ArrayLists, and sortedRules keeps
  delegating to ScopingGeneratorUtil.
- ScopeNameProviderGenerator / ScopeProviderGenerator: the non-@Inject
  extension fields become plain private fields assigned in configure;
  the configure signatures are unchanged. org.eclipse.xtext.xbase.lib.Pair
  is kept where ScopeExpressionTranslator.newCompilationContext demands
  it in its parameter type.
- Guard expression, scope method and global-cache bodies emit the same
  Java as before; ordering-sensitive iteration (allScopes, allScopeRules,
  sortBy, filterUniqueRules) is unchanged, so the emitted case labels and
  method bodies keep their order.

Gate-driven deviations from the reference, all output-neutral:
- error(...) and the "only one global rule allowed" guard still throw
  RuntimeException; the raw type is marked // NOPMD, matching the four
  existing prod sites in this repo.
- scopeMethodBody gains an @throws tag for that RuntimeException
  (checkstyle JavadocMethod requires it on a documented method).
- configure's parameters are renamed (nameGenerator, genModelUtilX) to
  clear checkstyle HiddenField; the Javadoc text is otherwise verbatim.
- _isEqual(EClass)/_isEqual(EReference) share a haveSameName helper and
  _isThisCall uses a guard clause, to satisfy BooleanExpressionComplexity
  without changing short-circuit order.

Further deviations from the reference, all output-neutral:
- collectAllScopeRules: the reference's `if (d == null)` branch on the
  filter(...) result was dropped as unreachable (IterableExtensions.filter
  never returns null); same list, same order.
- Nine private helpers factor out repeated model filtering the compiler
  inlined (haveSameName, newContext, scopesWithReference, scopeNames,
  namedScopes, globalRules, ruleContextType, dataOfType, reversed); pure
  functions evaluated at the same points, no public/protected surface added.
- Guava/xbase.lib calls replaced by stdlib (Lists.newArrayList +
  ListExtensions.reverse -> reversed, Iterables.filter(..., T.class) ->
  dataOfType, Iterables.concat/addAll -> loops); order and element identity
  preserved.
- eContainer uses type.cast(it) instead of the unchecked (T) it, guarded by
  the preceding isInstance check.
- new StringBuilder(512) where the reference had the default capacity.
- Parameters named `it` in the reference are kept as `it` (their preserved
  Javadoc documents @PARAM it); every call on them is qualified.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
cpd-check finds four intra-file duplications in ScopeProviderGenerator
and ScopeNameProviderGenerator: the by-reference/by-type scope bodies,
the global-cache bodies and the FeatureCall/OperationCall name functions
are parallel templates in the Xtend source, and the faithful Java keeps
that structure. Baselined with file-scoped CPD-OFF markers, as for the
migrated ANTLR generators (a68a240) and FormatJvmModelInferrer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@joaodinissf
joaodinissf merged commit 7f85ceb into master Sep 8, 2026
4 checks passed
@joaodinissf
joaodinissf deleted the migrate/xtend-to-java/scope-step-3 branch September 8, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants