Generate typed Java ViewModels and discover declarative registry defaults
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
<groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths><path><groupId>de.neitzel.fxdesigner</groupId><artifactId>designer-model-processor</artifactId><version>0.1.0-SNAPSHOT</version></path></annotationProcessorPaths>
|
||||
<compilerArgs><arg>-Adesigner.models=fixture.model.Person,fixture.model.Address</arg></compilerArgs>
|
||||
<compilerArgs><arg>-Adesigner.models=fixture.model.Person,fixture.model.Address,fixture.model.GeneratedPerson,fixture.model.GeneratedEmployee</arg><arg>-Adesigner.viewModels=true</arg><arg>-Adesigner.viewModelModels=fixture.model.GeneratedPerson,fixture.model.GeneratedEmployee</arg><arg>-Adesigner.generatedPackage=fixture.generated</arg><arg>-Adesigner.viewModelDefaults=fixture.model.GeneratedPerson=fixture.components.CustomGeneratedPerson</arg></compilerArgs>
|
||||
</configuration>
|
||||
</plugin></plugins></build>
|
||||
</project>
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package fixture.components;
|
||||
|
||||
public final class CustomGeneratedPerson extends fixture.generated.GeneratedPersonViewModel {
|
||||
public CustomGeneratedPerson(fixture.model.GeneratedPerson model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
public String greeting() {
|
||||
return "Hello " + getName();
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package fixture.components;
|
||||
|
||||
@jakarta.inject.Singleton
|
||||
@de.neitzel.fx.view.ViewModelClass(fixture.generated.GeneratedPersonViewModel.class)
|
||||
public class GeneratedController {}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package fixture.model;
|
||||
|
||||
public class GeneratedAddress {
|
||||
private String street = "Generated street";
|
||||
private GeneratedAddress next;
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String v) {
|
||||
street = v;
|
||||
}
|
||||
|
||||
public GeneratedAddress getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public void setNext(GeneratedAddress v) {
|
||||
next = v;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package fixture.model;
|
||||
|
||||
public class GeneratedEmployee extends GeneratedPerson {
|
||||
private int salary = 42;
|
||||
|
||||
public int getSalary() {
|
||||
return salary;
|
||||
}
|
||||
|
||||
public void setSalary(int v) {
|
||||
salary = v;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package fixture.model;
|
||||
|
||||
public class GeneratedPerson {
|
||||
static {
|
||||
System.setProperty("fixture.generated.initialized", "yes");
|
||||
}
|
||||
|
||||
private String name = "Generated sample";
|
||||
private GeneratedAddress home = new GeneratedAddress();
|
||||
private java.util.List<GeneratedAddress> visits = new java.util.ArrayList<>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String v) {
|
||||
name = v;
|
||||
}
|
||||
|
||||
public GeneratedAddress getHome() {
|
||||
return home;
|
||||
}
|
||||
|
||||
public void setHome(GeneratedAddress v) {
|
||||
home = v;
|
||||
}
|
||||
|
||||
public java.util.List<GeneratedAddress> getVisits() {
|
||||
return visits;
|
||||
}
|
||||
|
||||
public void setVisits(java.util.List<GeneratedAddress> v) {
|
||||
visits = v;
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<?neitzel-model fixture.model.GeneratedPerson?>
|
||||
<?import javafx.scene.layout.VBox?><?import javafx.scene.control.TextField?><?import de.neitzel.fx.view.*?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml/1"><fx:define><BindingList><DirectBinding control="name" property="text" path="name" direction="both"/><DirectBinding control="street" property="text" path="home.street" direction="both"/></BindingList></fx:define><TextField fx:id="name"/><TextField fx:id="street"/></VBox>
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
<?neitzel-model fixture.model.GeneratedAddress?><?import javafx.scene.control.TextField?><?import javafx.scene.layout.VBox?><?import de.neitzel.fx.view.*?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml/1"><fx:define><BindingList><DirectBinding control="street" property="text" path="street" direction="both"/></BindingList></fx:define><TextField fx:id="street"/></VBox>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<?neitzel-model fixture.model.GeneratedPerson?>
|
||||
<?import javafx.scene.layout.VBox?><?import javafx.scene.control.TextField?><?import de.neitzel.fx.view.*?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="fixture.components.GeneratedController"><fx:define><BindingList><DirectBinding control="name" property="text" path="name" direction="both"/><DirectBinding control="street" property="text" path="home.street" direction="both"/></BindingList></fx:define><TextField fx:id="name"/><TextField fx:id="street"/></VBox>
|
||||
+109
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user