Generate typed Java ViewModels and discover declarative registry defaults

This commit is contained in:
2026-11-13 20:06:26 +01:00
parent adf432b98b
commit 8be0aec287
36 changed files with 1123 additions and 17 deletions
@@ -0,0 +1,109 @@
package fixture.checks;
import de.neitzel.fx.view.*;
import de.neitzel.fxdesigner.target.BindingDiscovery;
import de.neitzel.injection.ApplicationContext;
import fixture.components.CustomGeneratedPerson;
import fixture.generated.*;
import fixture.model.*;
import java.util.concurrent.*;
import javafx.application.Platform;
import javafx.scene.control.TextField;
public final class GeneratedViewModelChecks {
public static void run() throws Exception {
var loader = GeneratedViewModelChecks.class.getClassLoader();
String xml;
try (var in = loader.getResourceAsStream("fixture/components/Generated.fxml")) {
xml = new String(in.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
}
var metadata = BindingDiscovery.inspect(xml, "home.street", "both", loader);
PreviewChecks.check(
metadata.viewModel().equals(CustomGeneratedPerson.class.getName()),
"Registry discovery default");
PreviewChecks.check(
metadata.problems().stream().noneMatch(p -> p.severity().equals("ERROR")),
"Generated binding validation: " + metadata.problems());
PreviewChecks.check(
System.getProperty("fixture.generated.initialized") == null,
"Registry discovery initialized Model");
var ready = new CountDownLatch(1);
Platform.startup(
() -> {
Platform.setImplicitExit(false);
ready.countDown();
});
if (!ready.await(10, TimeUnit.SECONDS)) throw new AssertionError("Toolkit startup");
try {
PreviewChecks.fx(
() -> {
var model = new GeneratedPerson();
model.getHome().setNext(model.getHome());
model.getVisits().add(model.getHome());
var context = new ApplicationContext("fixture.components");
var view =
ViewLoader.load(
loader.getResource("fixture/components/Generated.fxml"), model, context);
var vm = (CustomGeneratedPerson) view.getViewModel();
PreviewChecks.check(
vm.nameProperty() == view.property("name"), "Stored property identity");
((TextField) view.getRoot().lookup("#name")).setText("Typed writeback");
PreviewChecks.check(
model.getName().equals("Typed writeback") && vm.getName().equals(model.getName()),
"Typed writeback");
var child = vm.getHome();
PreviewChecks.check(child.getNext() == child, "Typed cycle identity");
var direct =
ViewLoader.load(
loader.getResource("fixture/components/GeneratedAddress.fxml"),
model.getHome(),
context);
PreviewChecks.check(direct.getViewModel() == child, "Nested/direct identity");
child.setStreet("Changed child");
PreviewChecks.check(
model.getHome().getStreet().equals("Changed child"), "Child writeback");
PreviewChecks.check(
vm.getVisits().getFirst() == model.getHome(), "Collection retains Models");
var again =
ViewLoader.load(
loader.getResource("fixture/components/GeneratedExplicit.fxml"),
model,
context);
PreviewChecks.check(
again.getViewModel() == vm, "Custom satisfies generated superclass request");
var fresh =
ViewLoader.load(
loader.getResource("fixture/components/GeneratedExplicit.fxml"),
new GeneratedPerson(),
context);
PreviewChecks.check(
fresh.getViewModel().getClass() == GeneratedPersonViewModel.class,
"Explicit overrides configured default");
vm.setHome(null);
PreviewChecks.check(
model.getHome() == null && vm.getHome() == null, "Null nested writeback");
var employee = new GeneratedEmployee();
var inherited =
ViewLoader.load(
loader.getResource("fixture/components/Generated.fxml"), employee, context);
PreviewChecks.check(
inherited.getViewModel() instanceof GeneratedEmployeeViewModel,
"Most-specific generated default");
var evm = (GeneratedEmployeeViewModel) inherited.getViewModel();
evm.setSalary(55);
evm.setName("Inherited");
PreviewChecks.check(
employee.getSalary() == 55 && employee.getName().equals("Inherited"),
"Inherited typed access");
vm.addMessage(new Message(Message.Severity.INFO, "Generated notice", "name"));
PreviewChecks.check(
view.property("latestMessage").getValue().equals("Generated notice"),
"Shared messages");
return null;
});
System.out.println("PASS generated " + PreviewChecks.checks);
} finally {
Platform.exit();
}
}
}
@@ -41,6 +41,10 @@ public final class PreviewChecks {
public static void main(String[] args) throws Exception {
String mode = args[0];
if (mode.equals("generated")) {
GeneratedViewModelChecks.run();
return;
}
if (mode.equals("viewmodels")) {
ViewModelRuntimeChecks.run();
return;