You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2023/03/30 07:30:42 UTC

[causeway] 01/01: CAUSEWAY-2485: wip for @DomainObject#mixinMethod

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

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

commit 1e3a1f6cb9dc9c0231c3c1b9a6bdb06d9b6c67b0
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Mar 30 07:22:35 2023 +0100

    CAUSEWAY-2485: wip for @DomainObject#mixinMethod
---
 .../src/main/java/demoapp/dom/DemoModuleJpa.java   |  2 +
 .../mixinMethod/DomainObjectMixinMethod.java       | 45 +++++++++++++++
 ...yout.xml => DomainObjectMixinMethod.layout.xml} | 46 ++++++++++++---
 .../DomainObjectMixinMethodSeeding.java            | 38 +++++++++++++
 .../DomainObjectMixinMethodVm-description.adoc     | 45 ++++++++++++---
 .../DomainObjectMixinMethodVm.layout.xml           | 12 +++-
 .../DomainObjectMixinMethodVm_objects.java         | 42 ++++++++++++++
 .../DomainObjectMixinMethodVm_updateName.java      | 46 +++++++++++++++
 .../DomainObjectMixinMethod_initialCharacter.java  | 29 ++++++++++
 .../DomainObjectMixinMethod_updateName.java        | 32 +++++++++++
 .../DomainObjectMixinMethodJpa-description.adoc    | 17 ++++++
 .../jpa/DomainObjectMixinMethodJpa.java            | 66 ++++++++++++++++++++++
 .../jpa/DomainObjectMixinMethodJpaEntities.java    | 40 +++++++++++++
 13 files changed, 442 insertions(+), 18 deletions(-)

diff --git a/examples/demo/domain/src/main/java/demoapp/dom/DemoModuleJpa.java b/examples/demo/domain/src/main/java/demoapp/dom/DemoModuleJpa.java
index 899a0f93a7..99c781b4b0 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/DemoModuleJpa.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/DemoModuleJpa.java
@@ -29,6 +29,7 @@ import demoapp.dom.domain.objects.DomainObject.introspection.annotOpt.jpa.Domain
 import demoapp.dom.domain.objects.DomainObject.introspection.annotReqd.jpa.DomainObjectIntrospectionAnnotReqdJpa;
 import demoapp.dom.domain.objects.DomainObject.introspection.encapsulated.DomainObjectIntrospectionEncapsulated;
 import demoapp.dom.domain.objects.DomainObject.introspection.encapsulated.jpa.DomainObjectIntrospectionEncapsulatedJpa;
+import demoapp.dom.domain.objects.DomainObject.mixinMethod.jpa.DomainObjectMixinMethodJpa;
 import demoapp.dom.domain.objects.DomainObject.nature.viewmodels.jaxbrefentity.jpa.JaxbRefJpa;
 import demoapp.dom.domain.objects.other.embedded.jpa.NumberConstantJpa;
 import demoapp.dom.domain.properties.Property.commandPublishing.jpa.PropertyCommandPublishingJpa;
@@ -103,6 +104,7 @@ import org.springframework.context.annotation.Profile;
         DomainObjectIntrospectionAnnotOptJpa.class,
         DomainObjectIntrospectionAnnotReqdJpa.class,
         DomainObjectIntrospectionEncapsulatedJpa.class,
+        DomainObjectMixinMethodJpa.class,
 
         CausewayBlobJpa.class,
         CausewayClobJpa.class,
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod.java
new file mode 100644
index 0000000000..072ec721d3
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod.java
@@ -0,0 +1,45 @@
+/*
+ *  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.domain.objects.DomainObject.mixinMethod;
+
+import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom._infra.values.ValueHolder;
+
+import org.apache.causeway.applib.annotation.Editing;
+import org.apache.causeway.applib.annotation.Property;
+
+@SuppressWarnings("CdiManagedBeanInconsistencyInspection")
+public abstract class DomainObjectMixinMethod
+        implements
+        HasAsciiDocDescription,
+        ValueHolder<String> {
+
+    public String title() {
+        return value();
+    }
+
+    @Override
+    public String value() {
+        return getName();
+    }
+
+    public abstract String getName();
+    public abstract void setName(String value);
+
+}
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod.layout.xml
similarity index 61%
copy from examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml
copy to examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod.layout.xml
index b4f853de75..691a0c6d47 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod.layout.xml
@@ -26,22 +26,54 @@
 
 	<bs3:row>
 		<bs3:col span="6">
-			<cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/>
+			<bs3:tabGroup>
+				<bs3:tab name="General">
+					<bs3:row>
+						<bs3:col span="12">
+							<cpt:fieldSet name="General" id="general" >
+								<cpt:property id="name"/>
+								<cpt:property id="originalName"/>
+								<cpt:property id="initialCharacter"/>
+							</cpt:fieldSet>
+						</bs3:col>
+					</bs3:row>
+				</bs3:tab>
+				<bs3:tab name="Metadata">
+					<bs3:row>
+						<bs3:col span="12">
+							<cpt:fieldSet name="Metadata" id="metadata" >
+								<cpt:property id="id"/>
+								<cpt:property id="logicalTypeName"/>
+								<cpt:property id="version"/>
+							</cpt:fieldSet>
+						</bs3:col>
+					</bs3:row>
+				</bs3:tab>
+				<bs3:tab name="Other">
+					<bs3:row>
+						<bs3:col span="12">
+							<cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/>
+						</bs3:col>
+					</bs3:row>
+				</bs3:tab>
+			</bs3:tabGroup>
 		</bs3:col>
 		<bs3:col span="6">
 			<cpt:fieldSet name="Description" id="description" >
 				<cpt:action id="clearHints" position="PANEL" />
-				<cpt:action id="downloadLayoutXml"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="rebuildMetamodel" position="PANEL"/>
-				<cpt:action id="downloadMetamodelXml"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="downloadLayout"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="inspectMetamodel"  position="PANEL_DROPDOWN"/>
-                <cpt:action id="recentCommands"  position="PANEL_DROPDOWN"/>
-				<cpt:action id="downloadJdoMetadata"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="downloadMetamodelXml"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="downloadJdoMetamodel"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="recentCommands"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="recentExecutions"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="recentAuditTrailEntries"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="impersonateWithRoles"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="openRestApi" position="PANEL_DROPDOWN" />
 				<cpt:property id="description"/>
 			</cpt:fieldSet>
-		</bs3:col>
-	</bs3:row>
+		</bs3:col>	</bs3:row>
 	<bs3:row>
 		<bs3:col span="12" unreferencedCollections="true"/>
 	</bs3:row>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodSeeding.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodSeeding.java
new file mode 100644
index 0000000000..ee18653ad0
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodSeeding.java
@@ -0,0 +1,38 @@
+/*
+ *  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.domain.objects.DomainObject.mixinMethod;
+
+import demoapp.dom._infra.seed.SeedServiceAbstract;
+import demoapp.dom._infra.values.ValueHolderRepository;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class DomainObjectMixinMethodSeeding
+extends SeedServiceAbstract {
+
+    @Inject
+    public DomainObjectMixinMethodSeeding(
+            ValueHolderRepository<String, ? extends DomainObjectMixinMethod> entities) {
+        super(entities);
+    }
+
+}
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm-description.adoc
index 2992beaaab..192af40c70 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm-description.adoc
@@ -1,13 +1,42 @@
 :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 `mixinMethod` attribute ...
+Mixins are a mechanism for decoupling behaviour from state, so that the behaviour of the mixin seemingly belongs to an underlying domain object, but in fact is implemented in a different class.
+This is a particularly powerful capability for large "modular monoliths", because the mixin can reside in one module and the mixee (or contributee) can reside in another.
+This is made even more powerful by the fact that the contributee can be an interface type rather than a concrete class.
 
-WARNING: TODO[CAUSEWAY-3312]
-Applicable only if #nature() is Nature#MIXIN , indicates the name of the method within the mixin class to be inferred as the action of that mixin.
-Supporting methods are then derived from that method name. For example, if the mixin method name is "act", then the disable supporting method will be "disableAct".
-Typical examples are "act", "prop", "coll", "exec", "execute", "invoke", "apply" and so on.
-The default name is $$.
-NOTE: it's more typical to instead use https://causeway.apache.org/refguide/${CAUSEWAY_VERSION}/applib/index/annotation/Action.html[Action] , https://causeway.apache.org/refguide/${CAUSEWAY_VERSION}/applib/index/annotation/Property.html[Property] or https://causeway.apache.org/refguide/${CAUSEWAY_VERSION}/applib/index/annotation/Collection.html[Collection] as the class-level annotation, indicating that the domain object is a mixin.
-The mixin method name for these is, respectively, "act", "prop" and "coll".
+The idiomatic way of writing mixins is as class that is annotated with link:https://causeway.apache.org/refguide/2.0.0-SNAPSHOT/applib/index/annotation/Property.html[@Property], link:https://causeway.apache.org/refguide/2.0.0-SNAPSHOT/applib/index/annotation/Collection.html[@Collection] or link:https://causeway.apache.org/refguide/2.0.0-SNAPSHOT/applib/index/annotation/Action.html[@Action].
+These require that the mixin class has a single primary method representing the domain member being contributed.
+By default the name of this method is "prop" for properties, "coll" for collections, and "act" for actions.
+This default is defined through the link:https://causeway.apache.org/refguide/2.0.0-SNAPSHOT/applib/index/annotation/DomainObject.html#mixinmethod[@DomainObject#mixinmethod]; if you look into their definition you will see that the `@Property,` `@Collection` and `@Action` are all meta-annotated with `@DomainObject#mixinMethod`.
 
+In most circumstances there will be little need to use `@DomainObject#mixinMethod` directly.
+However, if you prefer some other method names other than the defaults then you can annotate your mixins with this annotation; or define your own annotation (eg `@MyAction`) and meta-annotate it with both `@Action` and `@DomainObject#mixinMethod` as appropriate.
 
+
+=== How this demo works
+
+The collection on the left is a mixin to this view model, but (for demonstration purposes) uses `@DomainObject#mixinMethod` to change the default method name from "coll" to "collection":
+
+[source,java,indent=0]
+.DomainObjectMixinMethodVm_objects.java
+----
+include::DomainObjectMixinMethodVm_objects.java[tags=class]
+----
+<.> overrides the default mixin method
+<.> method representing the contributed domain collection, using the overridden method name
+
+Similarly, the "updateName" action shown on the collection panel is also a mixin, allowing the name of any object to be updated.
+This also overrrides the default name:
+
+[source,java,indent=0]
+.DomainObjectMixinMethodVm_updateName.java
+----
+include::DomainObjectMixinMethodVm_updateName.java[tags=class]
+----
+<.> overrides the default mixin method
+<.> method representing the contributed domain collection, using the overridden method name
+
+The 'initialCharacter' column in the table is also a mixin, this time of the domain class in the collection.
+
+
+Navigate through to each class to inspect that mixin.
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml
index b4f853de75..e631467f47 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm.layout.xml
@@ -27,16 +27,22 @@
 	<bs3:row>
 		<bs3:col span="6">
 			<cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/>
+			<cpt:collection id="objects">
+				<cpt:action id="updateName"/>
+			</cpt:collection>
 		</bs3:col>
 		<bs3:col span="6">
 			<cpt:fieldSet name="Description" id="description" >
 				<cpt:action id="clearHints" position="PANEL" />
-				<cpt:action id="downloadLayoutXml"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="rebuildMetamodel" position="PANEL"/>
-				<cpt:action id="downloadMetamodelXml"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="downloadLayout"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="inspectMetamodel"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="downloadMetamodelXml"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="downloadJdoMetamodel"  position="PANEL_DROPDOWN"/>
                 <cpt:action id="recentCommands"  position="PANEL_DROPDOWN"/>
-				<cpt:action id="downloadJdoMetadata"  position="PANEL_DROPDOWN"/>
+                <cpt:action id="recentExecutions"  position="PANEL_DROPDOWN"/>
+                <cpt:action id="recentAuditTrailEntries"  position="PANEL_DROPDOWN"/>
+				<cpt:action id="impersonateWithRoles"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="openRestApi" position="PANEL_DROPDOWN" />
 				<cpt:property id="description"/>
 			</cpt:fieldSet>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm_objects.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm_objects.java
new file mode 100644
index 0000000000..1323f08c17
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm_objects.java
@@ -0,0 +1,42 @@
+package demoapp.dom.domain.objects.DomainObject.mixinMethod;
+
+import demoapp.dom._infra.values.ValueHolderRepository;
+import demoapp.dom.domain.objects.DomainObject.editing.DomainObjectEditing;
+import demoapp.dom.domain.objects.DomainObject.editing.DomainObjectEditingVm;
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.causeway.applib.annotation.Collection;
+import org.apache.causeway.applib.annotation.CollectionLayout;
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.MemberSupport;
+
+//tag::class[]
+@DomainObject(mixinMethod = "collection")                           // <.>
+@Collection()
+@CollectionLayout()
+@RequiredArgsConstructor
+public class DomainObjectMixinMethodVm_objects {
+    // ...
+//end::class[]
+    @SuppressWarnings("unused")
+    private final DomainObjectMixinMethodVm mixee;
+
+//tag::class[]
+    public List<? extends DomainObjectMixinMethod> collection() {   // <.>
+        // ...
+//end::class[]
+        return objectRepository.all();
+//tag::class[]
+    }
+//end::class[]
+
+    @Inject
+    ValueHolderRepository<String, ? extends DomainObjectMixinMethod> objectRepository;
+
+//tag::class[]
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm_updateName.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm_updateName.java
new file mode 100644
index 0000000000..253487b18b
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethodVm_updateName.java
@@ -0,0 +1,46 @@
+package demoapp.dom.domain.objects.DomainObject.mixinMethod;
+
+import demoapp.dom._infra.values.ValueHolderRepository;
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.causeway.applib.annotation.*;
+
+//tag::class[]
+@DomainObject(mixinMethod = "action")                           // <.>
+@Action()
+@ActionLayout()
+@RequiredArgsConstructor
+public class DomainObjectMixinMethodVm_updateName {
+    // ...
+//end::class[]
+    private final DomainObjectMixinMethodVm mixee;
+
+//tag::class[]
+    public DomainObjectMixinMethodVm action(                    // <.>
+              final DomainObjectMixinMethod object,
+              final String newName) {
+        // ...
+//end::class[]
+        object.setName(newName);
+        return mixee;
+//tag::class[]
+    }
+//end::class[]
+    public List<? extends DomainObjectMixinMethod> choices0Action() {
+        return objectRepository.all();
+    }
+    public String default1Action(final DomainObjectMixinMethod object) {
+        return Optional.ofNullable(object).map(DomainObjectMixinMethod::getName).orElse(null);
+    }
+
+    @Inject
+    ValueHolderRepository<String, ? extends DomainObjectMixinMethod> objectRepository;
+
+//tag::class[]
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod_initialCharacter.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod_initialCharacter.java
new file mode 100644
index 0000000000..6149b39cdb
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod_initialCharacter.java
@@ -0,0 +1,29 @@
+package demoapp.dom.domain.objects.DomainObject.mixinMethod;
+
+import demoapp.dom._infra.values.ValueHolderRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+import javax.inject.Inject;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.MemberSupport;
+import org.apache.causeway.applib.annotation.Property;
+
+//tag::class[]
+@DomainObject(mixinMethod = "property")                           // <.>
+@Property()
+@RequiredArgsConstructor
+public class DomainObjectMixinMethod_initialCharacter {
+
+    @SuppressWarnings("unused")
+    private final DomainObjectMixinMethod mixee;
+
+    @MemberSupport
+    public Character property() {                                   // <.>
+        val charArray = mixee.getName().toCharArray();
+        return charArray.length == 0 ? null : charArray[0];
+    }
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod_updateName.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod_updateName.java
new file mode 100644
index 0000000000..f639bcfdc2
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/DomainObjectMixinMethod_updateName.java
@@ -0,0 +1,32 @@
+package demoapp.dom.domain.objects.DomainObject.mixinMethod;
+
+import demoapp.dom._infra.values.ValueHolderRepository;
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.causeway.applib.annotation.*;
+
+//tag::class[]
+@DomainObject(mixinMethod = "action")                           // <.>
+@Action()
+@RequiredArgsConstructor
+public class DomainObjectMixinMethod_updateName {
+
+    @SuppressWarnings("unused")
+    private final DomainObjectMixinMethod mixee;
+
+    @MemberSupport
+    public DomainObjectMixinMethod action(                      // <.>
+                                      final String newName) {
+        mixee.setName(newName);
+        return mixee;
+    }
+    public String default0Action() {
+        return mixee.getName();
+    }
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpa-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpa-description.adoc
new file mode 100644
index 0000000000..5df1d4b96b
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpa-description.adoc
@@ -0,0 +1,17 @@
+: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 [...]
+
+TODO: In this demo app,
+
+[source,java,indent=0]
+.DomainObjectMixinMethod_updateName.java
+----
+include::../DomainObjectMixinMethod_updateName.java[tags=class]
+----
+<.> xxx
+
+[source,java,indent=0]
+.DomainObjectMixinMethod_initialCharacter.java
+----
+include::../DomainObjectMixinMethod_initialCharacter.java[tags=class]
+----
+<.> xxx
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpa.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpa.java
new file mode 100644
index 0000000000..0dd050c888
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpa.java
@@ -0,0 +1,66 @@
+/*
+ *  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.domain.objects.DomainObject.mixinMethod.jpa;
+
+import demoapp.dom.domain.objects.DomainObject.mixinMethod.DomainObjectMixinMethod;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.inject.Named;
+import javax.persistence.*;
+
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.Editing;
+import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.persistence.jpa.applib.integration.CausewayEntityListener;
+import org.springframework.context.annotation.Profile;
+
+@Profile("demo-jpa")
+@Entity
+@Table(
+    schema = "demo",
+    name = "DomainObjectMixinMethodJpaJpa"
+)
+@EntityListeners(CausewayEntityListener.class)
+@Named("demo.DomainObjectMixinMethodJpa")
+@NoArgsConstructor
+//tag::class[]
+// ...
+@DomainObject(nature = Nature.ENTITY)
+public class DomainObjectMixinMethodJpa
+                extends DomainObjectMixinMethod {
+    // ...
+//end::class[]
+
+    public DomainObjectMixinMethodJpa(String value) {
+        setName(value);
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+//tag::class[]
+
+    @Getter @Setter
+    private String name;
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpaEntities.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpaEntities.java
new file mode 100644
index 0000000000..29a6d54e5a
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/DomainObject/mixinMethod/jpa/DomainObjectMixinMethodJpaEntities.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.domain.objects.DomainObject.mixinMethod.jpa;
+
+import demoapp.dom._infra.values.ValueHolderRepository;
+
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Service;
+
+@Profile("demo-jpa")
+@Service
+public class DomainObjectMixinMethodJpaEntities
+extends ValueHolderRepository<String, DomainObjectMixinMethodJpa> {
+
+    protected DomainObjectMixinMethodJpaEntities() {
+        super(DomainObjectMixinMethodJpa.class);
+    }
+
+    @Override
+    protected DomainObjectMixinMethodJpa newDetachedEntity(String value) {
+        return new DomainObjectMixinMethodJpa(value);
+    }
+
+}