Skip to main content
Entwickler Themen
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Generierte ViewModels und Registries

Die Runtime benötigt keine generierten Klassen. Generierung ergänzt typisierte Accessors und einen registrierten Default für ein Model, während Speicherung, Rückschreibung, Listen, Kind-ViewModels und Nachrichten weiterhin von ViewModel verwaltet werden.

Der Java-Generator und seine Maven-Integration gehören zum NeitzelFXDesigner. Model-Metadaten, Java-ViewModel-Generierung und die Erzeugung einer neuen FXML-View sind unterschiedliche Schritte. Keiner davon erzeugt automatisch einen Ereignis-Controller.

Typisierter Zugriff

Für das Person-Model aus dem Schnellstart kann eine generierte Basis so aussehen:

package example.generated;

import de.neitzel.fx.view.ViewModel;
import javafx.beans.property.StringProperty;

public class PersonViewModel extends ViewModel {
    public PersonViewModel(example.Person model) { super(model); }
    public StringProperty nameProperty() {
        return (StringProperty) storedProperty("name");
    }
}

storedProperty ist protected final. Es liefert die bestehende Attribut-Property, ohne wieder einen reflektierenden nameProperty()-Accessor aufzurufen. Unbekannte gespeicherte Attribute scheitern explizit. Die generierte Datei wird nicht von Hand bearbeitet; eigene abgeleitete Properties gehören in eine gewöhnliche Unterklasse.

Registry auf dem Classpath

package example.generated;

import de.neitzel.fx.view.ViewModelRegistry;
import de.neitzel.fx.view.ViewModelRegistration;

@ViewModelRegistration(model = example.Person.class,
        generated = PersonViewModel.class,
        defaultType = PersonViewModel.class)
public final class Registry implements ViewModelRegistry { }

Die Ressource src/main/resources/META-INF/services/de.neitzel.fx.view.ViewModelRegistry enthält:

example.generated.Registry

ViewModelRegistry ist ein Marker. Die Runtime liest die Annotationen über ServiceLoader.Provider.type(), ohne Provider zu konstruieren. @ViewModelRegistration ist wiederholbar; die Container-Annotation heißt @ViewModelRegistrations. Eine Deklaration benennt Model, generierte Basis und ausgewählten Default. Dieser Default darf eine eigene Unterklasse der generierten Basis sein.

Module und Auswahlregeln

Ein benanntes Modul verwendet statt einer ausschließlich classpathbezogenen Servicedatei eine Moduldeklaration:

provides de.neitzel.fx.view.ViewModelRegistry with example.generated.Registry;

Die generierten Pakete brauchen geeignete exports/opens. Klassen und Registry müssen zur Laufzeit gemeinsam mit dem Model erreichbar sein; eine nur zur Compile-Zeit sichtbare Registrierung genügt nicht.

ViewModelDefaults.select(modelClass, explicitClass, classLoader) prüft Beiträge, wählt die spezifischste passende Model-Deklaration und kontrolliert die Typverträglichkeit. Normale Anwendungen überlassen diesen Aufruf dem ViewLoader. Widersprüchliche Defaults, mehrdeutige gleichrangige Beiträge und ungeeignete Basisklassen führen zu Fehlern statt zu einer stillen Auswahl.

Eine passende explizite @ViewModelClass hat vor der ersten Konstruktion Vorrang, muss bei vorhandenem generiertem Vertrag aber dessen Basis erweitern. Ohne Registry bleibt das bisherige generische beziehungsweise Ersatzobjekt-Verhalten erhalten. Bestehende Instanzen werden nur für kompatible Anforderungen wiederverwendet. Verzögerte Kindauflösung nutzt dieselbe Registry und dieselbe Identitätstabelle. Scheitert ein Unterklassen-Konstruktor, wird seine teilweise registrierte Instanz entfernt.

Die Referenzanwendung nutzt weiterhin ein handgeschriebenes PersonViewModel. Ihr optionales Designer-Profil erzeugt Model-Metadaten, keine Default-Registry. Das vermeidet einen unbemerkten Wechsel der bereits festgelegten ViewModel-Klasse.