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 2021/11/02 09:56:39 UTC

[isis] branch master updated: ISIS-2741: introduce IConverter (wkt) which is purely based on value-semantics

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 061f712  ISIS-2741: introduce IConverter (wkt) which is purely based on value-semantics
061f712 is described below

commit 061f71280f01b3e13808b65857504df239098782
Author: andi-huber <ah...@apache.org>
AuthorDate: Tue Nov 2 10:55:59 2021 +0100

    ISIS-2741: introduce IConverter (wkt) which is purely based on
    value-semantics
---
 .../_testing/MetaModelContext_forTesting.java      |  21 +++-
 .../interaction/DomainObjectTesterFactory.java     |   2 +-
 .../scalars/ConverterBasedOnValueSemantics.java    | 133 +++++++++++++++++++++
 .../components/scalars/IsisConverterLocator.java   |   3 +
 ...BigDecimalConverterWithScaleTest_roundtrip.java |  92 +++++++-------
 5 files changed, 197 insertions(+), 54 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
index 56ea5a5..e0d8563 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/_testing/MetaModelContext_forTesting.java
@@ -28,10 +28,9 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static java.util.Objects.requireNonNull;
-
 import org.springframework.core.env.AbstractEnvironment;
 
+import org.apache.isis.applib.adapters.ValueSemanticsProvider;
 import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.applib.services.grid.GridLoaderService;
 import org.apache.isis.applib.services.grid.GridService;
@@ -63,6 +62,7 @@ import org.apache.isis.core.config.beans.IsisBeanTypeClassifier;
 import org.apache.isis.core.config.beans.IsisBeanTypeRegistry;
 import org.apache.isis.core.config.beans.IsisBeanTypeRegistryDefault;
 import org.apache.isis.core.config.environment.IsisSystemEnvironment;
+import org.apache.isis.core.config.valuetypes.ValueSemanticsRegistry;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.execution.MemberExecutorService;
 import org.apache.isis.core.metamodel.facets.object.icon.ObjectIconService;
@@ -91,6 +91,8 @@ import org.apache.isis.core.metamodel.valuetypes.ValueSemanticsRegistryDefault;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
 import org.apache.isis.core.security.authorization.manager.AuthorizationManager;
 
+import static java.util.Objects.requireNonNull;
+
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NonNull;
@@ -131,7 +133,7 @@ implements MetaModelContext {
     private SpecificationLoader specificationLoader;
 
     @Builder.Default
-    private Function<MetaModelContext,  ProgrammingModel> programmingModelFactory = ProgrammingModelFacetsJava11::new;
+    private Function<MetaModelContext, ProgrammingModel> programmingModelFactory = ProgrammingModelFacetsJava11::new;
 
     private InteractionProvider interactionProvider;
 
@@ -168,6 +170,9 @@ implements MetaModelContext {
     private List<Object> singletons;
 
     @Singular
+    private List<ValueSemanticsProvider<?>> valueSemantics;
+
+    @Singular
     private List<_ManagedBeanAdapter> singletonProviders;
 
     // -- SERVICE SUPPORT
@@ -213,7 +218,7 @@ implements MetaModelContext {
                 repositoryService,
                 transactionService,
                 transactionState,
-                new ValueSemanticsRegistryDefault(List.of(), getTranslationService()),
+                getValueSemanticsRegistry(),
                 new ObjectMementoService_forTesting(),
                 new BigDecimalValueSemantics(),
                 new URLValueSemantics(),
@@ -290,6 +295,14 @@ implements MetaModelContext {
         return translationService;
     }
 
+    private ValueSemanticsRegistry valueSemanticsRegistry;
+    private ValueSemanticsRegistry getValueSemanticsRegistry(){
+        if(valueSemanticsRegistry==null) {
+            valueSemanticsRegistry = new ValueSemanticsRegistryDefault(valueSemantics, getTranslationService());
+        }
+        return valueSemanticsRegistry;
+    }
+
     private final IsisBeanFactoryPostProcessorForSpring isisBeanFactoryPostProcessorForSpring =
             new IsisBeanFactoryPostProcessorForSpring();
 
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java
index 09ee8f4..2cd23f5 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java
@@ -743,7 +743,7 @@ public class DomainObjectTesterFactory {
 
         protected abstract Optional<ObjectSpecification> getElementType();
 
-        public ObjectSpecification getElementTypeElseFaile() {
+        public ObjectSpecification getElementTypeElseFail() {
             return getElementType().orElseThrow();
         }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ConverterBasedOnValueSemantics.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ConverterBasedOnValueSemantics.java
new file mode 100644
index 0000000..8f0b61a
--- /dev/null
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ConverterBasedOnValueSemantics.java
@@ -0,0 +1,133 @@
+/*
+ *  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.viewer.wicket.ui.components.scalars;
+
+import java.util.Locale;
+
+import org.apache.wicket.util.convert.ConversionException;
+import org.apache.wicket.util.convert.IConverter;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.commons.internal.base._Either;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.runtime.context.IsisAppCommonContext;
+import org.apache.isis.core.runtime.context.IsisAppCommonContext.HasCommonContext;
+import org.apache.isis.viewer.wicket.model.util.CommonContextUtils;
+
+import lombok.Synchronized;
+import lombok.val;
+
+public abstract class ConverterBasedOnValueSemantics<T>
+implements
+    IConverter<T>,
+    HasCommonContext {
+
+    private static final long serialVersionUID = 1L;
+
+    private final Identifier featureIdentifier;
+    private final int paramIndex;
+    private transient _Either<OneToOneAssociation,  ObjectActionParameter> propOrParam;
+    private transient IsisAppCommonContext commonContext;
+
+    protected ConverterBasedOnValueSemantics(final ObjectFeature propOrParam) {
+        this.propOrParam = propOrParam instanceof OneToOneAssociation // memoize
+                ? _Either.left((OneToOneAssociation)propOrParam)
+                : _Either.right((ObjectActionParameter)propOrParam);
+        this.featureIdentifier = propOrParam.getFeatureIdentifier();
+        this.paramIndex = this.propOrParam.fold(
+                prop->-1,
+                param->param.getParameterIndex());
+    }
+
+    /**
+     * Parameter {@code locale} is ignored!
+     * @see IConverter#convertToObject(String, Locale)
+     */
+    @Override
+    public T convertToObject(final String text, final Locale locale) throws ConversionException {
+
+        val feature = feature();
+        val valueFacet = valueFacet();
+
+        val context = valueFacet
+                .createValueSemanticsContext(feature.getFeatureIdentifier());
+
+        return valueFacet.selectParserForFeatureElseFallback(feature)
+                .parseTextRepresentation(context, text);
+    }
+
+    /**
+     * Parameter {@code locale} is ignored!
+     * @see IConverter#convertToString(String, Locale)
+     */
+    @Override
+    public String convertToString(final T value, final Locale locale) {
+
+        val feature = feature();
+        val valueFacet = valueFacet();
+
+        val context = valueFacet
+                .createValueSemanticsContext(feature.getFeatureIdentifier());
+
+        return valueFacet.selectParserForFeatureElseFallback(feature)
+                .parseableTextRepresentation(context, value);
+    }
+
+    // -- HELPER
+
+    @Synchronized
+    private ObjectFeature feature() {
+        if(propOrParam==null) {
+            val typeSpec = getSpecificationLoader().specForLogicalTypeElseFail(featureIdentifier.getLogicalType());
+            val member = typeSpec.getMemberElseFail(featureIdentifier.getMemberLogicalName());
+            this.propOrParam = this.paramIndex<0
+                    ? _Either.left((OneToOneAssociation)member)
+                    : _Either.right(((ObjectAction)member).getParameters().getElseFail(paramIndex));
+        }
+        return propOrParam.fold(
+                ObjectFeature.class::cast,
+                ObjectFeature.class::cast);
+    }
+
+    @SuppressWarnings("unchecked")
+    private ValueFacet<T> valueFacet() {
+
+        val feature = feature();
+        val valueFacet = feature.getElementType()
+                .lookupFacet(ValueFacet.class)
+                .orElseThrow(()->_Exceptions.noSuchElement(
+                        "Value type Property or Parameter %s is missing a ValueFacet",
+                        feature.getFeatureIdentifier()));
+
+        return valueFacet;
+    }
+
+    // -- DEPENDENCIES
+
+    @Override
+    public IsisAppCommonContext getCommonContext() {
+        return commonContext = CommonContextUtils.computeIfAbsent(commonContext);
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/IsisConverterLocator.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/IsisConverterLocator.java
index 969b07d..2ab8fd7 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/IsisConverterLocator.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/IsisConverterLocator.java
@@ -23,6 +23,7 @@ import org.apache.wicket.IConverterLocator;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.BigIntegerConverter;
 
+import org.apache.isis.applib.adapters.ValueSemanticsProvider;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxFractionalDigitsFacet;
@@ -41,7 +42,9 @@ import lombok.val;
 
 /**
  * A locator for IConverters for ObjectAdapters
+ * @deprecated instead use {@link ValueSemanticsProvider}
  */
+@Deprecated(forRemoval = true, since = "2.0.0-M7")
 public class IsisConverterLocator {
 
     /**
diff --git a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScaleTest_roundtrip.java b/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScaleTest_roundtrip.java
index 554fcdb..98b8040 100644
--- a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScaleTest_roundtrip.java
+++ b/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScaleTest_roundtrip.java
@@ -22,13 +22,14 @@ import java.math.BigDecimal;
 import java.util.Locale;
 
 import org.apache.wicket.util.convert.ConversionException;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
-public class BigDecimalConverterWithScaleTest_roundtrip {
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class BigDecimalConverterWithScaleTest_roundtrip {
 
     final BigDecimal bd_123_45_scale2 = new BigDecimal("123.45").setScale(2);
     final BigDecimal bd_123_4500_scale2 = new BigDecimal("123.4500").setScale(2);
@@ -40,104 +41,97 @@ public class BigDecimalConverterWithScaleTest_roundtrip {
 
     private BigDecimalConverterWithScale converter;
 
-    @Rule
-    public ExpectedException exception = ExpectedException.none();
-
-    @Before
-    public void setUp() throws Exception {
+    @BeforeEach
+    void setUp() throws Exception {
         converter = newConverter(2);
     }
 
     @Test
-    public void scale2_english() {
+    void scale2_english() {
 
         // when
         final BigDecimal actual = converter.convertToObject("123.45", Locale.ENGLISH);
-        Assert.assertEquals(bd_123_4500_scale2, actual);
-        Assert.assertEquals(bd_123_45_scale2, actual);
+        assertEquals(bd_123_4500_scale2, actual);
+        assertEquals(bd_123_45_scale2, actual);
 
-        Assert.assertNotEquals(bd_123_4500_scale4, actual);
-        Assert.assertNotEquals(bd_123_45_scale4, actual);
+        assertNotEquals(bd_123_4500_scale4, actual);
+        assertNotEquals(bd_123_45_scale4, actual);
 
         // when
         String actualStr = converter.convertToString(actual, Locale.ENGLISH);
-        Assert.assertEquals("123.45", actualStr);
+        assertEquals("123.45", actualStr);
     }
 
     @Test
-    public void scale4_english() {
+    void scale4_english() {
         converter = newConverter(4);
 
         final BigDecimal actual = converter.convertToObject("123.45", Locale.ENGLISH);
-        Assert.assertNotEquals(bd_123_4500_scale2, actual);
-        Assert.assertNotEquals(bd_123_45_scale2, actual);
+        assertNotEquals(bd_123_4500_scale2, actual);
+        assertNotEquals(bd_123_45_scale2, actual);
 
-        Assert.assertEquals(bd_123_4500_scale4, actual);
-        Assert.assertEquals(bd_123_45_scale4, actual);
+        assertEquals(bd_123_4500_scale4, actual);
+        assertEquals(bd_123_45_scale4, actual);
 
         // when
         String actualStr = converter.convertToString(actual, Locale.ENGLISH);
-        Assert.assertEquals("123.4500", actualStr);
+        assertEquals("123.4500", actualStr);
     }
 
 
     @Test
-    public void scaleNull_english() {
+    void scaleNull_english() {
         converter = newConverter(null);
 
         final BigDecimal actual = converter.convertToObject("123.45", Locale.ENGLISH);
-        Assert.assertEquals(bd_123_4500_scale2, actual);
-        Assert.assertEquals(bd_123_45_scale2, actual);
+        assertEquals(bd_123_4500_scale2, actual);
+        assertEquals(bd_123_45_scale2, actual);
 
         final BigDecimal actual2 = converter.convertToObject("123.4500", Locale.ENGLISH);
-        Assert.assertEquals(bd_123_4500_scale4, actual2);
-        Assert.assertEquals(bd_123_45_scale4, actual2);
+        assertEquals(bd_123_4500_scale4, actual2);
+        assertEquals(bd_123_45_scale4, actual2);
     }
 
 
     @Test
-    public void scale2_italian() {
+    void scale2_italian() {
 
         final BigDecimal actual = converter.convertToObject("123,45", Locale.ITALIAN);
-        Assert.assertEquals(bd_123_4500_scale2, actual);
-        Assert.assertEquals(bd_123_45_scale2, actual);
+        assertEquals(bd_123_4500_scale2, actual);
+        assertEquals(bd_123_45_scale2, actual);
 
-        Assert.assertNotEquals(bd_123_4500_scale4, actual);
-        Assert.assertNotEquals(bd_123_45_scale4, actual);
+        assertNotEquals(bd_123_4500_scale4, actual);
+        assertNotEquals(bd_123_45_scale4, actual);
     }
 
 
     @Test
-    public void scale2_english_withThousandSeparators() {
-
-        exception.expect(ConversionException.class);
-        exception.expectMessage("Thousands separator ',' is not allowed in input");
-
-        converter.convertToObject("789,123.45", Locale.ENGLISH);
+    void scale2_english_withThousandSeparators() {
+        assertThrows(ConversionException.class, ()->
+            converter.convertToObject("789,123.45", Locale.ENGLISH),
+            "Thousands separator ',' is not allowed in input");
     }
 
     @Test
-    public void scale2_english_withoutThousandSeparators() {
+    void scale2_english_withoutThousandSeparators() {
 
         // when
         final BigDecimal actual = converter.convertToObject("789123.45", Locale.ENGLISH);
-        Assert.assertEquals(bd_789123_45_scale2, actual);
+        assertEquals(bd_789123_45_scale2, actual);
 
         // when
         String actualStr = converter.convertToString(actual, Locale.ENGLISH);
-        Assert.assertEquals("789123.45", actualStr);
+        assertEquals("789123.45", actualStr);
     }
 
     @Test
-    public void scale2_english_tooLargeScale() {
-
-        exception.expect(ConversionException.class);
-        exception.expectMessage("No more than 2 digits can be entered after the decimal place");
-
-        converter.convertToObject("123.454", Locale.ENGLISH);
+    void scale2_english_tooLargeScale() {
+        assertThrows(ConversionException.class, ()->
+            converter.convertToObject("123.454", Locale.ENGLISH),
+            "No more than 2 digits can be entered after the decimal place");
     }
 
-    private BigDecimalConverterWithScale newConverter(Integer scale) {
+    private BigDecimalConverterWithScale newConverter(final Integer scale) {
         return new BigDecimalConverterWithScale(scale);
     }