65 lines
9.1 KiB
Markdown
65 lines
9.1 KiB
Markdown
# Generated Java ViewModels and registry defaults
|
|
|
|
The existing Model processor now optionally generates Java subclasses from the same `ModelMetadata` descriptions used by discovery. Generated accessors use NeitzelLib's stored Attribute properties; they do not create another property map or identity registry. Both hosts discover the configured default ViewModel from the compiled registry without executing providers, and Build and Refresh runs the configured generator in the application build.
|
|
|
|
## Configure the application build
|
|
|
|
Keep Model selections, generated package and hand-written defaults in the application module's checked-in compiler configuration, alongside the [metadata processor path](generated-model-metadata.md):
|
|
|
|
```xml
|
|
<compilerArgs>
|
|
<arg>-Adesigner.models=com.example.Person,com.example.Employee</arg>
|
|
<arg>-Adesigner.viewModels=true</arg>
|
|
<arg>-Adesigner.viewModelModels=com.example.Person,com.example.Employee</arg>
|
|
<arg>-Adesigner.generatedPackage=com.example.generated</arg>
|
|
<arg>-Adesigner.viewModelDefaults=com.example.Person=com.example.CustomPersonViewModel</arg>
|
|
</compilerArgs>
|
|
```
|
|
|
|
`viewModelModels` selects the generated subset of metadata Models; unknown selections fail compilation, and nested canonical class names are normalized; when omitted, it uses `designer.models`. `viewModelDefaults` is optional; a Model otherwise defaults to its generated class. Use a distinct generated package per participating module. The module must depend on the qualified NeitzelLib FX runtime. The processor remains a build dependency; runtime applications do not depend on designer hosts or target tooling.
|
|
|
|
Output goes to Maven's `target/generated-sources/annotations`, with names such as `PersonViewModel`. Hand-written subclasses remain ordinary source files and can extend the generated superclass in a clean compilation. Generated classes have a concrete Model constructor, typed `nameProperty()`, `getName()` and `setName(...)` methods. String/numeric/boolean properties use the runtime's specialized JavaFX classes. Complex Attributes expose typed child ViewModels, while known collections expose observable lists of Model elements. Existing runtime null, collection-setter and write-back semantics remain in force.
|
|
|
|
Generation includes available source ancestors and nested Models, visits cycles once, and preserves safe generated superclass APIs. Incompatible writable narrowing, name collisions, reserved runtime APIs, unsupported generic Model declarations and custom BeanInfo mappings are diagnosed. A nested complex type without an available generated mapping is rejected rather than exposed with an incorrect Model-valued accessor. Cross-module nested-generation mapping and broader generic/BeanInfo configurations remain outside this qualified slice.
|
|
|
|
Lombok accessor generation is tested with either processor ordering. A compiler source round allows accessors to complete; compiler source-tree ownership prevents test/dependent compilations from duplicating main-source registries. Clean builds remove obsolete generated sources, classes and resources. Removing an Attribute makes custom references fail compilation; the generator does not rewrite custom source. Build and Refresh already uses clean isolated builds and immutable snapshots. External incremental builds must clean after selection changes/removals.
|
|
|
|
## Runtime registry and selection
|
|
|
|
Each participating module generates `GeneratedViewModelRegistry`, a marker service with repeatable `ViewModelRegistration` annotations naming the Model, generated base and selected default. A generated compile-time assignment checks that a custom default extends its generated base. Classpath builds package the service descriptor automatically.
|
|
|
|
Named modules must declare the generated provider and make generated constructors accessible, for example:
|
|
|
|
```java
|
|
provides de.neitzel.fx.view.ViewModelRegistry
|
|
with com.example.generated.GeneratedViewModelRegistry;
|
|
exports com.example.generated;
|
|
opens com.example.generated to fx;
|
|
```
|
|
|
|
Existing Model and Controller access requirements still apply. Both classpath and named-module fixtures are qualified against the pinned runtime. The library inspects `ServiceLoader.Provider.type()` and annotations without constructing registry objects. Conflicting defaults identify both contributing registry classes. Default lookup chooses the most-specific configured Model ancestor; unconfigured subclasses can use their ancestor's default.
|
|
|
|
A compatible explicit `@ViewModelClass` takes precedence before first creation and must extend the applicable generated base. An existing compatible subclass satisfies later requests for its generated superclass; incompatible requests fail. Nested and direct loading share the same Model-identity mapping, including cycles and null children. Failed subclass construction withdraws its partial identity entry. Messages and ordinary binding behavior remain owned by the existing runtime.
|
|
|
|
The library extension is [NeitzelLib main `90e08b7`](https://gitea.neitzel.de/konrad/NeitzelLib/src/commit/90e08b7/fx/docs/generated-viewmodels.md). The [runtime manifest](runtime/neitzellib-baseline.json) pins the tested local artifact bytes. No released runtime version or remote artifact deployment is claimed.
|
|
|
|
## Host integration and boundaries
|
|
|
|
Standalone and IntelliJ use the same registry-aware target discovery. The browser shows the selected generated/custom class, uses the shared Model Attributes for authoring and retains the existing source-preserving edit/history path. Neither host loads application classes. The current UI invokes generation through **Build and Refresh** and checked-in Maven settings; a dedicated selection/settings editor and reviewed FXML form generation remain later work.
|
|
|
|
Automated acceptance covers clean consumer compilation, custom subclasses, both Lombok orders, removed Attributes, narrowing/reserved-name/default/BeanInfo errors, runtime stored identity/write-back, typed nested access, cycles/nulls, inheritance, collection element identity, Messages, compatible explicit/default selection, conflicting services and constructor failure cleanup. Real Maven classpath/module-path applications compile and load the generated classes independently of a designer. The shared live-host test discovers the generated custom default without changing FXML; existing authoring, Undo/Redo, diagnostics and lifecycle scenarios remain required in both hosts. No manual testing is requested.
|
|
|
|
## Qualification record (2026-11-13)
|
|
|
|
The complete bootstrap passed module builds, target linkage, Java bytecode baselines, plugin packaging, documentation checks, both standalone launch modes, native shared-Kit workflows, 48 worker lifecycle cycles and abrupt owner death. The final processor-selection check then passed all ten processor tests (including six new generation tests) and was installed for a fresh fixture run: 38 target processes passed 548 checks across classpath and module-path applications. Combined current reports contain 151 designer unit/adapter tests and zero failures, errors or skips. The independently built NeitzelLib runtime passed 116 tests with zero failures, errors or skips; its Surefire XML was checked explicitly.
|
|
|
|
Evidence logs are `/tmp/generated-vm-bootstrap.log`, `/tmp/generated-vm-processor-final.log`, `/tmp/generated-vm-fixtures-final.log`, `/tmp/generated-vm-registered-ide.log`, `/tmp/generated-vm-ide-modulepath-retry.log`, `/tmp/generated-vm-ide-modulepath-final.log` and `/tmp/viewmodel-runtime-qualified.log`; host evidence is retained under `target/connected-workflow` and `target/ide-workflow`. These local outputs are disposable, not release artifacts. No manual testing was performed, and previously skipped human scenarios remain skipped.
|
|
|
|
The first registered IntelliJ run passed the classpath workflow but stopped in module-path mode at the previously recorded immediate exact-save assertion, before generation checks. An unchanged module-path retry timed out at initial canvas rendering (`WorkflowProbe` line 438), also before generation checks. No assertion was weakened. Existing startup/persistence/preview-gate reliability work remains open; this slice does not claim to fix those intermittent failures.
|
|
|
|
The final unchanged module-path retry hit the same initial-render timeout. Consequently, **registered IntelliJ module-path whole-host qualification remains open** for this slice. Registered IntelliJ classpath passed generated-registry discovery, full shared editing/history/diagnostic checks, exclusive JavaFX 26 native verification and worker shutdown. Standalone and real target-process module-path checks passed, including generated classes and registry behavior; these do not substitute for the missing registered IDE pass. Follow up on initial rendering and save synchronization before declaring that host gate complete.
|
|
|
|
## Save/startup gate follow-up
|
|
|
|
The previously open module-path host gate is closed by the [IntelliJ save/startup reliability follow-up](ide-host-reliability.md): deterministic regressions reproduced and corrected queued VFS persistence and stale validation state, followed by three consecutive passing registered module-path workflows with the generated registry checks included. The failed attempts above remain historical evidence.
|