This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v3
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/v3 by this push:
new da85a3ede45 CAUSEWAY-2297: ditch ActionMemento and
ActionParameterMemento (make ObjectAction serializable)
da85a3ede45 is described below
commit da85a3ede45373fd2b0ed6fa7d5b0d9326dd0f00
Author: Andi Huber <[email protected]>
AuthorDate: Sat Nov 23 18:07:43 2024 +0100
CAUSEWAY-2297: ditch ActionMemento and ActionParameterMemento (make
ObjectAction serializable)
---
.../core/metamodel/spec/feature/ObjectAction.java | 8 --
.../spec/feature/ObjectActionParameter.java | 7 --
.../spec/feature/memento/ActionMemento.java | 83 --------------------
.../feature/memento/ActionParameterMemento.java | 90 ----------------------
.../specloader/specimpl/ObjectActionDefault.java | 32 +++++++-
.../specloader/specimpl/ObjectActionMixedIn.java | 1 +
.../domainmodel/DomainModelTest_serialization.java | 76 ++++++++++++++++++
.../interaction/act/ActionInteractionWkt.java | 10 +--
8 files changed, 110 insertions(+), 197 deletions(-)
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
index 619b6eba3e5..fdb38c350e2 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
@@ -53,7 +53,6 @@ import
org.apache.causeway.core.metamodel.object.ManagedObject;
import org.apache.causeway.core.metamodel.object.ManagedObjects;
import org.apache.causeway.core.metamodel.spec.ActionScope;
import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
-import org.apache.causeway.core.metamodel.spec.feature.memento.ActionMemento;
import
org.apache.causeway.core.metamodel.specloader.specimpl.ObjectActionDefault;
import
org.apache.causeway.core.metamodel.specloader.specimpl.ObjectActionMixedIn;
@@ -264,13 +263,6 @@ public interface ObjectAction extends ObjectMember {
return prefix + ownerId + "-" + getId();
}
- /**
- * Returns a serializable representation of this action.
- */
- default ActionMemento getMemento() {
- return ActionMemento.forAction(this);
- }
-
default PromptStyle getPromptStyle() {
var promptStyle = lookupFacet(PromptStyleFacet.class)
.map(PromptStyleFacet::value);
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionParameter.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionParameter.java
index f6b1037f660..f9a28d6b663 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionParameter.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectActionParameter.java
@@ -36,7 +36,6 @@ import
org.apache.causeway.core.metamodel.interactions.managed.ParameterNegotiat
import org.apache.causeway.core.metamodel.object.ManagedObject;
import org.apache.causeway.core.metamodel.object.ManagedObjects;
import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
-import
org.apache.causeway.core.metamodel.spec.feature.memento.ActionParameterMemento;
import org.apache.causeway.core.metamodel.util.Facets;
import lombok.NonNull;
@@ -284,10 +283,4 @@ extends ObjectFeature, CurrentHolder {
return getAction().getCssClass(prefix) + "-" + getId();
}
- /**
- * Returns a serializable representation of this parameter.
- */
- default ActionParameterMemento getMemento() {
- return ActionParameterMemento.forActionParameter(this);
- }
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/memento/ActionMemento.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/memento/ActionMemento.java
deleted file mode 100644
index f0379f900c4..00000000000
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/memento/ActionMemento.java
+++ /dev/null
@@ -1,83 +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.core.metamodel.spec.feature.memento;
-
-import java.io.Serializable;
-import java.util.function.Supplier;
-
-import org.apache.causeway.applib.Identifier;
-import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
-import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
-
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.Synchronized;
-
-/**
- * {@link Serializable} representation of an {@link ObjectAction}
- *
- * @implNote thread-safe memoization
- *
- * @since 2.0 {index}
- */
-@EqualsAndHashCode
-@AllArgsConstructor(access = AccessLevel.PROTECTED)
-public class ActionMemento implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- @EqualsAndHashCode.Include
- @Getter private final @NonNull Identifier identifier;
-
- // -- FACTORY
-
- public static ActionMemento forAction(final @NonNull ObjectAction action) {
- return new ActionMemento(
- action.getFeatureIdentifier(),
- action);
- }
-
- // -- LOAD/UNMARSHAL
-
- @EqualsAndHashCode.Exclude
- private transient ObjectAction action;
-
- @Synchronized
- public ObjectAction getAction(final @NonNull Supplier<SpecificationLoader>
specLoader) {
- if (action == null) {
- action = specLoader.get()
-
.specForLogicalTypeElseFail(getIdentifier().getLogicalType())
- .getActionElseFail(
-
getIdentifier().getMemberNameAndParameterClassNamesIdentityString());
- }
- return action;
- }
-
- // -- OBJECT CONTRACT
-
- @Override
- public String toString() {
- return getIdentifier().getLogicalTypeName() + "#"
- +
getIdentifier().getMemberNameAndParameterClassNamesIdentityString();
- }
-
-}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/memento/ActionParameterMemento.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/memento/ActionParameterMemento.java
deleted file mode 100644
index f3e645f5b06..00000000000
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/memento/ActionParameterMemento.java
+++ /dev/null
@@ -1,90 +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.core.metamodel.spec.feature.memento;
-
-import java.io.Serializable;
-import java.util.function.Supplier;
-
-import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
-import org.apache.causeway.core.metamodel.spec.feature.ObjectActionParameter;
-import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
-
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.Synchronized;
-
-/**
- * {@link Serializable} representation of an {@link ObjectActionParameter
parameter}
- * that belongs to an {@link ObjectAction}.
- *
- * @implNote thread-safe memoization
- *
- * @see ActionMemento
- *
- * @since 2.0 {index}
- */
-@EqualsAndHashCode
-@AllArgsConstructor(access = AccessLevel.PROTECTED)
-public class ActionParameterMemento implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- @EqualsAndHashCode.Include
- @Getter private final @NonNull ActionMemento actionMemento;
-
- @EqualsAndHashCode.Include
- @Getter private final int number;
-
- // -- FACTORY
-
- public static ActionParameterMemento forActionParameter(
- final @NonNull ObjectActionParameter actionParameter) {
- return new ActionParameterMemento(
- actionParameter.getAction().getMemento(),
- actionParameter.getParameterIndex(),
- actionParameter);
- }
-
- // -- LOAD/UNMARSHAL
-
- @EqualsAndHashCode.Exclude
- private transient ObjectActionParameter actionParameter;
-
- @Synchronized
- public ObjectActionParameter getActionParameter(final @NonNull
Supplier<SpecificationLoader> specLoader) {
- if (actionParameter == null) {
- this.actionParameter = actionMemento
- .getAction(specLoader)
- .getParameters()
- .getElseFail(number);
- }
- return actionParameter;
- }
-
- // -- OBJECT CONTRACT
-
- @Override
- public String toString() {
- return getActionMemento().toString() + "[" + getNumber() + "]";
- }
-
-}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index 712a8ebd8cc..a5afc9570bc 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionDefault.java
@@ -18,6 +18,9 @@
*/
package org.apache.causeway.core.metamodel.specloader.specimpl;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
@@ -42,6 +45,7 @@ import org.apache.causeway.core.metamodel.commons.UtilStr;
import org.apache.causeway.core.metamodel.consent.Consent;
import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy;
import org.apache.causeway.core.metamodel.consent.InteractionResultSet;
+import org.apache.causeway.core.metamodel.context.MetaModelContext;
import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
import org.apache.causeway.core.metamodel.facetapi.FeatureType;
import org.apache.causeway.core.metamodel.facets.FacetedMethod;
@@ -72,7 +76,8 @@ import lombok.extern.log4j.Log4j2;
@Log4j2
public class ObjectActionDefault
extends ObjectMemberAbstract
-implements ObjectAction {
+implements ObjectAction, Serializable {
+ private static final long serialVersionUID = 1L;
public static ActionScope getType(final String typeStr) {
final ActionScope type = ActionScope.valueOf(typeStr);
@@ -587,7 +592,7 @@ implements ObjectAction {
// -- HELPER
- protected String argsFor(Can<ObjectActionParameter> parameters,
Can<ManagedObject> arguments) {
+ protected String argsFor(final Can<ObjectActionParameter> parameters,
final Can<ManagedObject> arguments) {
if(parameters.size() != arguments.size()) {
return "???"; // shouldn't happen
}
@@ -620,4 +625,27 @@ implements ObjectAction {
|| methodFacade.synthesize(ActionLayout.class).isPresent();
}
+ // -- SERIALIZATION PROXY
+
+ protected final Object writeReplace() {
+ return new SerializationProxy(this);
+ }
+
+ protected final void readObject(final ObjectInputStream stream) throws
InvalidObjectException {
+ throw new InvalidObjectException("Proxy required");
+ }
+
+ protected record SerializationProxy(Identifier identifier) implements
Serializable {
+ SerializationProxy(final ObjectActionDefault action) {
+ this(action.getFeatureIdentifier());
+ }
+ private Object readResolve() {
+ return MetaModelContext.instanceElseFail()
+ .getSpecificationLoader()
+ .specForLogicalTypeElseFail(identifier.getLogicalType())
+ .getActionElseFail(
+
identifier.getMemberNameAndParameterClassNamesIdentityString());
+ }
+ }
+
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index 08b373575d5..f0fdddc1b90 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -49,6 +49,7 @@ import lombok.extern.log4j.Log4j2;
public class ObjectActionMixedIn
extends ObjectActionDefault
implements MixedInMember {
+ private static final long serialVersionUID = 1L;
// -- FACTORIES
diff --git
a/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_serialization.java
b/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_serialization.java
new file mode 100644
index 00000000000..7570c0fcf4d
--- /dev/null
+++
b/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_serialization.java
@@ -0,0 +1,76 @@
+/*
+ * 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.testdomain.domainmodel;
+
+import jakarta.inject.Inject;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+import org.apache.causeway.commons.internal.testing._SerializationTester;
+import org.apache.causeway.core.config.presets.CausewayPresets;
+import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
+import
org.apache.causeway.core.metamodel.specloader.specimpl.ObjectActionDefault;
+import
org.apache.causeway.core.metamodel.specloader.specimpl.ObjectActionMixedIn;
+import org.apache.causeway.testdomain.conf.Configuration_headless;
+import
org.apache.causeway.testdomain.model.good.Configuration_usingValidDomain;
+import org.apache.causeway.testdomain.model.good.ProperMemberSupport;
+import
org.apache.causeway.testing.integtestsupport.applib.CausewayIntegrationTestAbstract;
+
+@SpringBootTest(
+ classes = {
+ Configuration_headless.class,
+ Configuration_usingValidDomain.class,
+
+ },
+ properties = {
+
//"causeway.core.meta-model.introspector.policy=annotation_optional",
+ "causeway.core.meta-model.introspector.mode=FULL",
+ "causeway.applib.annotation.domain-object.editing=TRUE",
+
"causeway.core.meta-model.validator.explicit-object-type=FALSE" // does not
override any of the imports
+ })
+@TestPropertySource({
+ CausewayPresets.SilenceMetaModel,
+ CausewayPresets.SilenceProgrammingModel
+})
+class DomainModelTest_serialization extends CausewayIntegrationTestAbstract {
+
+ @Inject private SpecificationLoader specificationLoader;
+
+ @Test
+ void objectActionDefault_shouldBe_Serializable() {
+ var holderSpec =
specificationLoader.specForTypeElseFail(ProperMemberSupport.class);
+ var act = (ObjectActionDefault)
holderSpec.getDeclaredAction("hideMe").orElseThrow();
+ assertEquals(ObjectActionDefault.class, act.getClass());
+ _SerializationTester.assertEqualsOnRoundtrip(act);
+ }
+
+ @Test
+ void objectActionMixedIn_shouldBe_Serializable() {
+ var holderSpec =
specificationLoader.specForTypeElseFail(ProperMemberSupport.class);
+ var mixin = (ObjectActionMixedIn)
holderSpec.getDeclaredAction("openRestApi").orElseThrow(); // built-in mixin
support
+ assertEquals(ObjectActionMixedIn.class, mixin.getClass());
+ _SerializationTester.assertEqualsOnRoundtrip(mixin);
+ }
+
+}
diff --git
a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
index 0547bfc9b22..fcfca864d5d 100644
---
a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
+++
b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
@@ -18,7 +18,6 @@
*/
package org.apache.causeway.viewer.wicket.model.models.interaction.act;
-import java.util.Objects;
import java.util.Optional;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -38,7 +37,6 @@ import
org.apache.causeway.core.metamodel.interactions.managed.ParameterNegotiat
import
org.apache.causeway.core.metamodel.interactions.managed.PendingParamsSnapshot;
import org.apache.causeway.core.metamodel.object.ManagedObjects;
import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
-import org.apache.causeway.core.metamodel.spec.feature.memento.ActionMemento;
import org.apache.causeway.viewer.wicket.model.models.EntityCollectionModel;
import org.apache.causeway.viewer.wicket.model.models.InlinePromptContext;
import org.apache.causeway.viewer.wicket.model.models.ScalarParameterModel;
@@ -80,7 +78,7 @@ extends HasBookmarkedOwnerAbstract<ActionInteraction> {
* <p>
* nullable in support of lazy evaluation
*/
- private @Nullable ActionMemento actionMemento;
+ private @Nullable ObjectAction actionMemento;
private Can<UiParameterWkt> childModels;
private @Nullable ScalarPropertyModel associatedWithPropertyIfAny;
@@ -128,7 +126,6 @@ extends HasBookmarkedOwnerAbstract<ActionInteraction> {
this.memberId = memberId;
this.where = where;
this.actionMemento = objectAction
- .map(ObjectAction::getMemento) // if present, eagerly
memoize
.orElse(null);
this.associatedWithPropertyIfAny = associatedWithPropertyIfAny;
this.associatedWithParameterIfAny = associatedWithParameterIfAny;
@@ -170,14 +167,13 @@ extends HasBookmarkedOwnerAbstract<ActionInteraction> {
var objectAction = actionInteraction().getMetamodel()
.orElseThrow(()->_Exceptions
.noSuchElement("could not resolve action by memberId
'%s'", memberId));
- this.actionMemento = objectAction.getMemento();
+ this.actionMemento = objectAction;
return objectAction;
}
// re-attachment fails, if the owner is not found (eg. deleted entity),
// hence we return the directly memoized meta-model of the underlying
action
- return
Objects.requireNonNull(actionMemento.getAction(this::getSpecificationLoader),
- ()->"framework bug: lost objectAction on model recycling
(serialization issue)");
+ return actionMemento;
}
public Optional<ScalarPropertyModel> associatedWithProperty() {