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/12 13:16:58 UTC

[isis] branch master updated: ISIS-2882: BigDecimal scale fixes

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 32c15d1  ISIS-2882: BigDecimal scale fixes
32c15d1 is described below

commit 32c15d185401e62c9b6801e2ffb2b62688d909f2
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Nov 12 14:16:47 2021 +0100

    ISIS-2882: BigDecimal scale fixes
    
    - framework default scale for BigDecimal is 16 (that is, if there is no
    scale explicitly specified)
    
    - however, for JDO/JPA entities, when not specified the default scale is
    0
---
 .../applib/adapters/ValueSemanticsAbstract.java    |  2 -
 .../isis/commons/internal/base/_Optionals.java     | 10 +++
 ...acetForPersistentBigDecimalWhenUnspecified.java | 73 ++++++++++++++++++++++
 examples/demo/pre-flight.adoc                      |  1 +
 ...DecimalFromJdoColumnAnnotationFacetFactory.java | 17 ++++-
 ... => MaxFractionalDigitsFacetFromJdoColumn.java} |  6 +-
 ...malFromJdoColumnAnnotationFacetFactoryTest.java |  2 +-
 ...DecimalFromJpaColumnAnnotationFacetFactory.java | 17 ++++-
 ...ctionalDigitsFacetFromJpaColumnAnnotation.java} |  6 +-
 9 files changed, 123 insertions(+), 11 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/adapters/ValueSemanticsAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/adapters/ValueSemanticsAbstract.java
index 50606a8..e5f3b1a 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/adapters/ValueSemanticsAbstract.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/adapters/ValueSemanticsAbstract.java
@@ -130,9 +130,7 @@ implements
         }
         val format = getNumberFormat(context);
         format.setParseBigDecimal(true);
-        System.err.printf("before configure %d%n", format.getMaximumFractionDigits()); //FIXME[ISIS-2741] debug remove
         configureDecimalFormat(context, format);
-        System.err.printf("after configure %d%n", format.getMaximumFractionDigits()); //FIXME[ISIS-2741] debug remove
 
         val position = new ParsePosition(0);
         try {
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java
index 991d7b4..ec1e8b2 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java
@@ -19,7 +19,9 @@
 package org.apache.isis.commons.internal.base;
 
 import java.util.Optional;
+import java.util.OptionalInt;
 import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
 
 import lombok.experimental.UtilityClass;
 
@@ -42,4 +44,12 @@ public class _Optionals {
     }
 
 
+    public <T> OptionalInt toInt(
+            final Optional<T> optional,
+            final ToIntFunction<? super T> mapper) {
+        return optional.isPresent()
+            ? OptionalInt.of(mapper.applyAsInt(optional.get()))
+            : OptionalInt.empty();
+    }
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/digits/MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/digits/MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified.java
new file mode 100644
index 0000000..b25be82
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/digits/MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified.java
@@ -0,0 +1,73 @@
+/*
+ *  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.facets.objectvalue.digits;
+
+import java.math.BigDecimal;
+import java.util.Optional;
+import java.util.OptionalInt;
+
+import org.apache.isis.core.config.beans.IsisBeanTypeRegistry;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessMethodContext;
+
+import lombok.val;
+
+/**
+ * With {@link BigDecimal}, both JDO and JPA, if left unspecified,
+ * default their max-fractional digits to 0.
+ * (However, I could not find specific documents to support this claim.)
+ *
+ * @apiNote This facet should be applied in the absence of a corresponding {@code @Column} annotation,
+ * but only for properties of type {@link BigDecimal} that appear within a (persistable) entity.
+ * However, entities might extend abstract classes, where the framework - on type introspection -
+ * cannot distinguish entity from non-entity type.
+ * It is safe to assume that mixed-in properties are not to consider here.
+ */
+public class MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified
+extends MaxFractionalDigitsFacetAbstract {
+
+    public static Optional<MaxFractionalDigitsFacet> create(
+            final OptionalInt scaleIfAny,
+            final ProcessMethodContext processMethodContext,
+            final IsisBeanTypeRegistry beanTypeRegistry) {
+
+        val cls = processMethodContext.getCls();
+        val facetHolder = processMethodContext.getFacetHolder();
+
+        // only applies in a very specific context, see class java-doc
+        if(facetHolder.getFeatureType().isProperty()
+                || !processMethodContext.getMethod().getReturnType().equals(BigDecimal.class)
+                || !beanTypeRegistry.getEntityTypes().contains(cls)) {
+            return Optional.empty();
+        }
+
+        final int scale = scaleIfAny.orElse(-1);
+
+        return scale<0
+                ? Optional.of(new MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified(
+                        facetHolder))
+                : Optional.empty();
+    }
+
+    private MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified(
+            final FacetHolder holder) {
+        super(0, holder);
+    }
+
+}
diff --git a/examples/demo/pre-flight.adoc b/examples/demo/pre-flight.adoc
index 42610bd..037c8b6 100644
--- a/examples/demo/pre-flight.adoc
+++ b/examples/demo/pre-flight.adoc
@@ -80,6 +80,7 @@ Returns scalar of: `demo.StatefulVmUsingJaxb`
 * [ ] Test: click on the viewmodel's title, should render the very same thing
 
 IMPORTANT: renders an empty object (JAXB serialization is not working as expected here)   
+
 * [ ] Test: open a Child, then return to previous page (browser back button)
 
 [IMPORTANT]
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactory.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactory.java
index 29a21d9..b927b02 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactory.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactory.java
@@ -19,17 +19,21 @@
 package org.apache.isis.persistence.jdo.metamodel.facets.prop.column;
 
 import java.math.BigDecimal;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.jdo.annotations.Column;
 import javax.jdo.annotations.IdentityType;
 
+import org.apache.isis.commons.internal.base._Optionals;
+import org.apache.isis.core.config.beans.IsisBeanTypeRegistry;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified;
 import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxTotalDigitsFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
@@ -44,9 +48,12 @@ public class BigDecimalFromJdoColumnAnnotationFacetFactory
 extends FacetFactoryAbstract
 implements MetaModelRefiner {
 
+    private Optional<IsisBeanTypeRegistry> beanTypeRegistryIfAny; // JUnit support (allowed to be empty)
+
     @Inject
     public BigDecimalFromJdoColumnAnnotationFacetFactory(final MetaModelContext mmc) {
         super(mmc, FeatureType.PROPERTIES_ONLY);
+        beanTypeRegistryIfAny = mmc.getServiceRegistry().lookupService(IsisBeanTypeRegistry.class);
     }
 
     @Override
@@ -65,8 +72,16 @@ implements MetaModelRefiner {
                 .create(jdoColumnIfAny, holder));
 
         addFacetIfPresent(
-                MaxFractionDigitsFacetInferredFromJdoColumn
+                MaxFractionalDigitsFacetFromJdoColumn
                 .create(jdoColumnIfAny, holder));
+
+        // adds additional constraints if applicable
+        beanTypeRegistryIfAny.ifPresent(beanTypeRegistry->{
+            addFacetIfPresent(
+                    MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified
+                    .create(_Optionals.toInt(jdoColumnIfAny, Column::scale), processMethodContext, beanTypeRegistry));
+        });
+
     }
 
     @Override
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxFractionDigitsFacetInferredFromJdoColumn.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxFractionalDigitsFacetFromJdoColumn.java
similarity index 90%
rename from persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxFractionDigitsFacetInferredFromJdoColumn.java
rename to persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxFractionalDigitsFacetFromJdoColumn.java
index 87aa6a3..f87f784 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxFractionDigitsFacetInferredFromJdoColumn.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxFractionalDigitsFacetFromJdoColumn.java
@@ -26,7 +26,7 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacetAbstract;
 
-public class MaxFractionDigitsFacetInferredFromJdoColumn
+public class MaxFractionalDigitsFacetFromJdoColumn
 extends MaxFractionalDigitsFacetAbstract {
 
      public static Optional<MaxFractionalDigitsFacet> create(
@@ -36,12 +36,12 @@ extends MaxFractionalDigitsFacetAbstract {
          return jdoColumnIfAny
          .filter(jdoColumn->jdoColumn.scale()>=0)
          .map(jdoColumn->{
-             return new MaxFractionDigitsFacetInferredFromJdoColumn(
+             return new MaxFractionalDigitsFacetFromJdoColumn(
                      jdoColumn.scale(), holder);
          });
     }
 
-    private MaxFractionDigitsFacetInferredFromJdoColumn(
+    private MaxFractionalDigitsFacetFromJdoColumn(
             final int maxFractionalDigits, final FacetHolder holder) {
         super(maxFractionalDigits, holder);
     }
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactoryTest.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactoryTest.java
index 2006bfd..4b27ef7 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactoryTest.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalFromJdoColumnAnnotationFacetFactoryTest.java
@@ -114,7 +114,7 @@ extends AbstractFacetFactoryTest {
         if(maxFractionalDigits>=0) {
             final MaxFractionalDigitsFacet facet = facetedMethod.getFacet(MaxFractionalDigitsFacet.class);
             assertNotNull(facet);
-            assertTrue(facet instanceof MaxFractionDigitsFacetInferredFromJdoColumn);
+            assertTrue(facet instanceof MaxFractionalDigitsFacetFromJdoColumn);
             assertThat(facet.getMaxFractionalDigits(), is(maxFractionalDigits));
         } else {
             assertNull(facetedMethod.getFacet(MaxFractionalDigitsFacet.class));
diff --git a/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/BigDecimalFromJpaColumnAnnotationFacetFactory.java b/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/BigDecimalFromJpaColumnAnnotationFacetFactory.java
index cf7d908..c2b0d3f 100644
--- a/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/BigDecimalFromJpaColumnAnnotationFacetFactory.java
+++ b/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/BigDecimalFromJpaColumnAnnotationFacetFactory.java
@@ -19,23 +19,30 @@
 package org.apache.isis.persistence.jpa.metamodel.facets.prop.column;
 
 import java.math.BigDecimal;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.persistence.Column;
 
+import org.apache.isis.commons.internal.base._Optionals;
+import org.apache.isis.core.config.beans.IsisBeanTypeRegistry;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified;
 
 import lombok.val;
 
 public class BigDecimalFromJpaColumnAnnotationFacetFactory
 extends FacetFactoryAbstract {
 
+    private Optional<IsisBeanTypeRegistry> beanTypeRegistryIfAny; // JUnit support (allowed to be empty)
+
     @Inject
     public BigDecimalFromJpaColumnAnnotationFacetFactory(final MetaModelContext mmc) {
         super(mmc, FeatureType.PROPERTIES_ONLY);
+        beanTypeRegistryIfAny = mmc.getServiceRegistry().lookupService(IsisBeanTypeRegistry.class);
     }
 
     @Override
@@ -54,8 +61,16 @@ extends FacetFactoryAbstract {
                 .create(jpaColumnIfAny, holder));
 
         addFacetIfPresent(
-                MaxFractionDigitsFacetFromJpaColumnAnnotation
+                MaxFractionalDigitsFacetFromJpaColumnAnnotation
                 .create(jpaColumnIfAny, holder));
+
+        // adds additional constraints if applicable
+        beanTypeRegistryIfAny.ifPresent(beanTypeRegistry->{
+            addFacetIfPresent(
+                    MaxFractionalDigitsFacetForPersistentBigDecimalWhenUnspecified
+                    .create(_Optionals.toInt(jpaColumnIfAny, Column::scale), processMethodContext, beanTypeRegistry));
+        });
+
     }
 
 }
diff --git a/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/MaxFractionDigitsFacetFromJpaColumnAnnotation.java b/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/MaxFractionalDigitsFacetFromJpaColumnAnnotation.java
similarity index 89%
rename from persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/MaxFractionDigitsFacetFromJpaColumnAnnotation.java
rename to persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/MaxFractionalDigitsFacetFromJpaColumnAnnotation.java
index 40d0f0c..c404f6f 100644
--- a/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/MaxFractionDigitsFacetFromJpaColumnAnnotation.java
+++ b/persistence/jpa/metamodel/src/main/java/org/apache/isis/persistence/jpa/metamodel/facets/prop/column/MaxFractionalDigitsFacetFromJpaColumnAnnotation.java
@@ -26,7 +26,7 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacetAbstract;
 
-public class MaxFractionDigitsFacetFromJpaColumnAnnotation
+public class MaxFractionalDigitsFacetFromJpaColumnAnnotation
 extends MaxFractionalDigitsFacetAbstract {
 
      public static Optional<MaxFractionalDigitsFacet> create(
@@ -36,12 +36,12 @@ extends MaxFractionalDigitsFacetAbstract {
          return jpaColumnIfAny
          .filter(jpaColumn->jpaColumn.scale()>=0)
          .map(jdoColumn->{
-             return new MaxFractionDigitsFacetFromJpaColumnAnnotation(
+             return new MaxFractionalDigitsFacetFromJpaColumnAnnotation(
                      jdoColumn.scale(), holder);
          });
     }
 
-    private MaxFractionDigitsFacetFromJpaColumnAnnotation(
+    private MaxFractionalDigitsFacetFromJpaColumnAnnotation(
             final int maxFractionalDigits, final FacetHolder holder) {
         super(maxFractionalDigits, holder);
     }