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/06/28 05:53:52 UTC

[isis] branch master updated: ISIS-3049: early guard against incompatible scalar type for scalar panel with text-field

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 46335e25e8 ISIS-3049: early guard against incompatible scalar type for scalar panel with text-field
46335e25e8 is described below

commit 46335e25e80d0896b09f9094ce9182f782d4aef5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jun 28 07:53:46 2022 +0200

    ISIS-3049: early guard against incompatible scalar type for scalar panel
    with text-field
    
    - also convert anonymous component factories to static ones
---
 .../scalars/ScalarPanelTextFieldAbstract.java      |  17 ++-
 .../ComponentFactoryRegistrarDefault.java          | 144 +++++++++++----------
 2 files changed, 86 insertions(+), 75 deletions(-)

diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index 1a0c46d559..34338eca28 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -59,6 +59,7 @@ extends ScalarPanelFormFieldAbstract<T> {
             final ScalarModel scalarModel,
             final Class<T> type) {
         super(id, scalarModel, type);
+        guardAgainstIncompatibleScalarType();
     }
 
     // -- CONVERSION
@@ -92,13 +93,6 @@ extends ScalarPanelFormFieldAbstract<T> {
     }
 
     protected final IModel<T> unwrappedModel() {
-        _Assert.assertTrue(scalarModel().getScalarTypeSpec().isAssignableFrom(type), ()->
-            String.format("[%s:%s] cannot possibly unwrap model of type %s into target type %s",
-                    this.getClass().getSimpleName(),
-                    scalarModel().getIdentifier(),
-                    scalarModel().getScalarTypeSpec().getCorrespondingClass(),
-                    type));
-
         return scalarModel().unwrapped(type);
     }
 
@@ -138,6 +132,15 @@ extends ScalarPanelFormFieldAbstract<T> {
 
     // -- HELPER
 
+    private void guardAgainstIncompatibleScalarType() {
+        _Assert.assertTrue(scalarModel().getScalarTypeSpec().isAssignableFrom(type), ()->
+            String.format("[%s:%s] cannot possibly unwrap model of type %s into target type %s",
+                    this.getClass().getSimpleName(),
+                    scalarModel().getIdentifier(),
+                    scalarModel().getScalarTypeSpec().getCorrespondingClass(),
+                    type));
+    }
+
     <F extends FormComponent<?>> F applyFormComponentAttributes(final F formComponent) {
         val scalarModel = scalarModel();
         Wkt.setFormComponentAttributes(formComponent,
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index 910d070049..dd63fad31d 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@ -225,17 +225,8 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
         componentFactories.add(new IsisBlobPanelFactory());
         componentFactories.add(new IsisClobPanelFactory());
 
-        val registeredScalarTypes =
-            componentFactories.stream(ComponentFactoryScalarAbstract.class)
-            .flatMap(f->f.getScalarTypes().stream())
-            .collect(Collectors.toSet());
-
-        valueSemanticsResolver.streamClassesWithValueSemantics()
-            .filter(_Predicates.not(registeredScalarTypes::contains))
-            .flatMap(valueSemanticsResolver::streamValueSemantics)
-            //.peek(valueSemantics->System.err.printf("%s -> %s%n", valueSemantics, valueSemantics.getCorrespondingClass().getName()))
-            .map(valueSemantics->createForValueSemantics((ValueSemanticsProvider)valueSemantics))
-            .forEach(componentFactories::add);
+        // install after explicit values, but before fallbacks
+        addGenericComponentFactoriesForScalar(componentFactories);
 
         componentFactories.add(new ValueFallbackPanelFactory());
 
@@ -289,100 +280,117 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
     createForValueSemantics(final ValueSemanticsProvider<T> valueSemantics) {
 
         if(valueSemantics.isNumberType()) {
-            return createScalarPanelUsingNumberField(valueSemantics.getCorrespondingClass());
+            return new ScalarPanelFactoryForNumberField<T>(valueSemantics.getCorrespondingClass());
         }
 
         if(valueSemantics.isTemporalType()) {
-            return createScalarPanelUsingTemporalPicker(valueSemantics.getCorrespondingClass());
+            return new ScalarPanelFactoryForTemporalPicker<T>(valueSemantics.getCorrespondingClass());
         }
 
         if(valueSemantics.isCompositeType()) {
-            return createScalarPanelForComposite(valueSemantics.getCorrespondingClass());
+            return new ScalarPanelFactoryForCompositeValue<T>(valueSemantics.getCorrespondingClass());
         }
 
-        return createScalarPanelUsingTextField(valueSemantics.getCorrespondingClass());
+        return new ScalarPanelFactoryForTextField<T>(valueSemantics.getCorrespondingClass());
     }
 
-    public static <T extends Serializable> ComponentFactoryScalarAbstract
-    createScalarPanelUsingTextField(final Class<T> valueTypeClass) {
+    public static class ScalarPanelFactoryForTextField<T extends Serializable>
+    extends ComponentFactoryScalarAbstract {
 
-        var valueTypeClasses = withPrimitiveVariant(valueTypeClass);
+        private static final long serialVersionUID = 1L;
 
-        return new ComponentFactoryScalarAbstract(
-                ScalarPanelTextFieldWithValueSemantics.class,
-                valueTypeClasses) {
+        private final Class<T> valueTypeClass;
 
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public Component createComponent(final String id, final ScalarModel scalarModel) {
-                return new ScalarPanelTextFieldWithValueSemantics<T>(id, scalarModel, valueTypeClass);
-            }
+        protected ScalarPanelFactoryForTextField(final Class<T> valueTypeClass) {
+            super(ScalarPanelTextFieldWithValueSemantics.class, withPrimitiveVariant(valueTypeClass));
+            this.valueTypeClass = valueTypeClass;
+        }
 
-        };
+        @Override
+        public Component createComponent(final String id, final ScalarModel scalarModel) {
+            return new ScalarPanelTextFieldWithValueSemantics<T>(id, scalarModel, valueTypeClass);
+        }
     }
 
-    public static <T extends Serializable> ComponentFactoryScalarAbstract
-    createScalarPanelUsingNumberField(final Class<T> valueTypeClass) {
 
-        var valueTypeClasses = withPrimitiveVariant(valueTypeClass);
+    public static class ScalarPanelFactoryForNumberField<T extends Serializable>
+    extends ComponentFactoryScalarAbstract {
 
-        return new ComponentFactoryScalarAbstract(
-                ScalarPanelTextFieldNumeric.class,
-                valueTypeClasses) {
+        private static final long serialVersionUID = 1L;
 
-            private static final long serialVersionUID = 1L;
+        private final Class<T> valueTypeClass;
 
-            @Override
-            public Component createComponent(final String id, final ScalarModel scalarModel) {
-                return new ScalarPanelTextFieldNumeric<T>(id, scalarModel, valueTypeClass);
-            }
+        protected ScalarPanelFactoryForNumberField(final Class<T> valueTypeClass) {
+            super(ScalarPanelTextFieldNumeric.class, withPrimitiveVariant(valueTypeClass));
+            this.valueTypeClass = valueTypeClass;
+        }
 
-        };
+        @Override
+        public Component createComponent(final String id, final ScalarModel scalarModel) {
+            return new ScalarPanelTextFieldNumeric<T>(id, scalarModel, valueTypeClass);
+        }
     }
 
-    public static <T extends Serializable> ComponentFactoryScalarAbstract
-    createScalarPanelUsingTemporalPicker(final Class<T> valueTypeClass) {
-
-        // assuming there is no primitive temporal type
-        val valueTypeClasses = Can.<Class<?>>ofSingleton(valueTypeClass);
+    public static class ScalarPanelFactoryForTemporalPicker<T extends Serializable>
+    extends ComponentFactoryScalarAbstract {
 
-        return new ComponentFactoryScalarAbstract(
-                ScalarPanelTextFieldWithTemporalPicker.class,
-                valueTypeClasses) {
+        private static final long serialVersionUID = 1L;
 
-            private static final long serialVersionUID = 1L;
+        private final Class<T> valueTypeClass;
 
-            @Override
-            public Component createComponent(final String id, final ScalarModel scalarModel) {
-                return new ScalarPanelTextFieldWithTemporalPicker<T>(id, scalarModel, valueTypeClass);
-            }
+        protected ScalarPanelFactoryForTemporalPicker(final Class<T> valueTypeClass) {
+            super(ScalarPanelTextFieldWithTemporalPicker.class,
+                    // assuming there is no primitive temporal type
+                    Can.<Class<?>>ofSingleton(valueTypeClass));
+            this.valueTypeClass = valueTypeClass;
+        }
 
-        };
+        @Override
+        public Component createComponent(final String id, final ScalarModel scalarModel) {
+            return new ScalarPanelTextFieldWithTemporalPicker<T>(id, scalarModel, valueTypeClass);
+        }
     }
 
-    public static <T extends Serializable> ComponentFactoryScalarAbstract
-    createScalarPanelForComposite(final Class<T> valueTypeClass) {
+    public static class ScalarPanelFactoryForCompositeValue<T extends Serializable>
+    extends ComponentFactoryScalarAbstract {
 
-        // assuming there is no primitive composite type
-        val valueTypeClasses = Can.<Class<?>>ofSingleton(valueTypeClass);
+        private static final long serialVersionUID = 1L;
 
-        return new ComponentFactoryScalarAbstract(
-                CompositeValuePanel.class,
-                valueTypeClasses) {
+        private final Class<T> valueTypeClass;
 
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public Component createComponent(final String id, final ScalarModel scalarModel) {
-                return new CompositeValuePanel<T>(id, scalarModel, valueTypeClass);
-            }
+        protected ScalarPanelFactoryForCompositeValue(final Class<T> valueTypeClass) {
+            super(CompositeValuePanel.class,
+                    // assuming there is no primitive composite type
+                    Can.<Class<?>>ofSingleton(valueTypeClass));
+            this.valueTypeClass = valueTypeClass;
+        }
 
-        };
+        @Override
+        public Component createComponent(final String id, final ScalarModel scalarModel) {
+            return new CompositeValuePanel<T>(id, scalarModel, valueTypeClass);
+        }
     }
 
     // -- HELPER
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private void addGenericComponentFactoriesForScalar(
+            final ComponentFactoryList componentFactories) {
+
+        // collect those registered up to this point, so we don't override with generic ones at steps below
+        val registeredScalarTypes =
+                componentFactories.stream(ComponentFactoryScalarAbstract.class)
+                .flatMap(f->f.getScalarTypes().stream())
+                .collect(Collectors.toSet());
+
+        valueSemanticsResolver.streamClassesWithValueSemantics()
+            .filter(_Predicates.not(registeredScalarTypes::contains))
+            .flatMap(valueSemanticsResolver::streamValueSemantics)
+            //.peek(valueSemantics->System.err.printf("%s -> %s%n", valueSemantics, valueSemantics.getCorrespondingClass().getName()))
+            .map(valueSemantics->createForValueSemantics((ValueSemanticsProvider)valueSemantics))
+            .forEach(componentFactories::add);
+    }
+
     private static Can<Class<?>> withPrimitiveVariant(final @NonNull Class<?> valueTypeClass) {
         var valueTypeClasses = Can.<Class<?>>ofSingleton(valueTypeClass);