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 2017/09/16 15:11:28 UTC

isis git commit: ISIS-1712: adds hint-n-tip for instantiating view models

Repository: isis
Updated Branches:
  refs/heads/master 5ba685c16 -> abc2daf9e


ISIS-1712: adds hint-n-tip for instantiating view models


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/abc2daf9
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/abc2daf9
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/abc2daf9

Branch: refs/heads/master
Commit: abc2daf9e7e39ec327b168a2d18e72e469b4983d
Parents: 5ba685c
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Sep 15 17:35:08 2017 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Sep 15 17:35:08 2017 +0100

----------------------------------------------------------------------
 .../guides/ugbtb/_ugbtb_hints-and-tips.adoc     |   2 +
 ...hints-and-tips_view-model-instantiation.adoc | 160 +++++++++++++++++++
 .../images/hints-and-tips/view-model-fail.png   | Bin 0 -> 6960 bytes
 .../hints-and-tips/view-model-success.png       | Bin 0 -> 7046 bytes
 4 files changed, 162 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/abc2daf9/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips.adoc b/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips.adoc
index 7bf516f..9b98dd7 100644
--- a/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips.adoc
@@ -28,6 +28,7 @@ include::_ugbtb_hints-and-tips_replacing-default-service-implementations.adoc[le
 include::_ugbtb_hints-and-tips_vetoing-visibility.adoc[leveloffset=+1]
 include::_ugbtb_hints-and-tips_transactions-and-errors.adoc[leveloffset=+1]
 include::_ugbtb_hints-and-tips_persisted-title.adoc[leveloffset=+1]
+include::_ugbtb_hints-and-tips_view-model-instantiation.adoc[leveloffset=+1]
 
 include::_ugbtb_hints-and-tips_simulating-collections-of-values.adoc[leveloffset=+1]
 
@@ -38,3 +39,4 @@ include::_ugbtb_hints-and-tips_subclass-properties-in-tables.adoc[leveloffset=+1
 include::_ugbtb_hints-and-tips_pushing-changes.adoc[leveloffset=+1]
 include::_ugbtb_hints-and-tips_how-to-implement-a-spellchecker.adoc[leveloffset=+1]
 
+

http://git-wip-us.apache.org/repos/asf/isis/blob/abc2daf9/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips_view-model-instantiation.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips_view-model-instantiation.adoc b/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips_view-model-instantiation.adoc
new file mode 100644
index 0000000..aa0cb41
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/ugbtb/_ugbtb_hints-and-tips_view-model-instantiation.adoc
@@ -0,0 +1,160 @@
+
+[[_ugbtb_hints-and-tips_view-model-instantiation]]
+= View Model Instantiation
+: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 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.
+:_basedir: ../../
+:_imagesdir: images/
+
+
+Vith view models, some care must be taken in how they are instantiated.
+Specifically, it's important that the framework doesn't "know" about the view model until its state is "sufficiently" populated to distinguish from other view models.
+
+In practical terms, this means that view models should be instantiated using a constructor, and then injecting services (if required) using the xref:../rgsvc/rgsvc.adoc#_rgsvc_metadata-api_ServiceRegistry[`ServiceRegistry`] service:
+
+[source,java]
+----
+CustomerViewModel viewModel = new CustomerViewModel("Joe", "Bloggs");
+serviceRegistry.injectServicesInto(viewModel);
+----
+
+What will most likely *fail* is to use the xref:../rgsvc/rgsvc.adoc#_rgsvc_core-domain-api_FactoryService[`FactoryService`]:
+
+
+[source,java]
+----
+// DON'T DO THIS WITH VIEW MODELS
+CustomerViewModel viewModel = factoryService.instantiate(CustomerViewModel.class);
+
+viewModel.setFirstName("Joe");
+viewModel.setLastName("Bloggs");
+serviceRegistry.injectServicesInto(viewModel);
+----
+
+That's because the internal "OID" identifier that the framework creates to handle this view model will be incomplete.
+Although the framework can handle changes to the OID (when the corresponding view model's state changes) once created, this isn't the case during initial instantiation process.
+
+
+== Example
+
+To explain further, here's an implementation using `FactoryService` that fails:
+
+[source,java]
+----
+@XmlRootElement(name = "yearSummary")
+@XmlType( propOrder = { ... } )
+@XmlAccessorType(XmlAccessType.FIELD)
+public class YearSummary {                                                  // <1>
+    ...
+    @XmlTransient
+    @CollectionLayout(defaultView = "table")
+    public List<OfficeOptionViewModel> getAmountsPerOffice() {
+        List<OfficeOptionViewModel> amountsPerOffice = new ArrayList<>();
+
+        OfficeOptionViewModel office1 =                                     // <2>
+            factoryService.instantiate(OfficeOptionViewModel.class);
+        office1.setOffice("Amsterdam");                                     // <3>
+        office1.setAmount(200);
+        amountsPerOffice.add(office1);
+
+        OfficeOptionViewModel office2 =                                     // <2>
+            factoryService.instantiate(OfficeOptionViewModel.class);
+        office2.setOffice("London");                                        // <3>
+        office2.setAmount(100);
+        amountsPerOffice.add(office2);
+
+        return amountsPerOffice;
+    }
+}
+----
+<1> Parent view model
+<2> Using `FactoryService`, incorrectly.
+<3> Hard-coded just for demo purposes
+
+This collection, is, confusing, rendered as:
+
+image::{_imagesdir}hints-and-tips/view-model-fail.png[width="800px",link="{_imagesdir}hints-and-tips/view-model-fail.png"]
+
+Even though the `amountsPerOffice` collection of view models is correctly populated, the framework/viewer maps these to their corresponding OIDs before they are rendered.
+Because the "Amsterdam" pojo and "London" pojo each mapped to the same OID, when fetching out the results the viewer obtains the London pojo both times.
+
+The following implementation, on the other hand, succeeds:
+
+
+
+[source,java]
+----
+@XmlRootElement(name = "yearSummary")
+@XmlType( propOrder = { ... } )
+@XmlAccessorType(XmlAccessType.FIELD)
+public class YearSummary {
+    ...
+    @XmlTransient
+    @CollectionLayout(defaultView = "table")
+    public List<OfficeOptionViewModel> getAmountsPerOffice() {
+        List<OfficeOptionViewModel> amountsPerOffice = new ArrayList<>();
+
+		OfficeOptionViewModel office1 = new OfficeOptionViewModel("Amsterdam", 200);    // <1>
+		serviceRegistry.injectServicesInto(office1);
+		amountsPerOffice.add(office1);
+
+		OfficeOptionViewModel office2 = new OfficeOptionViewModel("London", 100);       // <1>
+		serviceRegistry.injectServicesInto(office2);
+		amountsPerOffice.add(office2);
+
+        return amountsPerOffice;
+    }
+}
+----
+<1> Just instantiate with constructor.
+The framework "sees" the domain object when services are injected into it.
+
+As can be seen, this renders just fine:
+
+image::{_imagesdir}hints-and-tips/view-model-success.png[width="800px",link="{_imagesdir}hints-and-tips/view-model-success.png"]
+
+
+To complicate matters a little, note though that following "incorrect" implementation using `FactoryService` does also work correctly:
+
+[source,java]
+----
+@XmlRootElement(name = "yearSummary")
+@XmlType( propOrder = { ..., "amountsPerOffice" } )                     // <1>
+@XmlAccessorType(XmlAccessType.FIELD)
+public class YearSummary {
+	...
+
+    void init() {
+        amountsPerOffice = calculateAmountsPerOffice();
+    }
+
+    @XmlElementWrapper
+    @XmlElement(name = "officeOption")
+    @CollectionLayout(defaultView = "table")
+    @Getter @Setter
+    private List<OfficeOptionViewModel> amountsPerOffice = Lists.newArrayList();
+
+	@XmlTransient
+    @CollectionLayout(defaultView = "table")
+    public List<OfficeOptionViewModel> calculateAmountsPerOffice() {
+        List<OfficeOptionViewModel> amountsPerOffice = new ArrayList<>();
+
+		OfficeOptionViewModel office1 = factoryService.instantiate(OfficeOptionViewModel.class);
+		office1.setOffice("Amsterdam");
+		office1.setAmount(200);
+
+		amountsPerOffice.add(office1);
+
+		OfficeOptionViewModel office2 = factoryService.instantiate(OfficeOptionViewModel.class);
+		office2.setOffice("London");
+		office2.setAmount(100);
+
+		amountsPerOffice.add(office2);
+
+        return amountsPerOffice;
+    }
+}
+----
+<1> "amountsPerOffice" is part of the state of the parent view model
+
+In this case the `amountsPerOffice` collection is part of the state of the parent view model and so in this particular case everything works with either `FactoryService#instantiate` or using `ServiceRegistry`.
+

http://git-wip-us.apache.org/repos/asf/isis/blob/abc2daf9/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-fail.png
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-fail.png b/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-fail.png
new file mode 100644
index 0000000..57446d8
Binary files /dev/null and b/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-fail.png differ

http://git-wip-us.apache.org/repos/asf/isis/blob/abc2daf9/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-success.png
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-success.png b/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-success.png
new file mode 100644
index 0000000..ea47a25
Binary files /dev/null and b/adocs/documentation/src/main/asciidoc/guides/ugbtb/images/hints-and-tips/view-model-success.png differ