You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2020/12/03 10:29:28 UTC

[isis] 06/07: ISIS-2444: adds memento serialization example

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

danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 43ad6aa122d819e20dc5fd610e11622f703485cc
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Nov 26 18:59:29 2020 +0000

    ISIS-2444: adds memento serialization example
---
 .../child/ActionAssociateWithVm-description.adoc   |   2 +-
 .../Collection/mementoSerialization/.gitkeep       |   0
 .../dom/annotDomain/Property/PropertyMenu.java     |   9 +-
 ...MementoSerializationExcludedMetaAnnotation.java |  40 ++++++
 ...MementoSerializationIncludedMetaAnnotation.java |  40 ++++++
 ...PropertyMementoSerializationVm-description.adoc | 135 +++++++++++++++++++++
 .../PropertyMementoSerializationVm.java            | 127 +++++++++++++++++++
 .../PropertyMementoSerializationVm.layout.xml}     |  12 +-
 ...ropertyMementoSerializationVm_takeSnapshot.java |  68 +++++++++++
 .../java/demoapp/dom/services/ServicesMenu.java    |  14 +--
 .../xmlSnapshotService/XmlSnapshotParentVm.java    |   7 +-
 .../XmlSnapshotParentVm.layout.xml                 |   4 +-
 .../XmlSnapshotParentVm_takeSnapshot.java          |  26 ++--
 .../child/XmlSnapshotChildVm-description.adoc      |   2 +-
 .../{child => }/XmlSnapshotPeerVm-description.adoc |   2 +-
 .../peer/{child => }/XmlSnapshotPeerVm.java        |   2 +-
 .../peer/{child => }/XmlSnapshotPeerVm.layout.xml  |   0
 17 files changed, 447 insertions(+), 43 deletions(-)

diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/associateWith/child/ActionAssociateWithVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/associateWith/child/ActionAssociateWithVm-description.adoc
index bc9d16d..e755465 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/associateWith/child/ActionAssociateWithVm-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/associateWith/child/ActionAssociateWithVm-description.adoc
@@ -1,3 +1,3 @@
 :Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
 
-This child object exists just to act as the element of the two collections of the `XmlSnapshotParentVm` demo object.
+This child object exists just to act as the element of the two collections of the `PropertyMementoSerializationVm` demo object.
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Collection/mementoSerialization/.gitkeep b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Collection/mementoSerialization/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/PropertyMenu.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/PropertyMenu.java
index 6aa43c8..aaf17a7 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/PropertyMenu.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/PropertyMenu.java
@@ -30,6 +30,7 @@ import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.value.Blob;
 import org.apache.isis.applib.value.Clob;
 
+import demoapp.dom.annotDomain.Property.mementoSerialization.PropertyMementoSerializationVm;
 import lombok.RequiredArgsConstructor;
 import lombok.val;
 
@@ -120,7 +121,6 @@ public class PropertyMenu {
         return vm;
     }
 
-
     @Action(semantics = SemanticsOf.SAFE)
     @ActionLayout(cssClassFa="fa-ruler-horizontal", describedAs = "Length of text fields")
     public PropertyMaxLengthVm maxLength(){
@@ -132,6 +132,13 @@ public class PropertyMenu {
     }
 
     @Action(semantics = SemanticsOf.SAFE)
+    @ActionLayout(cssClassFa="fa-camera", describedAs = "Snapshot inclusion/exclusion")
+    public PropertyMementoSerializationVm mementoSerialization(){
+        val vm = new PropertyMementoSerializationVm("value");
+        return new PropertyMementoSerializationVm("value");
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
     @ActionLayout(cssClassFa="fa-star-half-alt", describedAs = "Regular expressions, such as email")
     public PropertyMustSatisfyVm mustSatisfy(){
         val vm = new PropertyMustSatisfyVm();
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/MementoSerializationExcludedMetaAnnotation.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/MementoSerializationExcludedMetaAnnotation.java
new file mode 100644
index 0000000..e8d399c
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/MementoSerializationExcludedMetaAnnotation.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package demoapp.dom.annotDomain.Property.mementoSerialization;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.isis.applib.annotation.MementoSerialization;
+import org.apache.isis.applib.annotation.Property;
+
+//tag::class[]
+@Property(mementoSerialization = MementoSerialization.EXCLUDED) // <.>
+@Inherited
+@Target({
+        ElementType.METHOD, ElementType.FIELD                   // <.>
+})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MementoSerializationExcludedMetaAnnotation {
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/MementoSerializationIncludedMetaAnnotation.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/MementoSerializationIncludedMetaAnnotation.java
new file mode 100644
index 0000000..c7725c1
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/MementoSerializationIncludedMetaAnnotation.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package demoapp.dom.annotDomain.Property.mementoSerialization;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.isis.applib.annotation.MementoSerialization;
+import org.apache.isis.applib.annotation.Property;
+
+//tag::class[]
+@Property(mementoSerialization = MementoSerialization.INCLUDED) // <.>
+@Inherited
+@Target({
+        ElementType.METHOD, ElementType.FIELD                   // <.>
+})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MementoSerializationIncludedMetaAnnotation {
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm-description.adoc
new file mode 100644
index 0000000..a86fcdc
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm-description.adoc
@@ -0,0 +1,135 @@
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
+
+The `associateWith` element specifies an action has a relationship with another property or another collection of the domain class.
+
+* For properties, the association (currently) is used solely for layout purposes, so that the action will by default be rendered close to the property.
++
+This can of course be overridden using `@ActionLayout` or the layout file
+
+* For collections, the association is also used for layout purposes, rendering the action near to the collection.
++
+However, it is also used at a deeper level, because the action may have a collection parameter which is the same type as the collection elements.
+In the Wicket viewer, the collection is rendered with checkboxes; those selected objects are used as defaults for the action collection parameter.
+
+
+== Associated with Properties
+
+The `AssociateWithVm` class defines two properties, `text` and `anotherProperty`:
+
+[source,java]
+----
+include::ActionAssociateWithVm.java[tags=class-properties]
+----
+
+The regular `updateText` action is associated with the `text` property:
+
+[source,java,indent=0]
+----
+include::ActionAssociateWithVm.java[tags=action-associateWith-property]
+----
+<.> indicates the property to associate with
+<.> if there are multiple actions associated with the property, indicates their order in the UI
+
+Meanwhile the mixin `updateOtherProperty` is associated with the `otherProperty` property:
+
+[source,java,indent=0]
+----
+include::ActionAssociateWithVm_updateOtherProperty.java[tags=class]
+----
+<.> indicates the property to associate with
+<.> indicates their order in the UI
+
+
+== Collection
+
+The `AssociateWithVm` class also defines the `children` collection:
+
+[source,java]
+----
+include::ActionAssociateWithVm.java[tags=class-collections-children]
+----
+
+There are three actions associated with this collection:
+
+* the `addChild` action:
++
+[source,java,indent=0]
+----
+include::ActionAssociateWithVm.java[tags=action-associateWith-children-1]
+----
+<.> associates with the "children" collection
+<.> positioned first in the UI
+
+* the `removeChild` action.
++
+[source,java,indent=0]
+----
+include::ActionAssociateWithVm.java[tags=action-associateWith-children-2]
+----
+<.> associates with the "children" collection
+<.> positioned second in the UI
+<.> because this action is associated with a collection, no supporting `choices()` or `autoComplete(...)` is required to provide the parameter.
+Instead, the elements in the collection are automatically used.
+
++
+TIP: an explicit `choices()` or `autoComplete(...)` supporting method can be provided to override the default usage of the collection elements if required.
+
+* the `removeChildren` action, which allows multiple children to be removed:
++
+[source,java,indent=0]
+----
+include::ActionAssociateWithVm.java[tags=action-associateWith-children-3]
+----
+<.> associates with the "children" collection
+<.> positioned third in the UI
+<.> again, no supporting `choices()` or `autoComplete(...)` method is required.
+Instead, the elements of the collection are used as options.
+Also, each row in the collection is rendered with a checkbox, and those selected are used as the default for the parameter.
+
+== Mixin Actions
+
+The `AssociateWithVm` class also defines the `favorites` collection:
+
+[source,java]
+----
+include::ActionAssociateWithVm.java[tags=class-collections-favorites]
+----
+
+There are three mixin actions associated with this collection:
+
+* the `makeFavorite` action.
+This takes a element from the "children" collectio and also adds to the "favorites" collection:
++
+[source,java]
+----
+include::child/ActionAssociateWithVm_makeFavorite.java[tags=class]
+----
+<.> associates with the "favorites" collection
+<.> positioned first in the UI
+<.> choices are taken from the "children" collection
+
+* the `noLongerFavorite` action.
+This just removes a selected element from the "children" collection:
++
+[source,java]
+----
+include::child/ActionAssociateWithVm_noLongerFavorite.java[tags=class]
+----
+<.> associates with the "children" collection
+<.> positioned second in the UI
+<.> because this action is associated with a collection, no supporting `choices()` or `autoComplete(...)` is required to provide the parameter.
+Instead, the elements in the collection are automatically used.
+
+* the `noLongerFavorites` action.
+This is similar to the previous action, but for multiple favorite elements:
++
+[source,java]
+----
+include::child/ActionAssociateWithVm_noLongerFavorites.java[tags=class]
+----
+<.> associates with the "favorites" collection
+<.> positioned third in the UI
+<.> because this action is associated with a collection, no supporting `choices()` or `autoComplete(...)` is required to provide the parameter.
+Instead, the elements in the collection are automatically used.
+
+
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm.java
new file mode 100644
index 0000000..a4e2f26
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package demoapp.dom.annotDomain.Property.mementoSerialization;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.MementoSerialization;
+import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+
+import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@XmlRootElement(name = "root")
+@XmlType
+@XmlAccessorType(XmlAccessType.FIELD)
+@DomainObject(
+    nature=Nature.VIEW_MODEL,
+    objectType = "demo.PropertyMementoSerializationVm",
+    editing = Editing.ENABLED
+)
+@NoArgsConstructor
+public class PropertyMementoSerializationVm implements HasAsciiDocDescription {
+
+    public PropertyMementoSerializationVm(String text) {
+        this.text = text;
+        this.excludedProperty = text;
+        this.includedProperty = text;
+        this.notSpecifiedProperty = text;
+        this.metaAnnotatedProperty = text;
+        this.metaAnnotatedPropertyOverridden = text;
+    }
+
+    public String title() {
+        return "PropertyMementoSerializationVm";
+    }
+
+    @Property()
+    @MemberOrder(name = "no-annotations", sequence = "1")
+    @XmlElement(required = true)
+    @Getter @Setter
+    private String text;
+
+    @Property(
+        mementoSerialization = MementoSerialization.NOT_SPECIFIED
+    )
+    @PropertyLayout(
+        describedAs = "@Property(mementoSerialization = NOT_SPECIFIED)"
+    )
+    @MemberOrder(name = "annotations", sequence = "1")
+    @XmlElement(required = true)
+    @Getter @Setter
+    private String notSpecifiedProperty;
+
+    @Property(
+        mementoSerialization = MementoSerialization.EXCLUDED
+    )
+    @PropertyLayout(
+        describedAs = "@Property(mementoSerialization = EXCLUDED)"
+    )
+    @MemberOrder(name = "annotations", sequence = "2")
+    @XmlElement(required = true)
+    @Getter @Setter
+    private String excludedProperty;
+
+    @Property(
+        mementoSerialization = MementoSerialization.INCLUDED
+    )
+    @PropertyLayout(
+        describedAs = "@Property(mementoSerialization = INCLUDED)"
+    )
+    @MemberOrder(name = "annotations", sequence = "2")
+    @XmlElement(required = true)
+    @Getter @Setter
+    private String includedProperty;
+
+    @MementoSerializationExcludedMetaAnnotation     // <.>
+    @Property()
+    @PropertyLayout(
+        describedAs = "@MementoSerializationExcludedMetaAnnotation "
+    )
+    @MemberOrder(name = "meta-annotations", sequence = "1")
+    @XmlElement(required = true)
+    @Getter @Setter
+    private String metaAnnotatedProperty;
+
+    @MementoSerializationIncludedMetaAnnotation                 // <.>
+    @Property(
+        mementoSerialization = MementoSerialization.EXCLUDED    // <.>
+    )
+    @PropertyLayout(
+        describedAs =
+            "@MementoSerializationIncludedMetaAnnotation "
+            + "@Property(mementoSerialization = EXCLUDED)"
+    )
+    @MemberOrder(name = "meta-annotations-overridden", sequence = "1")
+    @XmlElement(required = true)
+    @Getter @Setter
+    private String metaAnnotatedPropertyOverridden;
+
+}
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm.layout.xml
similarity index 90%
copy from examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm.layout.xml
index 1a69b0c..8c2abe6 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm.layout.xml
@@ -29,17 +29,13 @@
 		<bs3:col span="6">
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:fieldSet name="Properties" id="annotation"/>
+					<cpt:fieldSet name="Not annotated" id="no-annotations"/>
+					<cpt:fieldSet name="Annotated" id="annotations"/>
+					<cpt:fieldSet name="Meta-annotated" id="meta-annotations"/>
+					<cpt:fieldSet name="Meta-annotated overrriden" id="meta-annotated-overrriden"/>
 					<cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/>
 				</bs3:col>
 			</bs3:row>
-			<bs3:row>
-				<bs3:col span="12">
-					<cpt:collection id="children"/>
-					<cpt:collection id="favorites"/>
-					<cpt:collection id="mixinChildren"/>
-				</bs3:col>
-			</bs3:row>
 		</bs3:col>
 		<bs3:col span="6">
 			<cpt:fieldSet name="Description" id="description" >
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm_takeSnapshot.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm_takeSnapshot.java
new file mode 100644
index 0000000..7e97ae8
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/mementoSerialization/PropertyMementoSerializationVm_takeSnapshot.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package demoapp.dom.annotDomain.Property.mementoSerialization;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.xml.XmlService;
+import org.apache.isis.applib.services.xmlsnapshot.XmlSnapshotService;
+import org.apache.isis.applib.value.Clob;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+//tag::class[]
+@Action(
+    semantics = SemanticsOf.SAFE
+)
+@RequiredArgsConstructor
+public class PropertyMementoSerializationVm_takeSnapshot {
+
+    @Inject
+    XmlSnapshotService xmlSnapshotService;
+    @Inject
+    XmlService xmlService;
+
+    // ...
+//end::class[]
+
+    private final PropertyMementoSerializationVm propertyMementoSerializationVm;
+
+
+//tag::class[]
+    public Clob act() {
+        return snapshotUsing(propertyMementoSerializationVm);
+    }
+
+    private Clob snapshotUsing(
+            final Object parentVm) {
+        val builder = xmlSnapshotService.builderFor(parentVm);
+        val snapshot = builder.build();
+        val doc = snapshot.getXmlDocument();
+        return asClob(xmlService.asString(doc));
+    }
+
+
+    private static Clob asClob(final String xmlStr) {
+        return new Clob("snapshot.xml", "application/xml", xmlStr);
+    }
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/ServicesMenu.java b/examples/demo/domain/src/main/java/demoapp/dom/services/ServicesMenu.java
index 2bc47a3..2ea837f 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/ServicesMenu.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/ServicesMenu.java
@@ -26,14 +26,13 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.SemanticsOf;
 
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-import lombok.extern.log4j.Log4j2;
-
 import demoapp.dom.services.wrapperFactory.WrapperFactoryJdo;
 import demoapp.dom.services.wrapperFactory.WrapperFactoryJdoEntities;
 import demoapp.dom.services.xmlSnapshotService.XmlSnapshotParentVm;
-import demoapp.dom.services.xmlSnapshotService.peer.child.XmlSnapshotPeerVm;
+import demoapp.dom.services.xmlSnapshotService.peer.XmlSnapshotPeerVm;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import lombok.val;
 
 @DomainService(nature=NatureOfService.VIEW, objectType = "demo.ServicesMenu")
 @Log4j2
@@ -49,13 +48,12 @@ public class ServicesMenu {
     }
 
     @Action(semantics = SemanticsOf.SAFE)
-    @ActionLayout(cssClassFa="fa-gift", describedAs = "Snapshot object graphs as XML")
+    @ActionLayout(cssClassFa="fa-camera", describedAs = "Snapshot object graphs as XML")
     public XmlSnapshotParentVm xmlSnapshot(){
 
         val parentVm = new XmlSnapshotParentVm("parent object");
 
-        val peerVm = new XmlSnapshotPeerVm("peer object");
-        parentVm.setPeer(peerVm);
+        parentVm.setPeer(new XmlSnapshotPeerVm("peer object"));
 
         parentVm.addChild("child 1");
         parentVm.addChild("child 2");
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.java b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.java
index 85611c3..22daa66 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.java
@@ -36,15 +36,14 @@ import org.apache.isis.applib.annotation.MementoSerialization;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
 
+import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom.services.xmlSnapshotService.child.XmlSnapshotChildVm;
+import demoapp.dom.services.xmlSnapshotService.peer.XmlSnapshotPeerVm;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
 import lombok.val;
 
-import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
-import demoapp.dom.services.xmlSnapshotService.child.XmlSnapshotChildVm;
-import demoapp.dom.services.xmlSnapshotService.peer.child.XmlSnapshotPeerVm;
-
 @XmlRootElement(name = "root")
 @XmlType
 @XmlAccessorType(XmlAccessType.FIELD)
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml
index 1a69b0c..a7640cd 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm.layout.xml
@@ -29,15 +29,13 @@
 		<bs3:col span="6">
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:fieldSet name="Properties" id="annotation"/>
+					<cpt:fieldSet name="Properties" id="properties"/>
 					<cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
 				<bs3:col span="12">
 					<cpt:collection id="children"/>
-					<cpt:collection id="favorites"/>
-					<cpt:collection id="mixinChildren"/>
 				</bs3:col>
 			</bs3:row>
 		</bs3:col>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm_takeSnapshot.java b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm_takeSnapshot.java
index 7b8179c..b1cea7f 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm_takeSnapshot.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/XmlSnapshotParentVm_takeSnapshot.java
@@ -29,6 +29,7 @@ import org.w3c.dom.Document;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.xml.XmlService;
 import org.apache.isis.applib.services.xmlsnapshot.XmlSnapshotService;
 import org.apache.isis.applib.value.Clob;
 
@@ -45,6 +46,8 @@ public class XmlSnapshotParentVm_takeSnapshot {
 
     @Inject
     XmlSnapshotService xmlSnapshotService;
+    @Inject
+    XmlService xmlService;
 
     // ...
 //end::class[]
@@ -54,7 +57,7 @@ public class XmlSnapshotParentVm_takeSnapshot {
 
 //tag::class[]
     public Clob act(Demo demo) {
-        return demo.snapshotUsing(xmlSnapshotService, xmlSnapshotParentVm);
+        return demo.snapshotUsing(xmlSnapshotParentVm, xmlSnapshotService, xmlService);
     }
 
     public Demo default0Act() {
@@ -87,30 +90,23 @@ public class XmlSnapshotParentVm_takeSnapshot {
             }
         };
 
-        public final Clob snapshotUsing(XmlSnapshotService xmlSnapshotService, Object parentVm) {
+        public final Clob snapshotUsing(
+                final Object parentVm,
+                final XmlSnapshotService xmlSnapshotService,
+                final XmlService xmlService) {
             val builder = xmlSnapshotService.builderFor(parentVm);
             refine(builder);
             XmlSnapshotService.Snapshot snapshot = builder.build();
             val doc = snapshot.getXmlDocument();
-            return Demo.asClob(doc, this);
+            return Demo.asClob(xmlService.asString(doc), this);
         }
 
         abstract void refine(XmlSnapshotService.Snapshot.Builder builder);
 
-        private static Clob asClob(final Document document, final Demo demo) {
-            return new Clob(demo.name() + ".xml", "application/xml", asChars(document));
+        private static Clob asClob(final String xmlStr, final Demo demo) {
+            return new Clob(demo.name() + ".xml", "application/xml", xmlStr);
         }
 
-        @SneakyThrows
-        private static CharSequence asChars(Document document) {
-            val domSource = new DOMSource(document);
-            val writer = new StringWriter();
-            val result = new StreamResult(writer);
-            val tf = TransformerFactory.newInstance();
-            val transformer = tf.newTransformer();
-            transformer.transform(domSource, result);
-            return writer.toString();
-        }
     }
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/child/XmlSnapshotChildVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/child/XmlSnapshotChildVm-description.adoc
index bc9d16d..e755465 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/child/XmlSnapshotChildVm-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/child/XmlSnapshotChildVm-description.adoc
@@ -1,3 +1,3 @@
 :Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
 
-This child object exists just to act as the element of the two collections of the `XmlSnapshotParentVm` demo object.
+This child object exists just to act as the element of the two collections of the `PropertyMementoSerializationVm` demo object.
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm-description.adoc
similarity index 89%
rename from examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm-description.adoc
rename to examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm-description.adoc
index c3eaa0f..a2f1be1 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm-description.adoc
@@ -1,3 +1,3 @@
 :Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
 
-This object exists just to be referenced by the `XmlSnapshotParentVm` demo object.
+This object exists just to be referenced by the `PropertyMementoSerializationVm` demo object.
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm.java b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm.java
similarity index 97%
rename from examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm.java
rename to examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm.java
index 7429bc6..bd6706c 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package demoapp.dom.services.xmlSnapshotService.peer.child;
+package demoapp.dom.services.xmlSnapshotService.peer;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm.layout.xml
similarity index 100%
rename from examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/child/XmlSnapshotPeerVm.layout.xml
rename to examples/demo/domain/src/main/java/demoapp/dom/services/xmlSnapshotService/peer/XmlSnapshotPeerVm.layout.xml