This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/master by this push:
new 09b5cbc42b CAUSEWAY-3711: TreeNode should not be responsible for
creating new tree-adapter instances
09b5cbc42b is described below
commit 09b5cbc42b387da1cc86126b13cd567411f7e016
Author: andi-huber <[email protected]>
AuthorDate: Sat Mar 30 11:23:00 2024 +0100
CAUSEWAY-3711: TreeNode should not be responsible for creating new
tree-adapter instances
---
.../causeway/applib/graph/tree/TreeNode.java | 87 +++++++++-------------
.../causeway/applib/graph/tree/TreeState.java | 23 +++++-
.../applib/graph/tree/TreeState_Default.java | 43 -----------
.../metamodel/inspect/Object_inspectMetamodel.java | 7 +-
.../valuesemantics/TreeNodeValueSemantics.java | 11 ++-
.../docgen/help/helptree/HelpNodeVm.java | 6 +-
.../model/valuetypes/ValueTypeExample.java | 19 ++++-
.../tree/CausewayToWicketTreeAdapter.java | 2 +-
.../ui/components/tree/_TreeModelTreeAdapter.java | 9 ++-
9 files changed, 95 insertions(+), 112 deletions(-)
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeNode.java
b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeNode.java
index 4a887366e2..ddb372a9be 100644
---
a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeNode.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeNode.java
@@ -34,15 +34,12 @@ import org.apache.causeway.applib.annotation.Value;
import org.apache.causeway.applib.graph.Edge;
import org.apache.causeway.applib.graph.SimpleEdge;
import org.apache.causeway.applib.graph.Vertex;
-import org.apache.causeway.applib.services.inject.ServiceInjector;
+import org.apache.causeway.applib.services.factory.FactoryService;
import org.apache.causeway.commons.functional.IndexedFunction;
-import org.apache.causeway.commons.internal.base._Lazy;
import org.apache.causeway.commons.internal.base._NullSafe;
-import org.apache.causeway.commons.internal.context._Context;
import lombok.Getter;
import lombok.NonNull;
-import lombok.SneakyThrows;
/**
* Fundamental building block of Tree structures.
@@ -55,19 +52,27 @@ import lombok.SneakyThrows;
@Value
public class TreeNode<T> implements Vertex<T> {
- @Getter
- private final TreeNode<T> rootNode;
+ @Getter private final TreeNode<T> rootNode;
+ @Getter private final TreeAdapter<T> treeAdapter;
+
private final TreePath treePath;
private final T value;
private final TreeState sharedState;
- private final Class<? extends TreeAdapter<T>> treeAdapterClass;
- private final _Lazy<TreeAdapter<T>> treeAdapter =
_Lazy.of(this::newTreeAdapter);
public static <T> TreeNode<T> root(
final T value,
- final Class<? extends TreeAdapter<T>> treeAdapterClass,
+ final TreeAdapter<T> treeAdapter,
final TreeState sharedState) {
- return new TreeNode<T>(value, treeAdapterClass, sharedState);
+ return new TreeNode<T>(value, treeAdapter, sharedState);
+ }
+
+ public static <T> TreeNode<T> root(
+ final T value,
+ final Class<? extends TreeAdapter<T>> treeAdapterClass,
+ final TreeState sharedState,
+ final FactoryService factoryService
+ ) {
+ return root(value, factoryService.getOrCreate(treeAdapterClass));
}
// generic node constructor, with reference to root
@@ -75,24 +80,24 @@ public class TreeNode<T> implements Vertex<T> {
final @NonNull TreeNode<T> rootNode,
final @NonNull TreePath treePath,
final @NonNull T value,
- final @NonNull Class<? extends TreeAdapter<T>> treeAdapterClass,
+ final @NonNull TreeAdapter<T> treeAdapter,
final @NonNull TreeState sharedState) {
this.rootNode = rootNode;
this.treePath = treePath;
this.value = value;
- this.treeAdapterClass = treeAdapterClass;
+ this.treeAdapter = treeAdapter;
this.sharedState = sharedState;
}
// root-node constructor
private TreeNode(
final @NonNull T value,
- final @NonNull Class<? extends TreeAdapter<T>> treeAdapterClass,
+ final @NonNull TreeAdapter<T> treeAdapter,
final @NonNull TreeState sharedState) {
this.rootNode = this;
this.treePath = TreePath.root();
this.value = value;
- this.treeAdapterClass = treeAdapterClass;
+ this.treeAdapter = treeAdapter;
this.sharedState = sharedState;
}
@@ -167,14 +172,14 @@ public class TreeNode<T> implements Vertex<T> {
// -- CHILDREN
public int getChildCount() {
- return treeAdapter().childCountOf(value);
+ return treeAdapter.childCountOf(value);
}
public Stream<TreeNode<T>> streamChildren() {
if(isLeaf()) {
return Stream.empty();
}
- return treeAdapter().childrenOf(value)
+ return treeAdapter.childrenOf(value)
.map(IndexedFunction.zeroBased((siblingIndex, childPojo)->
toTreeNode(treePath.append(siblingIndex), childPojo)));
}
@@ -278,15 +283,22 @@ public class TreeNode<T> implements Vertex<T> {
// -- CONSTRUCTION
/**
- * Convenient shortcut.
- * @param rootNode
- * @param treeAdapterClass
- * @return new LazyTreeNode
+ * Creates the root node of a tree structure as inferred from given
treeAdapter.
+ */
+ public static <T> TreeNode<T> root(
+ final @NonNull T rootNode,
+ final @NonNull TreeAdapter<T> treeAdapter) {
+ return TreeNode.root(rootNode, treeAdapter, TreeState.rootCollapsed());
+ }
+
+ /**
+ * Creates the root node of a tree structure as inferred from given
treeAdapter.
*/
public static <T> TreeNode<T> root(
- final T rootNode,
- final Class<? extends TreeAdapter<T>> treeAdapterClass) {
- return TreeNode.root(rootNode, treeAdapterClass,
TreeState.rootCollapsed());
+ final @NonNull T rootNode,
+ final @NonNull Class<? extends TreeAdapter<T>> treeAdapterClass,
+ final @NonNull FactoryService factoryService) {
+ return root(rootNode, factoryService.getOrCreate(treeAdapterClass));
}
// -- PARENT NODE ITERATION
@@ -327,37 +339,10 @@ public class TreeNode<T> implements Vertex<T> {
false); // not parallel
}
- // -- TREE NODE ADAPTING
-
- /**
- * @apiNote a class rather than an instance, because otherwise
- * the adapter would need to be serializable for Wicket's trees to work
correctly.
- */
- public Class<? extends TreeAdapter<T>> getTreeAdapterClass() {
- return treeAdapterClass;
- }
-
// -- HELPER
- @SneakyThrows
- private TreeAdapter<T> newTreeAdapter() {
- try {
- var adapter =
treeAdapterClass.getDeclaredConstructor().newInstance();
- return _Context.lookup(ServiceInjector.class)
//TODO[CAUSEWAY-3711] requires some cooperator that provides it
-
.map(serviceInjector->serviceInjector.injectServicesInto(adapter))
- .orElse(adapter);
- } catch (InstantiationException | IllegalAccessException e) {
- throw new IllegalArgumentException(
- String.format("failed to instantiate TreeAdapter '%s'",
treeAdapterClass.getName()), e);
- }
- }
-
- private TreeAdapter<T> treeAdapter() {
- return treeAdapter.get();
- }
-
private TreeNode<T> toTreeNode(final TreePath treePath, final T value){
- return new TreeNode<>(rootNode, treePath, value,
getTreeAdapterClass(), sharedState);
+ return new TreeNode<>(rootNode, treePath, value, treeAdapter,
sharedState);
}
}
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState.java
b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState.java
index d1dba0c6b6..70ccfa2e6e 100644
---
a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState.java
@@ -19,18 +19,33 @@
package org.apache.causeway.applib.graph.tree;
import java.io.Serializable;
+import java.util.HashSet;
import java.util.Set;
/**
* @since 2.0 {@index}
*/
-public interface TreeState extends Serializable {
+public class TreeState implements Serializable {
+ // -- FACTORIES
+
public static TreeState rootCollapsed() {
- return new TreeState_Default();
+ return new TreeState();
}
- public Set<TreePath> getExpandedNodePaths();
- public Set<TreePath> getSelectedNodePaths();
+ // -- CONSTRUCTION
+
+ private static final long serialVersionUID = 7971539034663543462L;
+
+ private final Set<TreePath> expandedNodes = new HashSet<>();
+ private final Set<TreePath> selectedNodes = new HashSet<>();
+
+ public Set<TreePath> getExpandedNodePaths() {
+ return expandedNodes;
+ }
+
+ public Set<TreePath> getSelectedNodePaths() {
+ return selectedNodes;
+ }
}
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState_Default.java
b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState_Default.java
deleted file mode 100644
index e44c458ba4..0000000000
---
a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreeState_Default.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 org.apache.causeway.applib.graph.tree;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import lombok.ToString;
-
-@ToString
-class TreeState_Default implements TreeState {
- private static final long serialVersionUID = 7971539034663543462L;
-
- private final Set<TreePath> expandedNodes = new HashSet<>();
- private final Set<TreePath> selectedNodes = new HashSet<>();
-
- @Override
- public Set<TreePath> getExpandedNodePaths() {
- return expandedNodes;
- }
-
- @Override
- public Set<TreePath> getSelectedNodePaths() {
- return selectedNodes;
- }
-
-}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/inspect/Object_inspectMetamodel.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/inspect/Object_inspectMetamodel.java
index d291affc3f..26e3b554ce 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/inspect/Object_inspectMetamodel.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/inspect/Object_inspectMetamodel.java
@@ -33,6 +33,7 @@ import org.apache.causeway.applib.graph.tree.TreeNode;
import org.apache.causeway.applib.graph.tree.TreePath;
import org.apache.causeway.applib.id.LogicalType;
import org.apache.causeway.applib.layout.LayoutConstants;
+import org.apache.causeway.applib.services.factory.FactoryService;
import org.apache.causeway.applib.services.message.MessageService;
import org.apache.causeway.applib.services.metamodel.Config;
import org.apache.causeway.applib.services.metamodel.MetaModelService;
@@ -62,6 +63,8 @@ import lombok.val;
@RequiredArgsConstructor
public class Object_inspectMetamodel {
+ @Inject FactoryService factoryService;
+
private final Object domainObject; // mixee
public static class ActionDomainEvent
@@ -98,8 +101,8 @@ public class Object_inspectMetamodel {
.orElseThrow(_Exceptions::noSuchElement);
val root = MMNodeFactory.type(domainClassDto, null);
-
- val tree = TreeNode.root(root, MMTreeAdapter.class);
+
+ val tree = TreeNode.root(root,
factoryService.getOrCreate(MMTreeAdapter.class));
// Initialize view-model nodes of the entire tree,
// because as it stands, all the type information gets cleared,
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
index c363ca251d..1dff074f2d 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/TreeNodeValueSemantics.java
@@ -31,6 +31,7 @@ import org.apache.causeway.applib.graph.tree.TreeAdapter;
import org.apache.causeway.applib.graph.tree.TreeNode;
import org.apache.causeway.applib.graph.tree.TreePath;
import org.apache.causeway.applib.graph.tree.TreeState;
+import org.apache.causeway.applib.services.factory.FactoryService;
import org.apache.causeway.applib.services.urlencoding.UrlEncodingService;
import org.apache.causeway.applib.value.semantics.Renderer;
import org.apache.causeway.applib.value.semantics.ValueDecomposition;
@@ -52,6 +53,7 @@ implements
@Inject UrlEncodingService urlEncodingService;
@Inject SerializingAdapter serializingAdapter;
+ @Inject FactoryService factoryService;
@Override
public Class<TreeNode<?>> getCorrespondingClass() {
@@ -78,7 +80,7 @@ implements
private String toEncodedString(final TreeNode<?> treeNode) {
final Memento memento = newMemento();
memento.put("rootValue", treeNode.getRootValue());
- memento.put("adapterClass", treeNode.getTreeAdapterClass());
+ memento.put("adapterClass", treeNode.getTreeAdapter().getClass());
memento.put("treeState", treeNode.getTreeState());
memento.put("treePath", treeNode.getPositionAsPath());
return memento.asString();
@@ -90,7 +92,8 @@ implements
final TreeNode<?> rootNode = TreeNode.root(
memento.get("rootValue", Object.class),
memento.get("adapterClass", Class.class),
- memento.get("treeState", TreeState.class));
+ memento.get("treeState", TreeState.class),
+ factoryService);
return rootNode.resolve(memento.get("treePath", TreePath.class))
.orElse(null);
}
@@ -120,8 +123,8 @@ implements
}
return Can.of(
- TreeNode.root("TreeRoot", TreeAdapterString.class,
TreeState.rootCollapsed()),
- TreeNode.root("another TreeRoot", TreeAdapterString.class,
TreeState.rootCollapsed()));
+ TreeNode.root("TreeRoot", new TreeAdapterString(),
TreeState.rootCollapsed()),
+ TreeNode.root("another TreeRoot", new TreeAdapterString(),
TreeState.rootCollapsed()));
}
// -- HELPER
diff --git
a/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/helptree/HelpNodeVm.java
b/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/helptree/HelpNodeVm.java
index 6b70c3b491..db91799447 100644
---
a/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/helptree/HelpNodeVm.java
+++
b/extensions/core/docgen/help/src/main/java/org/apache/causeway/extensions/docgen/help/helptree/HelpNodeVm.java
@@ -36,6 +36,7 @@ import org.apache.causeway.applib.annotation.PropertyLayout;
import org.apache.causeway.applib.annotation.Where;
import org.apache.causeway.applib.graph.tree.TreeNode;
import org.apache.causeway.applib.graph.tree.TreePath;
+import org.apache.causeway.applib.services.factory.FactoryService;
import org.apache.causeway.extensions.docgen.help.CausewayModuleExtDocgenHelp;
import org.apache.causeway.extensions.docgen.help.applib.HelpNode;
import org.apache.causeway.extensions.docgen.help.applib.HelpNode.HelpTopic;
@@ -59,6 +60,8 @@ public class HelpNodeVm implements ViewModel {
public static HelpNodeVm forRootTopic(final HelpTopic rootTopic) {
return new HelpNodeVm(rootTopic, rootTopic);
}
+
+ @Inject FactoryService factoryService;
@Getter @Programmatic
private final HelpTopic rootTopic;
@@ -97,7 +100,8 @@ public class HelpNodeVm implements ViewModel {
@Property
@PropertyLayout(labelPosition = LabelPosition.NONE, fieldSetId = "tree",
sequence = "1")
public TreeNode<HelpNodeVm> getTree() {
- final TreeNode<HelpNodeVm> tree =
TreeNode.root(HelpNodeVm.forRootTopic(rootTopic), HelpTreeAdapter.class);
+ final TreeNode<HelpNodeVm> tree = TreeNode.root(
+ HelpNodeVm.forRootTopic(rootTopic), HelpTreeAdapter.class,
factoryService);
// expand the current node
helpNode.getPath().streamUpTheHierarchyStartingAtSelf()
diff --git
a/regressiontests/base/src/main/java/org/apache/causeway/testdomain/model/valuetypes/ValueTypeExample.java
b/regressiontests/base/src/main/java/org/apache/causeway/testdomain/model/valuetypes/ValueTypeExample.java
index 5570d7dc9c..b20e88850b 100644
---
a/regressiontests/base/src/main/java/org/apache/causeway/testdomain/model/valuetypes/ValueTypeExample.java
+++
b/regressiontests/base/src/main/java/org/apache/causeway/testdomain/model/valuetypes/ValueTypeExample.java
@@ -53,6 +53,7 @@ import org.apache.causeway.applib.annotation.ValueSemantics;
import
org.apache.causeway.applib.exceptions.recoverable.TextEntryParseException;
import org.apache.causeway.applib.graph.tree.TreeAdapter;
import org.apache.causeway.applib.graph.tree.TreeNode;
+import org.apache.causeway.applib.graph.tree.TreePath;
import org.apache.causeway.applib.graph.tree.TreeState;
import org.apache.causeway.applib.services.appfeat.ApplicationFeatureId;
import org.apache.causeway.applib.services.bookmark.Bookmark;
@@ -753,6 +754,20 @@ public abstract class ValueTypeExample<T> {
}
// -- EXAMPLES - DATA STRUCTURE
+
+ @Named("causeway.testdomain.valuetypes.ValueTypeExampleTreePath")
+ @DomainObject(
+ nature = Nature.BEAN) @Scope("prototype")
+ public static class ValueTypeExampleTreePath
+ extends ValueTypeExample<TreePath> {
+ @Property @Getter @Setter
+ private TreePath value = TreePath.root();
+ @Getter
+ private TreePath updateValue = TreePath.of(0, 1, 2, 3, 4);
+ @Action @Override
+ public TreePath sampleAction(@Parameter @Nullable final TreePath
value) { return value; }
+ }
+
//TODO TreeNode
// @DomainObject(
@@ -762,10 +777,10 @@ public abstract class ValueTypeExample<T> {
extends ValueTypeExample<TreeNode<String>> {
@Property @Getter @Setter
private TreeNode<String> value = TreeNode.root(
- "root", TreeAdapterString.class, TreeState.rootCollapsed());
+ "root", new TreeAdapterString(), TreeState.rootCollapsed());
@Getter
private TreeNode<String> updateValue = TreeNode.root(
- "anotherRoot", TreeAdapterString.class,
TreeState.rootCollapsed());
+ "anotherRoot", new TreeAdapterString(),
TreeState.rootCollapsed());
private static class TreeAdapterString implements TreeAdapter<String> {
@Override public Stream<String> childrenOf(final String value) {
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/CausewayToWicketTreeAdapter.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/CausewayToWicketTreeAdapter.java
index 81e826eb79..8bc9248d5b 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/CausewayToWicketTreeAdapter.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/CausewayToWicketTreeAdapter.java
@@ -84,7 +84,7 @@ class CausewayToWicketTreeAdapter {
final String id, final ManagedObject treeNodeObject) {
val treeNode = (TreeNode<?>) treeNodeObject.getPojo();
- val treeAdapterClass = treeNode.getTreeAdapterClass();
+ val treeAdapterClass = treeNode.getTreeAdapter().getClass();
val wrappingTreeAdapter = new
_TreeModelTreeAdapter(treeAdapterClass);
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/_TreeModelTreeAdapter.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/_TreeModelTreeAdapter.java
index 6743e98edd..023b0869ef 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/_TreeModelTreeAdapter.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/tree/_TreeModelTreeAdapter.java
@@ -47,7 +47,8 @@ implements
private final Class<? extends TreeAdapter> treeAdapterClass;
- private transient TreeAdapter wrappedTreeAdapter;
+ /** non serializable delegate */
+ private transient TreeAdapter delegate;
_TreeModelTreeAdapter(
final Class<? extends TreeAdapter> treeAdapterClass) {
@@ -93,11 +94,11 @@ implements
}
private TreeAdapter wrappedTreeAdapter() {
- if(wrappedTreeAdapter!=null) {
- return wrappedTreeAdapter;
+ if(delegate!=null) {
+ return delegate;
}
try {
- return wrappedTreeAdapter =
getFactoryService().getOrCreate(treeAdapterClass);
+ return delegate =
getFactoryService().getOrCreate(treeAdapterClass);
} catch (Exception e) {
throw new RuntimeException("failed to instantiate tree adapter",
e);
}