You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/08/29 09:26:58 UTC

[isis] branch master updated: ISIS-3167: purge _ManagedObjectWithLazySpec

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


The following commit(s) were added to refs/heads/master by this push:
     new cefdf288ff ISIS-3167: purge _ManagedObjectWithLazySpec
cefdf288ff is described below

commit cefdf288ff58ce550c5db5dcd2529bb854b0779a
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Aug 29 11:26:50 2022 +0200

    ISIS-3167: purge _ManagedObjectWithLazySpec
---
 .../isis/core/metamodel/object/ManagedObject.java  | 22 ------
 .../object/_ManagedObjectWithLazySpec.java         | 79 ----------------------
 ...entNegotiationServiceForRestfulObjectsV1_0.java | 11 ++-
 .../JsonValueEncoderServiceDefault.java            | 75 +++++++++++++-------
 .../JsonValueEncoderTest_asAdapter.java            | 31 +++++----
 5 files changed, 75 insertions(+), 143 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 17eca64550..41f3dadbba 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
@@ -538,26 +538,4 @@ public interface ManagedObject extends HasMetaModelContext {
         return _ManagedObjectWithEagerSpec.identified(spec, pojo, bookmark);
     }
 
-    /**
-     * For cases, when the pojo's specification is not available and needs to be looked up.
-     * @param specLoader
-     * @param pojo
-     */
-    @Deprecated
-    static ManagedObject lazy(
-            final SpecificationLoader specLoader,
-            final Object pojo) {
-
-        if(pojo!=null) {
-            _Assert.assertFalse(_Collections.isCollectionOrArrayOrCanType(pojo.getClass()));
-        }
-
-        ManagedObjects.assertPojoNotWrapped(pojo);
-        val adapter = new _ManagedObjectWithLazySpec(cls->specLoader.specForType(cls).orElse(null), pojo);
-        //ManagedObjects.warnIfAttachedEntity(adapter, "consider using ManagedObject.identified(...) for entity");
-        return adapter;
-    }
-
-
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithLazySpec.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithLazySpec.java
deleted file mode 100644
index 0ca4c35c08..0000000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithLazySpec.java
+++ /dev/null
@@ -1,79 +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.isis.core.metamodel.object;
-
-import java.util.function.Function;
-import java.util.function.UnaryOperator;
-
-import org.apache.isis.commons.internal.base._Lazy;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NonNull;
-
-@Deprecated
-@EqualsAndHashCode(of = "pojo", callSuper = false)
-final class _ManagedObjectWithLazySpec
-extends _ManagedObjectWithBookmark {
-
-    @NonNull private final Function<Class<?>, ObjectSpecification> specLoader;
-
-    @Getter @NonNull private /*final*/ Object pojo;
-
-    private final _Lazy<ObjectSpecification> specification = _Lazy.threadSafe(this::loadSpec);
-
-    _ManagedObjectWithLazySpec(
-            final @NonNull Function<Class<?>, ObjectSpecification> specLoader,
-            final @NonNull Object pojo) {
-        super(ManagedObject.Specialization.UNSPECIFIED); // FIXME
-        this.specLoader = specLoader;
-        this.pojo = pojo;
-    }
-
-    @Override
-    public ObjectSpecification getSpecification() {
-        return specification.get();
-    }
-
-    @Override //ISIS-2317 make sure toString() is without side-effects
-    public String toString() {
-        if(specification.isMemoized()) {
-            return String.format("ManagedObject[spec=%s, pojo=%s]",
-                    ""+getSpecification(),
-                    ""+getPojo());
-        }
-        return String.format("ManagedObject[spec=%s, pojo=%s]",
-                "[lazy not loaded]",
-                ""+getPojo());
-    }
-
-    private ObjectSpecification loadSpec() {
-        return specLoader.apply(pojo.getClass());
-    }
-
-    @Override
-    public void replacePojo(final UnaryOperator<Object> replacer) {
-        pojo = replacer.apply(pojo);
-        if(specification.isMemoized()) {
-            assertSpecIsInSyncWithPojo();
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceForRestfulObjectsV1_0.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceForRestfulObjectsV1_0.java
index 53fde969e6..0a4ffd3d0b 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceForRestfulObjectsV1_0.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceForRestfulObjectsV1_0.java
@@ -213,11 +213,16 @@ implements ContentNegotiationService {
                 final ObjectSpecification actionOwnerSpec = actionOwnerSpecFrom(objectAndActionInvocation);
                 final String actionId = actionIdFrom(objectAndActionInvocation);
                 final String actionArguments = actionArgumentsFrom(objectAndActionInvocation);
-                final DomainObjectList list = domainObjectListFrom(
+                final DomainObjectList listAsViewmodel = domainObjectListFrom(
                         collectionAdapters, elementSpec, actionOwnerSpec, actionId, actionArguments);
 
-                val listAdapter = ManagedObject.lazy(
-                        resourceContext.getMetaModelContext().getSpecificationLoader(), list);
+                val domainObjectListSpec = resourceContext.getMetaModelContext().getSpecificationLoader()
+                    .specForType(DomainObjectList.class)
+                    .filter(ObjectSpecification::isViewModel)
+                    .orElseThrow(()->_Exceptions.unrecoverable(
+                            "framework bug: DomainObjectList should be recognized as viewmodel"));
+
+                val listAdapter = ManagedObject.viewmodel(domainObjectListSpec, listAsViewmodel);
                 return responseBuilder(
                         buildResponse(
                                 resourceContext,
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java
index 56d99bb1b4..65766b0270 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java
@@ -33,10 +33,12 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.ClassUtils;
 
 import org.apache.isis.applib.annotation.PriorityPrecedence;
-import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
 import org.apache.isis.applib.value.semantics.ValueDecomposition;
+import org.apache.isis.commons.functional.Try;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.facets.object.value.ValueSerializer;
 import org.apache.isis.core.metamodel.facets.object.value.ValueSerializer.Format;
 import org.apache.isis.core.metamodel.object.ManagedObject;
 import org.apache.isis.core.metamodel.object.ManagedObjects;
@@ -71,57 +73,80 @@ public class JsonValueEncoderServiceDefault implements JsonValueEncoderService {
 
     @Override
     public ManagedObject asAdapter(
-            final ObjectSpecification objectSpec,
+            final ObjectSpecification spec,
             final JsonRepresentation valueRepr,
             final JsonValueConverter.Context context) {
 
         if(valueRepr == null) {
             return null;
         }
-        if (objectSpec == null) {
+        if (spec == null) {
             throw new IllegalArgumentException("ObjectSpecification is required");
         }
         if (!valueRepr.isValue()) {
             throw new IllegalArgumentException("Representation must be of a value");
         }
 
-        val valueClass = objectSpec.getCorrespondingClass();
+        val valueClass = spec.getCorrespondingClass();
         val valueSerializer =
-                Facets.valueSerializerElseFail(objectSpec, valueClass);
-
-        final JsonValueConverter jvc = converterByClass.get(ClassUtils.resolvePrimitiveIfNecessary(valueClass));
-        if(jvc == null) {
-            // best effort
-            if (valueRepr.isString()) {
-                final String argStr = valueRepr.asString();
-                return ManagedObject.of(objectSpec,
-                        valueSerializer.fromEncodedString(Format.JSON, argStr));
-            }
-            throw new IllegalArgumentException("Unable to parse value");
+                Facets.valueSerializerElseFail(spec, valueClass);
+
+        final JsonValueConverter jsonValueConverter = converterByClass
+                .get(ClassUtils.resolvePrimitiveIfNecessary(valueClass));
+        if(jsonValueConverter == null) {
+            // best effort: try 'String' type
+            return asStringElseFail(valueRepr, valueSerializer)
+                    .map(string->ManagedObject.value(spec, string))
+                    .orElseGet(()->ManagedObject.empty(spec));
         }
 
-        val valueAsPojo = jvc.recoverValueAsPojo(valueRepr, context);
+        val valueAsPojo = jsonValueConverter.recoverValueAsPojo(valueRepr, context);
         if(valueAsPojo != null) {
-            return ManagedObject.lazy(specificationLoader, valueAsPojo);
+            return ManagedObject.value(spec, valueAsPojo);
         }
 
         // last attempt
         if (valueRepr.isString()) {
-            final String argStr = valueRepr.asString();
-            try {
-                return ManagedObject.of(objectSpec,
-                        valueSerializer.fromEncodedString(Format.JSON, argStr));
-            } catch(TextEntryParseException ex) {
-                throw new IllegalArgumentException(ex.getMessage());
-            }
+            return asStringElseFail(valueRepr, valueSerializer)
+                    .map(string->ManagedObject.value(spec, string))
+                    .orElseGet(()->ManagedObject.empty(spec));
         }
 
         throw new IllegalArgumentException("Could not parse value '"
                 + valueRepr.asString()
                 + "' as a "
-                + objectSpec.getFullIdentifier());
+                + spec.getFullIdentifier());
+    }
+
+    /**
+     * Returns the recovered nullable String, wrapped as optional.
+     * @throws IllegalArgumentException if cannot be parsed as String
+     */
+    private static Optional<String> asStringElseFail(
+            final JsonRepresentation valueRepr,
+            final ValueSerializer<?> valueSerializer) {
+        if (valueRepr.isString()) {
+            val recoveredValue = Try.call(()->
+                    valueSerializer.fromEncodedString(Format.JSON, valueRepr.asString()))
+                    .mapFailure(ex->_Exceptions
+                            .illegalArgument(ex, "Unable to parse value %s as String", valueRepr))
+                    .ifFailureFail()
+                    .getValue().orElse(null);
+                    ;
+            if(recoveredValue==null) {
+                return Optional.empty();
+            }
+            val recoveredStringIfAny = _Casts.castTo(String.class, recoveredValue);
+            if(recoveredStringIfAny.isPresent()) {
+                return recoveredStringIfAny;
+            }
+            throw _Exceptions.illegalArgument("Unable to parse value %s as String", recoveredValue.getClass());
+        }
+        throw _Exceptions.illegalArgument("Unable to parse value %s as String"
+                + " (using 'String' as a fallback attempt)", valueRepr);
     }
 
+
     @Override
     public void appendValueAndFormat(
             final ManagedObject valueAdapter,
diff --git a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
index 9f986c74b4..592aaa0e12 100644
--- a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
+++ b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
@@ -38,6 +38,11 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
 import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
@@ -51,11 +56,6 @@ import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.rendering.service.valuerender.JsonValueEncoderService;
 import org.apache.isis.viewer.restfulobjects.rendering.service.valuerender.JsonValueEncoderServiceDefault;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-
 import lombok.val;
 
 public class JsonValueEncoderTest_asAdapter {
@@ -132,7 +132,7 @@ public class JsonValueEncoderTest_asAdapter {
         representation = new JsonRepresentation(BooleanNode.valueOf(value));
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(((Object)value).getClass());
+                allowing(specLoader).specForType(((Object)value).getClass());
                 will(returnValue(Optional.of(mockObjectSpec)));
             }
         });
@@ -152,7 +152,7 @@ public class JsonValueEncoderTest_asAdapter {
 
         context.checking(new Expectations() {
             {
-                oneOf(mockValueFacet).fromEncodedString(Format.JSON, "aString");
+                allowing(mockValueFacet).fromEncodedString(Format.JSON, "aString");
                 will(throwException(new TextEntryParseException("'aString' cannot be parsed as a boolean value")));
             }
         });
@@ -179,7 +179,7 @@ public class JsonValueEncoderTest_asAdapter {
         representation = new JsonRepresentation(IntNode.valueOf(value));
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(((Object)value).getClass());
+                allowing(specLoader).specForType(((Object)value).getClass());
                 will(returnValue(Optional.of(mockObjectSpec)));
             }
         });
@@ -221,7 +221,7 @@ public class JsonValueEncoderTest_asAdapter {
         representation = new JsonRepresentation(LongNode.valueOf(value));
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(((Object)value).getClass());
+                allowing(specLoader).specForType(((Object)value).getClass());
                 will(returnValue(Optional.of(mockObjectSpec)));
             }
         });
@@ -241,7 +241,7 @@ public class JsonValueEncoderTest_asAdapter {
 
         context.checking(new Expectations() {
             {
-                oneOf(mockValueFacet).fromEncodedString(Format.JSON, "aString");
+                allowing(mockValueFacet).fromEncodedString(Format.JSON, "aString");
                 will(throwException(new TextEntryParseException("'aString' cannot be parsed as a long value")));
             }
         });
@@ -268,7 +268,7 @@ public class JsonValueEncoderTest_asAdapter {
         representation = new JsonRepresentation(DoubleNode.valueOf(value));
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(((Object)value).getClass());
+                allowing(specLoader).specForType(((Object)value).getClass());
                 will(returnValue(Optional.of(mockObjectSpec)));
             }
         });
@@ -301,7 +301,7 @@ public class JsonValueEncoderTest_asAdapter {
         representation = new JsonRepresentation(BigIntegerNode.valueOf(value));
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(value.getClass());
+                allowing(specLoader).specForType(value.getClass());
                 will(returnValue(Optional.of(mockObjectSpec)));
             }
         });
@@ -334,7 +334,7 @@ public class JsonValueEncoderTest_asAdapter {
         representation = new JsonRepresentation(DecimalNode.valueOf(value));
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(value.getClass());
+                allowing(specLoader).specForType(value.getClass());
                 will(returnValue(Optional.of(mockObjectSpec)));
 
             }
@@ -368,7 +368,7 @@ public class JsonValueEncoderTest_asAdapter {
 
         context.checking(new Expectations() {
             {
-                oneOf(specLoader).specForType(String.class);
+                allowing(specLoader).specForType(String.class);
                 will(returnValue(Optional.of(mockObjectSpec)));
             }
         });
@@ -398,6 +398,9 @@ public class JsonValueEncoderTest_asAdapter {
                 allowing(mockValueFacet).getValueClass();
                 will(returnValue(valueClass));
 
+                allowing(mockObjectSpec).isNonScalar();
+                will(returnValue(true));
+
             }
         });
     }