This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-2873
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit b49ddafff1c5c27429cb0c3f8e92387f3f630ad5
Author: Dan Haywood <[email protected]>
AuthorDate: Sun May 26 10:51:42 2024 +0100

    CAUSEWAY-2873: 03-14
---
 .../petclinic/pages/030-petowner-entity.adoc       | 205 ++++++++++++++-------
 1 file changed, 142 insertions(+), 63 deletions(-)

diff --git 
a/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc 
b/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc
index 33c41617cd..496b871771 100644
--- 
a/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc
+++ 
b/antora/components/tutorials/modules/petclinic/pages/030-petowner-entity.adoc
@@ -1071,106 +1071,185 @@ public PetOwner create(
 Run the application and try to enter an invalid
 
 
-[#exercise-3-10-field-layout]
-== Ex 3.10: Field layout
+[#exercise-3-14-use-layout-xml-file-for-ui-semantics]
+== Ex 3.14: Use layout xml file for UI semantics
 
-At the moment all the properties of `PetOwner` are grouped into a single 
fieldset.
-The UI would be improved by grouping properties according to their nature, for 
example the "phoneNumber" and "emailAddress" in a "Contact Details" fieldset.
+At the moment the associated `.layout.xml` file for `PetOwner` is used to 
define rows, columns and fieldsets, while the 
xref:refguide:applib:index/annotation/PropertyLayout.adoc[@PropertyLayout] 
annotation is grouped to associate properties with those fieldsets.
+
+If we prefer, we can move specify this association within the 
`PetOwner.layout.xml` file instead.
+And we can also do the same thing associating actions with properties or 
collections.
+
+This has the benefit of being dynamic; we can move fields around in the layout 
without having to recompile/restart the application.
 
-We do this using the associated `PetOwner.layout.xml` file (which defines the 
positioning of the fieldsets), and also using the annotations within `PetOwner` 
(which associate the properties to those fieldsets).
 
 === Solution
 
 [source,bash]
 ----
-git checkout tags/03-10-PetOwner-fieldsets
+git checkout tags/03-14-PetOwner-fieldsets
 mvn clean install
 mvn -pl spring-boot:run
 ----
 
 === Task
 
-* modify the `PetOwner.layout.xml`, adding two new `fieldSet` definitions 
after the first `tabGroup`:
+Associate properties with fieldsets using `.layout.xml`:
+
+* associate `name` property with `identity` fieldset:
+
+** remove `@PropertyLayout` from `PetOwner`:
++
+[source,java]
+.PetOwner.java
+----
+@Name
+@Column(length = Name.MAX_LEN, nullable = false, name = "name")
+@Getter @Setter @ToString.Include
+// @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.IDENTITY, sequence 
= "1")
+private String name;
+----
+
+** add to `PetOwner.layout.xml`:
 +
 [source,xml]
 .PetOwner.layout.xml
 ----
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<bs:grid>
-    <bs:row>
-        <!-- ... -->
-    </bs:row>
-    <bs:row>
-        <bs:col span="6">
-            <bs:tabGroup>
-                <!-- ... -->
-            </bs:tabGroup>
-            <c:fieldSet id="contactDetails" name="Contact Details"/> <!--.-->
-            <c:fieldSet id="notes" name="Notes"/>                    <!--.-->
-        </bs:col>
-        <bs:col span="6">
-            <!-- ... -->
-        </bs:col>
-    </bs:row>
-</bs:grid>
-----
-<.> fieldSet for contact details
-<.> fieldset for the notes
-
-* modify the `@PropertyLayout` annotation for the properties to associate with 
these fieldsets:
+<cpt:fieldSet name="Identity" id="identity">
+    <cpt:property id="name"/>
+</cpt:fieldSet>
+----
+
+* similarly for `knownAs`
+* similarly for `telephoneNumber`
+* similarly for `emailAddress`
+* similarly for `notes`
+* similarly for `lastVisit`
+* similarly for `daysSinceLastVisit`
+* similarly for `attachment`
+
+* associate `version` property with `metadata` fieldset, and also explicitly 
specify the location of the two framework-provided properties that also reside 
in that fieldset:
+
+** change ``PetOwner#version` property to::
 +
 [source,java]
 .PetOwner.java
 ----
-// ...
-@PropertyLayout(fieldSetId = "contactDetails", sequence = "1")    // <.>
-private String phoneNumber;
-
-// ...
-@PropertyLayout(fieldSetId = "contactDetails", sequence = "2")    // <.>
-private String emailAddress;
+@Version
+@Column(name = "version", nullable = false)
+//@PropertyLayout(fieldSetId = "metadata", sequence = "999")    // <.>
+@Property                                                       // <.>
+@Getter @Setter
+private long version;
+----
+<.> The `@PropertyLayout` was removed...
+<.> ... but `@Property` has been added instead.
++
+This is because at least one of @Property` or `@PropertyLayout` must be 
present to identify the field as a property (at least using the configuration 
of the framework is concerned).
 
-// ...
-@PropertyLayout(fieldSetId = "notes", sequence = "1")               // <.>
-private String notes;
+** add to `PetOwner.layout.xml`:
++
+[source,xml]
+.PetOwner.layout.xml
+----
+<cpt:fieldSet name="Metadata" id="metadata">
+    <cpt:property id="logicalTypeName"/>        // <.>
+    <cpt:property id="objectIdentifier"/>       // <1>
+    <cpt:property id="version"/>
+</cpt:fieldSet>
 ----
-<.> associates as the 1^st^ property in the "contact details" fieldset
-<.> associates as the 2^nd^ property in the "contact details" fieldset
-<.> associates with the "notes" fieldset
+<.> framework-provided properties.
+If we want the `version` property to appear last in the fieldset, then we need 
to specify these other properties also.
 
-Run the application; the layout should look like:
 
-image::03-10/fieldsets.png[width=800]
+* associate the `updateName` action with the `name` property
 
+** remove from `PetOwner`:
++
+[source,java]
+.PetOwner.java
+----
+    @Action( ... )
+    @ActionLayout(
+            // associateWith = "name",      // <.>
+            ...
+    )
+    public PetOwner updateName(
+            @Name final String name) { ... }
+----
+<.> deleted this line
 
-The layout file can be reloaded dynamically (on IntelliJ, menu:Run[Debugging 
Actions > Reload Changed Classes]), so you can inspect any updates without 
having to restart the app.
-Experiment with this by moving a fieldset into a tab group, or change the 
width of a column).
+** add to `PetOwner.layout.xml`:
++
+[source,xml]
+.PetOwner.layout.xml
+----
+<cpt:property id="name">
+    <cpt:action id="updateName"/>
+</cpt:property>
+----
 
+* similarly `updateAttachment` action
 
+** remove from `PetOwner`:
++
+[source,java]
+.PetOwner.java
+----
+@Action( ... )
+// @ActionLayout(                               // <.>
+//      associateWith = "attachment",           // <1>
+//      position = ActionLayout.Position.PANEL  // <1>
+// )                                            // <1>
+public PetOwner updateAttachment( ... ) { ... }
+----
+<.> deleted lines
 
-=== Optional Exercise
+** add to `PetOwner.layout.xml`:
++
+[source,xml]
+.PetOwner.layout.xml
+----
+<cpt:property id="attachment">
+    <cpt:action id="updateAttachment" position="PANEL"/>
+</cpt:property>
+----
 
-NOTE: If you decide to do this optional exercise, make the changes on a git 
branch so that you can resume with the main flow of exercises later.
 
-It is also possible to associate the properties to fieldsets using only the 
`.layout.xml` file.
-In fact, pretty much all of the metadata in the `@XxxLayout` annotations can 
be specified in the layout file.
+** remove from `PetOwner`:
++
+[source,java]
+.PetOwner.java
+----
+@Action( ... )
+@ActionLayout(
+    // fieldSetId = LayoutConstants.FieldSetId.IDENTITY,        // <.>
+    // position = ActionLayout.Position.PANEL,                  // <1>
+    describedAs = "Deletes this object from the persistent datastore"
+)
+public void delete() { ... }
+----
+<.> deleted lines
 
+* add to `PetOwner.layout.xml`:
++
 [source,xml]
 .PetOwner.layout.xml
 ----
-<c:fieldSet id="contactDetails" name="Contact Details">
-    <c:property id="phoneNumber"/>
-    <c:property id="emailAddress"/>
-</c:fieldSet>
-<c:fieldSet id="notes" name="Notes">
-    <c:property id="notes"/>
-</c:fieldSet>
+<cpt:fieldSet name="Identity" id="identity">
+    <cpt:action id="delete" position="PANEL"/>  <!--.-->
+    <cpt:property id="name">
+        <cpt:action id="updateName"/>
+    </cpt:property>
+    ...
+</cpt:fieldSet>
 ----
+<.> added, _before_ any of the ``<property>``s
 
-The `@PropertyLayout` annotations could then be removed.
-
-Using the layout file to specify individual properties provides even more 
fine-grained control when dynamically reloading, so you could for example 
switch the order of properties in a fieldset and inspect the changes 
immediately without having to restart the app.
-You might find though that the main benefit of the layout file is to declare 
how the different "regions" of the UI fit together in terms of rows, columns, 
tabs and fieldsets, and then use annotations to slot the properties/actions 
into those regions.
-It really is a matter of personal preference which approach you use.
 
+Whether you choose to use layout file only or a mixture of layout file and 
annotations is a matter of taste.
+Notice that the `.layout.xml` files has elements with the 
"unreferencedProperties", "unreferencedCollections" or "unreferencedActions" 
(and is considered invalid if these are missing).
+As you might expect, these tags indicate where to render properties, 
collections or actions whose placement has not been specified explicitly.
 
+IMPORTANT::
+This is an important principle of the _naked objects pattern_ ; the domain 
object should always be rendered in some way or another.
+The presence of UI semantics (`@XxxLayout` annotations or the `.layout.xml` 
files) merely influence how that rendering is performed.

Reply via email to