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/isis.git
commit be37a5767835216f0574bc26ba30d0ef672ae197 Author: Andi Huber <ahu...@apache.org> AuthorDate: Mon Aug 29 09:29:13 2022 +0200 ISIS-3167: properly implement common spec finder --- .../isis/core/metamodel/object/ManagedObject.java | 1 + .../isis/core/metamodel/object/ManagedObjects.java | 29 +++++----------------- .../core/metamodel/spec/ObjectSpecification.java | 25 +++++++++++++++++++ .../runtimeservices/memento/_ObjectMemento.java | 23 ++++++++++------- .../xmlsnapshot/XmlSnapshotServiceDefault.java | 8 +++--- .../wkt/viewer/EventProviderAbstract.java | 2 +- .../components/tree/IsisToWicketTreeAdapter.java | 2 +- .../viewer/services/DeepLinkServiceWicket.java | 2 +- 8 files changed, 53 insertions(+), 39 deletions(-) diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java index 71cc7e5872..17eca64550 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java @@ -191,6 +191,7 @@ public interface ManagedObject extends HasMetaModelContext { * @see PojoPolicy#NO_POJO */ public boolean isUnspecified() { return this == UNSPECIFIED; } + public boolean isSpecified() { return this != UNSPECIFIED; } /** * EMPTY * @see TypePolicy#ABSTRACT_TYPE_ALLOWED diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java index af9fed768f..8623d56a1e 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java @@ -341,10 +341,8 @@ public final class ManagedObjects { // -- COMMON SUPER TYPE FINDER /** - * Find an ObjectSpecification that is common to all provided {@code objects} - * @param objects - * @return optionally the common ObjectSpecification based on whether provided {@code objects} - * are not empty + * Optionally the common {@link ObjectSpecification} based on whether provided {@code objects} + * have any at all. */ public static Optional<ObjectSpecification> commonSpecification( final @Nullable Can<ManagedObject> objects) { @@ -352,26 +350,11 @@ public final class ManagedObjects { if (_NullSafe.isEmpty(objects)) { return Optional.empty(); } - val firstElement = objects.getFirstOrFail(); - val firstElementSpec = firstElement.getSpecification(); - if(objects.getCardinality().isOne()) { - return Optional.of(firstElementSpec); - } - - val commonSuperClassFinder = new ClassExtensions.CommonSuperclassFinder(); - objects.stream() - .map(ManagedObject::getPojo) - .filter(_NullSafe::isPresent) - .forEach(commonSuperClassFinder::collect); - - val commonSuperClass = commonSuperClassFinder.getCommonSuperclass().orElse(null); - if(commonSuperClass!=null && commonSuperClass!=firstElement.getSpecification().getCorrespondingClass()) { - val specificationLoader = firstElementSpec.getMetaModelContext().getSpecificationLoader(); - return specificationLoader.specForType(commonSuperClass); - } - - return Optional.of(firstElementSpec); + return objects.stream() + .filter(obj->obj.getSpecialization().isSpecified()) + .map(ManagedObject::getSpecification) + .reduce(ObjectSpecification::commonSuperType); } // -- ADABT UTILITIES diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java index 7bc9d9ae9d..976b36f4b5 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java @@ -36,6 +36,7 @@ import org.apache.isis.applib.id.HasLogicalType; import org.apache.isis.applib.id.LogicalType; import org.apache.isis.applib.services.metamodel.BeanSort; import org.apache.isis.commons.collections.Can; +import org.apache.isis.commons.internal.assertions._Assert; import org.apache.isis.commons.internal.base._NullSafe; import org.apache.isis.commons.internal.collections._Streams; import org.apache.isis.commons.internal.exceptions._Exceptions; @@ -577,6 +578,30 @@ extends : Stream.of(this); } + // -- COMMON SUPER TYPE FINDER + + /** + * Lowest common ancestor search within the combined type hierarchy. + */ + public static ObjectSpecification commonSuperType( + final @NonNull ObjectSpecification a, + final @NonNull ObjectSpecification b) { + + val cls_a = a.getCorrespondingClass(); + val cls_b = b.getCorrespondingClass(); + if(cls_a.isAssignableFrom(cls_b)) { + return a; + } + if(cls_b.isAssignableFrom(cls_a)) { + return b; + } + // assuming the algorithm is correct: if non of the above is true, + // we must be able to walk up the tree on both branches + _Assert.assertNotNull(a.superclass()); + _Assert.assertNotNull(b.superclass()); + return commonSuperType(a.superclass(), b.superclass()); + } + // -- VALUE SEMANTICS SUPPORT /** introduced for lookup optimization / allow memoization */ diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/_ObjectMemento.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/_ObjectMemento.java index 3aa85515e4..bc151d117c 100644 --- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/_ObjectMemento.java +++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/_ObjectMemento.java @@ -21,7 +21,6 @@ package org.apache.isis.core.runtimeservices.memento; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Objects; import java.util.function.Function; @@ -32,9 +31,9 @@ import org.apache.isis.applib.id.LogicalType; import org.apache.isis.applib.services.bookmark.Bookmark; import org.apache.isis.applib.services.bookmark.Oid; import org.apache.isis.applib.services.hint.HintIdProvider; +import org.apache.isis.commons.collections.Can; import org.apache.isis.commons.internal.base._Casts; import org.apache.isis.commons.internal.base._NullSafe; -import org.apache.isis.commons.internal.collections._Lists; import org.apache.isis.commons.internal.exceptions._Exceptions; import org.apache.isis.core.metamodel.context.MetaModelContext; import org.apache.isis.core.metamodel.facets.object.value.ValueFacet; @@ -124,9 +123,15 @@ final class _ObjectMemento implements HasLogicalType, Serializable { final _ObjectMemento memento, final MetaModelContext mmc) { - final List<Object> listOfPojos = - _Lists.map(memento.list, Functions.toPojo(mmc)); - return ManagedObject.lazy(mmc.getSpecificationLoader(), listOfPojos); + final Can<ManagedObject> managedObjects = + _NullSafe.stream(memento.list) + .map(Functions.toManagedObject(mmc)) + .collect(Can.toCan()); + + val commonSpec = ManagedObjects.commonSpecification(managedObjects) + .orElseGet(()->mmc.getSpecificationLoader().loadSpecification(Object.class)); + + return ManagedObject.packed(commonSpec, managedObjects); } @Override @@ -576,19 +581,19 @@ final class _ObjectMemento implements HasLogicalType, Serializable { @NoArgsConstructor(access = AccessLevel.PRIVATE) private static final class Functions { - private static Function<_ObjectMemento, Object> toPojo( + private static Function<_ObjectMemento, ManagedObject> toManagedObject( final MetaModelContext mmc) { return memento->{ if(memento == null) { - return null; + return ManagedObject.unspecified(); } val objectAdapter = memento .reconstructObject(mmc); if(objectAdapter == null) { - return null; + return ManagedObject.unspecified(); } - return objectAdapter.getPojo(); + return objectAdapter; }; } diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xmlsnapshot/XmlSnapshotServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xmlsnapshot/XmlSnapshotServiceDefault.java index 4d56ca8ce2..669b1ae402 100644 --- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xmlsnapshot/XmlSnapshotServiceDefault.java +++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xmlsnapshot/XmlSnapshotServiceDefault.java @@ -60,17 +60,17 @@ public class XmlSnapshotServiceDefault implements XmlSnapshotService { static class XmlSnapshotServiceDefaultBuilder implements XmlSnapshotService.Snapshot.Builder{ private final XmlSnapshotBuilder builder; - public XmlSnapshotServiceDefaultBuilder(SpecificationLoader specificationLoader, Object domainObject) { + public XmlSnapshotServiceDefaultBuilder(final SpecificationLoader specificationLoader, final Object domainObject) { builder = new XmlSnapshotBuilder(specificationLoader, domainObject); } @Override - public void includePath(String path) { + public void includePath(final String path) { builder.includePath(path); } @Override - public void includePathAndAnnotation(String path, String annotation) { + public void includePathAndAnnotation(final String path, final String annotation) { builder.includePathAndAnnotation(path, annotation); } @@ -86,7 +86,7 @@ public class XmlSnapshotServiceDefault implements XmlSnapshotService { */ @Override public XmlSnapshotService.Snapshot snapshotFor(final Object domainObject) { - final ManagedObject adapter = ManagedObject.lazy(specificationLoader, domainObject); + final ManagedObject adapter = ManagedObject.wrapScalar(specificationLoader, domainObject); return new XmlSnapshot(adapter); } diff --git a/extensions/vw/fullcalendar/wicket/ui/src/main/java/org/apache/isis/extensions/fullcalendar/wkt/viewer/EventProviderAbstract.java b/extensions/vw/fullcalendar/wicket/ui/src/main/java/org/apache/isis/extensions/fullcalendar/wkt/viewer/EventProviderAbstract.java index c9c7590451..012cacff38 100644 --- a/extensions/vw/fullcalendar/wicket/ui/src/main/java/org/apache/isis/extensions/fullcalendar/wkt/viewer/EventProviderAbstract.java +++ b/extensions/vw/fullcalendar/wicket/ui/src/main/java/org/apache/isis/extensions/fullcalendar/wkt/viewer/EventProviderAbstract.java @@ -121,7 +121,7 @@ public abstract class EventProviderAbstract implements EventProvider { final Object dereferencedObject = dereference(commonContext, domainObjectPojo); val dereferencedManagedObject = - ManagedObject.lazy(commonContext.getSpecificationLoader(), dereferencedObject); + ManagedObject.wrapScalar(commonContext.getSpecificationLoader(), dereferencedObject); val oid = ManagedObjects.bookmark(dereferencedManagedObject).orElse(null); if(oid!=null) { diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java index e2467c8a9d..621dfb6fcb 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java +++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java @@ -259,7 +259,7 @@ class IsisToWicketTreeAdapter { this.commonContext = commonContext; this.factoryService = commonContext.lookupServiceElseFail(FactoryService.class); this.pojoToAdapter = pojo -> - ManagedObject.lazy(commonContext.getSpecificationLoader(), pojo); + ManagedObject.wrapScalar(commonContext.getSpecificationLoader(), pojo); } private TreeAdapter wrappedTreeAdapter() { diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/DeepLinkServiceWicket.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/DeepLinkServiceWicket.java index cc3f891315..bbfdde5944 100644 --- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/DeepLinkServiceWicket.java +++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/DeepLinkServiceWicket.java @@ -58,7 +58,7 @@ public class DeepLinkServiceWicket implements DeepLinkService { @Override public URI deepLinkFor(final Object domainObject) { - final ManagedObject objectAdapter = ManagedObject.lazy(specificationLoader, domainObject); + final ManagedObject objectAdapter = ManagedObject.wrapScalar(specificationLoader, domainObject); final PageParameters pageParameters = PageParameterUtils.createPageParametersForObject(objectAdapter);