Causeway 4042, 4039#3660
Merged
Merged
Conversation
…bstract superclass
…nto CommandManager
…lid. Cosmetic improvements in UI
…OrRetrySelected, rename
… (StackOverflow fix) ensureNavigationActionsForMixedInAssociations() was invoked on every streamDeclaredActions(...) call with no re-entrancy guard. Synthesising a navigation action forces full introspection of the collection's element type (filterPropertiesOf -> childSpec.streamAssociations), whose post-processing re-enters this method; with a cyclic collection graph (A.coll<B>, B.coll<A>, parent/child trees, mutually-referencing view models) this recursed forever and blew the stack during metamodel loading. Route the body through a per-spec _Oneshot (navigationActionAdder), mirroring mixedInActionAdder / mixedInAssociationAdder, so a spec synthesises its navigation actions at most once and re-entrant calls short-circuit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduces a configurable strategy for synthesising the synthetic navigation
("selector") actions for parented collections / scalar references, selected via
causeway.extensions.command-log.navigation-action-synthesis = INLINE | POST_PROCESS
INLINE (default): the original behaviour, preserved. Own collections are
synthesised eagerly during introspection (ObjectSpecificationDefault) and
mixed-in collections lazily via ensureNavigationActionsForMixedInAssociations()
(now re-entrancy-guarded by the navigationActionAdder one-shot).
POST_PROCESS: a dedicated MetaModelPostProcessor
(SynthesizeNavigationActionsPostProcessor, registered A0_BEFORE_BUILTIN so the
synthesised actions still receive downstream facet post-processing) synthesises
both own and mixed-in navigation actions once per type. This keeps synthesis out
of the lazy streamDeclaredActions path, so it no longer forces re-entrant
element-type introspection during ordinary action access — the root cause of the
StackOverflow on cyclic collection graphs.
- ObjectSpecificationAbstract: extract shared addNavigationActions(Stream); gate
inline path behind !isNavigationActionPostProcessing(); add public
synthesizeNavigationActions() entry point for the post-processor.
- ObjectSpecificationDefault: read strategy from config; skip eager synthesis in
POST_PROCESS mode; override isNavigationActionPostProcessing().
Default is unchanged (INLINE); existing navigation/recording tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…per-spec (not via isEnabled) Adds SynthesizeNavigationActionsPostProcessorTest, parameterised over both NavigationActionSynthesis strategies (INLINE, POST_PROCESS), asserting that each produces the synthetic navigation action for own, mixed-in, and mutually-cyclic parented collections. Also drops the post-processor's isEnabled() override: PostProcessor.init() snapshots enabledPostProcessors via isEnabled() once, which (a) is fragile w.r.t. when the pipeline is initialised relative to configuration and (b) prevented the post-processor from running in the unit-test harness. Gating is now performed per-type, live from configuration, inside ObjectSpecificationAbstract .synthesizeNavigationActions() (recording-support + POST_PROCESS), so the post-processor stays in the pipeline and no-ops cheaply under INLINE. Note: the unit-test harness (loadSpecification) does not run the post-process sweep, so the test invokes the post-processor as the production sweep would; the end-to-end StackOverflow regression on a cyclic graph is left for a full-boot integration test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sis; fixes stale-snapshot in INLINE
Adds RecordingNavigation_{inline,postProcess}_IntegTest (regressiontests/domainmodel):
boots the framework with command-log recording-support enabled over a domain whose two
view models reference each other via mixed-in parented collections (a cycle), under each
NavigationActionSynthesis strategy. Reaching the test body at all proves the metamodel was
created without recursing without bound during boot (the original StackOverflow); the
assertions further confirm the navigation actions are synthesized for own and mixed-in
(cyclic) collections.
Booting the cyclic domain surfaced a latent bug in the INLINE path: it sourced candidate
associations from the unmodifiableAssociations _Lazy snapshot, captured *before*
addNavigationActions() triggered mixed-in association materialization. On a cyclic graph the
mixed-in collection was therefore not yet present in the snapshot, so its navigation action
was silently omitted (no crash, thanks to the one-shot guard, but missing). Fixed by sourcing
candidates via streamDeclaredAssociations(MixedIn.INCLUDED), which materializes first and reads
fresh - matching the POST_PROCESS path. Non-cyclic behaviour is unchanged; metamodel unit tests
still pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…SS is now the only path
The inline strategy could still recurse to a StackOverflow during metamodel loading on real
domains (synthesis hangs off the lazy streamDeclaredActions path and forces re-entrant
element-type introspection); the post-processor strategy does not. So drop INLINE entirely and
always synthesize the synthetic navigation ("selector") actions via
SynthesizeNavigationActionsPostProcessor, once per type, during the post-processing phase.
- CausewayConfiguration: remove the navigation-action-synthesis property and NavigationActionSynthesis
enum. Synthesis is now governed solely by causeway.extensions.command-log.recording-support.
- ObjectSpecificationAbstract: remove ensureNavigationActionsForMixedInAssociations() and its call
from streamDeclaredActions, and isNavigationActionPostProcessing(); synthesizeNavigationActions()
is now gated only by recording-support (still one-shot, over streamAssociations(INCLUDED)).
- ObjectSpecificationDefault: remove the eager own-collection synthesis block and the strategy field/
override; introspectTypeHierarchy just creates regular actions and lets the post-processor add the
navigation actions.
- SynthesizeNavigationActionsPostProcessor: javadoc updated (sole mechanism, recording-support gated).
Tests:
- ParentedCollectionNavigationActionUtilTest / ScalarReferenceNavigationActionUtilTest: synthesis no
longer happens during loadSpecification in the unit harness (no post-process sweep), so invoke it
explicitly via a withNavigationActions(spec) helper after loading.
- SynthesizeNavigationActionsPostProcessorTest: de-parameterized (single behaviour).
- RecordingNavigation integ tests: collapsed the two strategy variants into one
RecordingNavigation_IntegTest (boots with recording-support enabled over the cyclic domain).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SynthesizeDomainEventsForMixinPostProcessor no longer mutates the shared mixin FacetedMethod when applying mixee/domain-object domain-event defaults. Instead, it installs object-type-specific local overlay facets onto the mixed-in member, so each contributed member can shadow the shared default without polluting other mixees. For actions, it also installs a local ActionInvocationFacetForAction overlay because action execution reads the event holder from the invocation facet. ObjectActionMixedIn now invokes through that local invocation facet when present, while preserving the existing shared delegation path otherwise. The same local-overlay approach is applied for action, property, and collection domain-event facets. Synthetic navigation actions remain domain-event neutral and keep their ids, semantics, invocation, and command publishing behavior unchanged. Validation: focused core/metamodel tests and RecordingNavigation_IntegTest passed with Java 21; OpenSpec validation passed; mvnd clean install confirmed separately.
…nstead handle replay error and return success
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.