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/04 14:18:44 UTC

[isis] branch master updated: ISIS-2741: circumvent Wicket's built in conversion error messages

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 905dc97  ISIS-2741: circumvent Wicket's built in conversion error messages
905dc97 is described below

commit 905dc976edd9b32f4b73f6abad0b4bd8399d90cf
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Nov 4 15:18:14 2021 +0100

    ISIS-2741: circumvent Wicket's built in conversion error messages
    
    - move the responsibility to ValueSemanticsProviders
---
 .../specloader/specimpl/ObjectActionMixedIn.java   |   4 +-
 .../specloader/specimpl/ObjectMemberAbstract.java  |   2 +-
 .../bigdecimals/jdo/JavaMathBigDecimalJdo.java     |   7 +-
 .../bigdecimals/jpa/JavaMathBigDecimalJpa.java     |   7 +-
 .../viewer/common/model/feature/ScalarUiModel.java |  14 ---
 .../scalars/ConverterBasedOnValueSemantics.java    |  27 ++--
 .../components/scalars/IsisConverterLocator.java   | 128 -------------------
 .../scalars/ScalarPanelTextFieldAbstract.java      |   2 +-
 .../scalars/ScalarPanelTextFieldNumeric.java       |  45 +++----
 .../jdkmath/BigDecimalConverterForFeature.java     |  34 +++++
 .../jdkmath/BigDecimalConverterWithScale.java      | 134 --------------------
 .../scalars/jdkmath/BigDecimalTextField.java       |  60 ---------
 .../scalars/jdkmath/JavaMathBigDecimalPanel.java   |  27 ++--
 .../jdkmath/JavaMathBigDecimalPanelFactory.java    |  29 +----
 .../scalars/jdkmath/JavaMathBigIntegerPanel.java   |  25 ++--
 .../ui/components/scalars/primitive/BytePanel.java |  25 ++--
 .../components/scalars/primitive/DoublePanel.java  |  22 ++--
 .../components/scalars/primitive/FloatPanel.java   |  21 ++--
 .../components/scalars/primitive/IntegerPanel.java |  22 ++--
 .../ui/components/scalars/primitive/LongPanel.java |  22 ++--
 .../components/scalars/primitive/ShortPanel.java   |  22 ++--
 .../ObjectAdapterMementoProviderAbstract.java      |  17 +--
 .../org/apache/isis/viewer/wicket/ui/util/Wkt.java |  46 ++++++-
 ...BigDecimalConverterWithScaleTest_roundtrip.java | 138 ---------------------
 24 files changed, 208 insertions(+), 672 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index 0151122..ba78da8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -143,8 +143,8 @@ implements MixedInMember {
         return mixinAction.getChoices(mixinAdapter, interactionInitiatedBy);
     }
 
-    protected ManagedObject mixinAdapterFor(final ManagedObject mixedInAdapter) {
-        return mixinAdapterFor(mixinType, mixedInAdapter);
+    protected ManagedObject mixinAdapterFor(final ManagedObject mixeeAdapter) {
+        return mixinAdapterFor(mixinType, mixeeAdapter);
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
index 5c0ee55..319f254 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
@@ -280,7 +280,7 @@ implements
 
         val spec = getSpecificationLoader().loadSpecification(mixinType);
         val mixinFacet = spec.getFacet(MixinFacet.class);
-        val mixinPojo = mixinFacet.instantiate(Objects.requireNonNull(mixee.getPojo()));
+        val mixinPojo = mixinFacet.instantiate(mixee.getPojo() /*nullable for action parameter mixins*/);
         return ManagedObject.of(spec, Objects.requireNonNull(mixinPojo));
     }
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jdo/JavaMathBigDecimalJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jdo/JavaMathBigDecimalJdo.java
index a1762cb..31f6ad8 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jdo/JavaMathBigDecimalJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jdo/JavaMathBigDecimalJdo.java
@@ -52,7 +52,7 @@ public class JavaMathBigDecimalJdo                                          // <
     public JavaMathBigDecimalJdo(final java.math.BigDecimal initialValue) {
         this.readOnlyProperty = initialValue;
         this.readWriteProperty = initialValue;
-        this.withMaxScale = initialValue;
+        this.withMax2FractionDigits = initialValue;
     }
 
 //tag::class[]
@@ -69,10 +69,11 @@ public class JavaMathBigDecimalJdo                                          // <
     private java.math.BigDecimal readWriteProperty;
 
     @Property(editing = Editing.ENABLED)
-    @PropertyLayout(fieldSetId = "editable-properties", sequence = "2")
+    @PropertyLayout(fieldSetId = "editable-properties", sequence = "2",
+        describedAs = "has a maximum of 2 fraction digits (scale=2)")
     @Column(allowsNull = "false", scale = 2)                                // <.>
     @Getter @Setter
-    private java.math.BigDecimal withMaxScale;
+    private java.math.BigDecimal withMax2FractionDigits;
 
     @Property(optionality = Optionality.OPTIONAL)                           // <.>
     @PropertyLayout(fieldSetId = "optional-properties", sequence = "1")
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jpa/JavaMathBigDecimalJpa.java b/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jpa/JavaMathBigDecimalJpa.java
index 8413351..9d2c095 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jpa/JavaMathBigDecimalJpa.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/types/javamath/bigdecimals/jpa/JavaMathBigDecimalJpa.java
@@ -60,7 +60,7 @@ public class JavaMathBigDecimalJpa                                           //
     public JavaMathBigDecimalJpa(final java.math.BigDecimal initialValue) {
         this.readOnlyProperty = initialValue;
         this.readWriteProperty = initialValue;
-        this.withMaxScale = initialValue;
+        this.withMax2FractionDigits = initialValue;
     }
 
 //tag::class[]
@@ -81,10 +81,11 @@ public class JavaMathBigDecimalJpa                                           //
     private java.math.BigDecimal readWriteProperty;
 
     @Property(editing = Editing.ENABLED)
-    @PropertyLayout(fieldSetId = "editable-properties", sequence = "2")
+    @PropertyLayout(fieldSetId = "editable-properties", sequence = "2",
+            describedAs = "has a maximum of 2 fraction digits (scale=2)")
     @Column(nullable = false, scale = 2)                                    // <.>
     @Getter @Setter
-    private java.math.BigDecimal withMaxScale;
+    private java.math.BigDecimal withMax2FractionDigits;
 
     @Property(optionality = Optionality.OPTIONAL)                           // <.>
     @PropertyLayout(fieldSetId = "optional-properties", sequence = "1")
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/feature/ScalarUiModel.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/feature/ScalarUiModel.java
index 5de5317..bd759ad 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/feature/ScalarUiModel.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/feature/ScalarUiModel.java
@@ -24,7 +24,6 @@ import java.util.Optional;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
-import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxFractionDigitsFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxTotalDigitsFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -62,17 +61,6 @@ public interface ScalarUiModel {
                 .orElse(null);
     }
 
-    /**
-     * for {@link BigDecimal}s only.
-     *
-     * @see #getScale()
-     */
-    default Integer getScale() {
-        return getMetaModel().lookupFacet(MaxFractionDigitsFacet.class)
-                .map(MaxFractionDigitsFacet::getMaximumFractionDigits)
-                .orElse(null);
-    }
-
     default Integer getTypicalLength() {
         final TypicalLengthFacet facet = getMetaModel().getFacet(TypicalLengthFacet.class);
         return facet != null? facet.value() : null;
@@ -90,6 +78,4 @@ public interface ScalarUiModel {
     Can<ManagedObject> getChoices();
     Can<ManagedObject> getAutoComplete(final String searchArg);
 
-
-
 }
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
index 70d9d92..13d379f 100644
--- 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
@@ -27,7 +27,6 @@ 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;
@@ -46,7 +45,6 @@ implements
     private static final long serialVersionUID = 1L;
 
     private final Identifier featureIdentifier;
-    private final int paramIndex;
     private transient _Either<OneToOneAssociation,  ObjectActionParameter> propOrParam;
     private transient IsisAppCommonContext commonContext;
 
@@ -55,9 +53,6 @@ implements
                 ? _Either.left((OneToOneAssociation)propOrParam)
                 : _Either.right((ObjectActionParameter)propOrParam);
         this.featureIdentifier = propOrParam.getFeatureIdentifier();
-        this.paramIndex = this.propOrParam.fold(
-                prop->-1,
-                param->param.getParameterIndex());
     }
 
     /**
@@ -73,8 +68,16 @@ implements
         val context = valueFacet
                 .createValueSemanticsContext(feature);
 
-        return valueFacet.selectParserForFeatureElseFallback(feature)
-                .parseTextRepresentation(context, text);
+        try {
+            return valueFacet.selectParserForFeatureElseFallback(feature)
+                    .parseTextRepresentation(context, text);
+        } catch (Exception e) {
+            if(e instanceof ConversionException) {
+                throw e;
+            } else {
+                throw new ConversionException(e.getMessage(), e);
+            }
+        }
     }
 
     /**
@@ -99,11 +102,10 @@ implements
     @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));
+            val feature = getSpecificationLoader().loadFeature(featureIdentifier).orElse(null);
+            this.propOrParam = (feature instanceof OneToOneAssociation)
+                    ? _Either.left((OneToOneAssociation)feature)
+                    : _Either.right(((ObjectActionParameter)feature));
         }
         return propOrParam.fold(
                 ObjectFeature.class::cast,
@@ -112,7 +114,6 @@ implements
 
     @SuppressWarnings("unchecked")
     private ValueFacet<T> valueFacet() {
-
         val feature = feature();
         val valueFacet = feature.getElementType()
                 .lookupFacet(ValueFacet.class)
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
deleted file mode 100644
index f7b9905..0000000
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/IsisConverterLocator.java
+++ /dev/null
@@ -1,128 +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.viewer.wicket.ui.components.scalars;
-
-import org.apache.wicket.Application;
-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.MaxFractionDigitsFacet;
-import org.apache.isis.core.metamodel.facets.objectvalue.renderedadjusted.RenderedAdjustedFacet;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.DateConverterForJavaSqlDate;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.DateConverterForJavaSqlTimestamp;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.DateConverterForJavaUtilDate;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jdkmath.BigDecimalConverterWithScale;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.DateConverterForJodaDateTime;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.DateConverterForJodaLocalDate;
-import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.DateConverterForJodaLocalDateTime;
-
-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 {
-
-    /**
-     * Locates the best IConverter implementation for a given {@link ManagedObject}
-     *
-     * @param objectAdapter The object adapter to locate converter for
-     * @param wicketViewerSettings The date related settings
-     * @return The best converter for the object adapter's type
-     */
-    public static IConverter<Object> findConverter(
-            final ManagedObject objectAdapter,
-            final WicketViewerSettings wicketViewerSettings) {
-
-        val objectSpecification = objectAdapter.getSpecification();
-
-        // only use Wicket IConverter for value types, not for domain objects.
-        if (!objectSpecification.isValue()) {
-            return null;
-        }
-
-        // explicitly exclude enums; this will force the titleString
-        // to be used from Isis' EnumValueSemanticsProvider
-        final Class<?> correspondingClass = objectSpecification.getCorrespondingClass();
-        if(Enum.class.isAssignableFrom(correspondingClass)) {
-            return null;
-        }
-
-        final RenderedAdjustedFacet renderedAdjustedFacet = objectSpecification.getFacet(RenderedAdjustedFacet.class);
-        final int adjustBy = renderedAdjustedFacet != null ? renderedAdjustedFacet.value() : 0;
-
-        if (java.util.Date.class == correspondingClass) {
-            return _Casts.uncheckedCast(new DateConverterForJavaUtilDate(wicketViewerSettings, adjustBy));
-        }
-        if (java.sql.Date.class == correspondingClass) {
-            return _Casts.uncheckedCast(new DateConverterForJavaSqlDate(wicketViewerSettings, adjustBy));
-        }
-        if (org.joda.time.LocalDate.class == correspondingClass) {
-            return _Casts.uncheckedCast(new DateConverterForJodaLocalDate(wicketViewerSettings, adjustBy));
-        }
-        if (org.joda.time.LocalDateTime.class == correspondingClass) {
-            return _Casts.uncheckedCast(new DateConverterForJodaLocalDateTime(wicketViewerSettings, adjustBy));
-        }
-        if (org.joda.time.DateTime.class == correspondingClass) {
-            return _Casts.uncheckedCast(new DateConverterForJodaDateTime(wicketViewerSettings, adjustBy));
-        }
-        if (java.sql.Timestamp.class == correspondingClass) {
-            return _Casts.uncheckedCast(new DateConverterForJavaSqlTimestamp(wicketViewerSettings, adjustBy));
-        }
-        {
-            // date converter plugins (if any)
-            val serviceRegistry = objectSpecification.getMetaModelContext().getServiceRegistry();
-            DateConverter<?> converter = serviceRegistry.select(DateConverterPlugin.class).stream()
-                    .map(plugin->plugin.converterForClassIfAny(correspondingClass, wicketViewerSettings, adjustBy))
-                    .filter(_NullSafe::isPresent)
-                    .findAny()
-                    .orElse(null);
-
-            if(converter!=null) {
-                return _Casts.uncheckedCast(converter);
-            }
-
-        }
-        if (java.math.BigInteger.class == correspondingClass) {
-            return _Casts.uncheckedCast(new BigIntegerConverter());
-        }
-        if (java.math.BigDecimal.class == correspondingClass) {
-            final int scale = objectSpecification
-                .lookupFacet(MaxFractionDigitsFacet.class)
-                .map(MaxFractionDigitsFacet::getMaximumFractionDigits)
-                .orElse(-1);
-            return _Casts.uncheckedCast(new BigDecimalConverterWithScale(scale).forViewMode());
-        }
-
-        if(Application.exists()) {
-            final IConverterLocator converterLocator = Application.get().getConverterLocator();
-            return _Casts.uncheckedCast(converterLocator.getConverter(correspondingClass));
-        }
-
-        return null;
-    }
-}
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 0f0dacd..4524011 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
@@ -118,7 +118,7 @@ implements TextFieldValueModel.ScalarModelProvider {
         return new TextField<>(id, newTextFieldValueModel(), cls);
     }
 
-    TextFieldValueModel<T> newTextFieldValueModel() {
+    protected TextFieldValueModel<T> newTextFieldValueModel() {
         return new TextFieldValueModel<>(this);
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java
index 87cd988..269f039 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java
@@ -21,13 +21,13 @@ package org.apache.isis.viewer.wicket.ui.components.scalars;
 import java.io.Serializable;
 
 import org.apache.wicket.Component;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.util.convert.IConverter;
 
-import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
+
+import lombok.val;
 
 /**
  * Panel for rendering numeric scalars.
@@ -37,41 +37,32 @@ extends ScalarPanelTextFieldAbstract<T> {
 
     private static final long serialVersionUID = 1L;
 
-    /**
-     * The converter that is going to be used for the regular view of the panel, i.e. for the text field.
-     * The same converter should be used to render the compact view as well, to show the same precision and scale
-     * for the floating point types
-     */
-    private final IConverter<T> converter;
-
-    public ScalarPanelTextFieldNumeric(final String id, final ScalarModel scalarModel, final Class<T> cls, final IConverter<T> converter) {
+    protected ScalarPanelTextFieldNumeric(
+            final String id,
+            final ScalarModel scalarModel,
+            final Class<T> cls) {
         super(id, scalarModel, cls);
-
-        this.converter = converter;
     }
 
     @Override
     protected Component createComponentForCompact() {
-        Fragment compactFragment = getCompactFragment(CompactType.SPAN);
-        final Label label = new Label(ID_SCALAR_IF_COMPACT, newTextFieldValueModel()) {
-
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public <C> IConverter<C> getConverter(final Class<C> type) {
-                return _Casts.uncheckedCast(converter);
-            }
-        };
-
+        val label = Wkt.labelAddWithConverter(
+                getCompactFragment(CompactType.SPAN),
+                ID_SCALAR_IF_COMPACT, newTextFieldValueModel(), cls, getConverter(getModel()));
         label.setEnabled(false);
-
-        compactFragment.add(label);
         return label;
     }
 
     @Override
     protected IModel<String> obtainInlinePromptModel() {
-        return super.toStringConvertingModelOf(converter);
+        return super.toStringConvertingModelOf(getConverter(scalarModel));
     }
 
+    /**
+     * The converter that is going to be used for the regular view of the panel, i.e. for the text field.
+     * The same converter should be used to render the compact view as well, to show the same precision and scale
+     * for the floating point types
+     */
+    protected abstract IConverter<T> getConverter(final ScalarModel scalarModel);
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterForFeature.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterForFeature.java
new file mode 100644
index 0000000..853e394
--- /dev/null
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterForFeature.java
@@ -0,0 +1,34 @@
+/*
+ *  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.jdkmath;
+
+import java.math.BigDecimal;
+
+import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ConverterBasedOnValueSemantics;
+
+public class BigDecimalConverterForFeature
+extends ConverterBasedOnValueSemantics<BigDecimal> {
+
+    private static final long serialVersionUID = 1L;
+
+    protected BigDecimalConverterForFeature(final ObjectFeature propOrParam) {
+        super(propOrParam);
+    }
+}
\ No newline at end of file
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScale.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScale.java
deleted file mode 100644
index 9d4e8c1..0000000
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScale.java
+++ /dev/null
@@ -1,134 +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.viewer.wicket.ui.components.scalars.jdkmath;
-
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-import org.apache.wicket.util.convert.ConversionException;
-import org.apache.wicket.util.convert.IConverter;
-import org.apache.wicket.util.convert.converter.AbstractNumberConverter;
-import org.apache.wicket.util.convert.converter.BigDecimalConverter;
-
-/**
- * The {@link IConverter} implementation that our {@link BigDecimalTextField} delegates to for converting strings into
- * values.
- *
- * <p>
- * We reuse as much of Wicket's {@link BigDecimal} implementation as possible, but overriding where necessary.
- * Whereas Wicket's own {@link BigDecimalConverter} is (clearly?) intended as a singleton, we actually want multiple
- * instances, per scale.  The {@link JavaMathBigDecimalPanelFactory} actually takes care of handling this cache,
- * providing the {@link JavaMathBigDecimalPanel} with an appropriate underlying converter for it to delegate to.
- */
-public class BigDecimalConverterWithScale extends BigDecimalConverter {
-
-    /**
-     * For {@link JavaMathBigDecimalPanelFactory} to call, so that there is a single instance.
-     */
-    static AbstractNumberConverter<BigDecimal> newThreadSafeConverter(final Integer scale) {
-        return new BigDecimalConverterWithScale(scale);
-    }
-
-    private static final long serialVersionUID = 1L;
-    private final Integer scale;
-
-    public BigDecimalConverterWithScale(final Integer scale) {
-        this.scale = scale!=null
-                && scale>=0
-                ? scale
-                : null;
-    }
-
-    /**
-     * Disables thousands separator grouping.
-     */
-    @Override
-    protected NumberFormat newNumberFormat(final Locale locale) {
-        NumberFormat numberFormat = NumberFormat.getInstance(locale);
-        numberFormat.setGroupingUsed(false);
-        return numberFormat;
-    }
-
-    /**
-     * Forces trailing zeros to be rendered.
-     */
-    @Override
-    public NumberFormat getNumberFormat(final Locale locale)
-    {
-        // we obtain a clone, so is okay to modify it to our purposes.
-        NumberFormat numberFormat = super.getNumberFormat(locale);
-        if(scale != null) {
-            numberFormat.setMaximumFractionDigits(scale);
-            numberFormat.setMinimumFractionDigits(scale);
-        }
-        return numberFormat;
-    }
-
-    @Override
-    public BigDecimal convertToObject(final String valueStr, final Locale locale) throws ConversionException {
-
-        DecimalFormat numberFormat = (DecimalFormat) getNumberFormat(locale);
-        char groupingSeparator = numberFormat.getDecimalFormatSymbols().getGroupingSeparator();
-
-        if(valueStr.contains(""+groupingSeparator)) {
-            // TODO: this is not actually shown; we see a generic error
-            // need to configure the ConversionException somehow
-            throw new ConversionException("Thousands separator '" + groupingSeparator + "' is not allowed in input");
-        }
-
-        // could also throw an exception
-        final BigDecimal bd = super.convertToObject(valueStr, locale);
-
-        if(this.scale != null) {
-            if(bd.scale() > this.scale) {
-                // TODO: this is not actually shown; we see a generic error
-                // need to configure the ConversionException somehow
-                throw new ConversionException("No more than " + this.scale + " digits can be entered after the decimal place");
-            }
-            try {
-                return bd.setScale(this.scale);
-            } catch(Exception ex) {
-                // TODO: this is not actually shown; we see a generic error
-                // need to configure the ConversionException somehow
-                throw new ConversionException("'" + valueStr + "' is not a valid decimal number.");
-            }
-        } else {
-            return bd;
-        }
-    }
-
-    public IConverter<BigDecimal> forEditMode() {
-        return this;
-    }
-
-    public IConverter<BigDecimal> forViewMode() {
-        return new BigDecimalConverterWithScale(this.scale){
-            private static final long serialVersionUID = 1L;
-            @Override
-            public String convertToString(final BigDecimal value, final Locale locale) {
-                NumberFormat fmt = BigDecimalConverterWithScale.this.getNumberFormat(locale);
-                fmt.setGroupingUsed(true);// re-enable for view mode
-                return fmt.format(value);
-            }
-        };
-    }
-
-}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalTextField.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalTextField.java
deleted file mode 100644
index a80d649..0000000
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalTextField.java
+++ /dev/null
@@ -1,60 +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.viewer.wicket.ui.components.scalars.jdkmath;
-
-import java.math.BigDecimal;
-
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.util.convert.IConverter;
-
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldAbstract;
-
-final class BigDecimalTextField extends TextFieldAbstract<BigDecimal> {
-
-    private static final long serialVersionUID = 1L;
-
-    private final BigDecimalConverterWithScale converter;
-
-    BigDecimalTextField(
-            final String id, final IModel<BigDecimal> model, final Class<BigDecimal> type,
-            final ScalarModel scalarModel,
-            final BigDecimalConverterWithScale converter) {
-        super(id, model, type, scalarModel);
-        this.converter = converter;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <C> IConverter<C> getConverter(Class<C> type) {
-        if (type != BigDecimal.class) {
-            return super.getConverter(type);
-        }
-        return (IConverter<C>) getConverterFor(scalarModel);
-    }
-
-    @Override
-    protected IConverter<BigDecimal> getConverterFor(ScalarModel scalarModel) {
-        if(scalarModel.isEditMode()) {
-            return converter.forEditMode();
-        } else {
-            return converter.forViewMode();
-        }
-    }
-}
\ No newline at end of file
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanel.java
index 430edf3..0f3b646 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanel.java
@@ -21,33 +21,30 @@ package org.apache.isis.viewer.wicket.ui.components.scalars.jdkmath;
 import java.math.BigDecimal;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
+import org.apache.wicket.util.convert.IConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link BigDecimal}.
  */
-public class JavaMathBigDecimalPanel extends ScalarPanelTextFieldNumeric<BigDecimal> {
+public class JavaMathBigDecimalPanel
+extends ScalarPanelTextFieldNumeric<BigDecimal> {
 
     private static final long serialVersionUID = 1L;
 
-    private final BigDecimalConverterWithScale converter;
-
     public JavaMathBigDecimalPanel(
             final String id,
-            final ScalarModel scalarModel,
-            final BigDecimalConverterWithScale converter) {
-        super(id, scalarModel, BigDecimal.class, converter.forViewMode());
-        this.converter = converter;
+            final ScalarModel scalarModel) {
+        super(id, scalarModel, BigDecimal.class);
     }
 
     @Override
     protected AbstractTextComponent<BigDecimal> createTextFieldForRegular(final String id) {
-        final ScalarModel model = getModel();
-        final TextFieldValueModel<BigDecimal> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new BigDecimalTextField(id, textFieldValueModel, cls, model, converter);
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), BigDecimal.class, getConverter(getModel()));
     }
 
 
@@ -55,6 +52,14 @@ public class JavaMathBigDecimalPanel extends ScalarPanelTextFieldNumeric<BigDeci
     protected String getScalarPanelType() {
         return "javaMathBigDecimalPanel";
     }
+
+    @Override
+    protected IConverter<BigDecimal> getConverter(final ScalarModel scalarModel) {
+
+        // honor when not scalarModel.isEditMode()
+
+        return new BigDecimalConverterForFeature(scalarModel.getMetaModel());
+    }
 }
 
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanelFactory.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanelFactory.java
index c962637..7f230fb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanelFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigDecimalPanelFactory.java
@@ -18,9 +18,6 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.scalars.jdkmath;
 
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
 import org.apache.wicket.Component;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
@@ -30,38 +27,18 @@ import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScala
 /**
  * {@link ComponentFactory} for {@link JavaMathBigDecimalPanel}.
  */
-public class JavaMathBigDecimalPanelFactory extends ComponentFactoryScalarAbstract {
+public class JavaMathBigDecimalPanelFactory
+extends ComponentFactoryScalarAbstract {
 
     private static final long serialVersionUID = 1L;
 
-
     public JavaMathBigDecimalPanelFactory() {
         super(JavaMathBigDecimalPanel.class, java.math.BigDecimal.class);
     }
 
     @Override
     public Component createComponent(final String id, final ScalarModel scalarModel) {
-        BigDecimalConverterWithScale converter = getConverter(scalarModel);
-        return new JavaMathBigDecimalPanel(id, scalarModel, converter);
-    }
-
-
-    // //////////////////////////////////////
-
-    private final BigDecimalConverterWithScale converterForNullScale = new BigDecimalConverterWithScale(null);
-    private final Map<Integer, BigDecimalConverterWithScale> converterByScale = new ConcurrentHashMap<>();
-
-    private BigDecimalConverterWithScale getConverter(final ScalarModel scalarModel) {
-        final Integer scale = scalarModel.getScale();
-        if(scale == null) {
-            return converterForNullScale;
-        }
-        BigDecimalConverterWithScale bigDecimalConverter = converterByScale.get(scale);
-        if(bigDecimalConverter == null) {
-            bigDecimalConverter = new BigDecimalConverterWithScale(scale);
-            converterByScale.put(scale, bigDecimalConverter);
-        }
-        return bigDecimalConverter;
+        return new JavaMathBigDecimalPanel(id, scalarModel);
     }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigIntegerPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigIntegerPanel.java
index 9ab6725..5575e7b 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigIntegerPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/JavaMathBigIntegerPanel.java
@@ -21,37 +21,29 @@ package org.apache.isis.viewer.wicket.ui.components.scalars.jdkmath;
 import java.math.BigInteger;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.BigIntegerConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link BigInteger}.
  */
-public class JavaMathBigIntegerPanel extends ScalarPanelTextFieldNumeric<BigInteger> {
+public class JavaMathBigIntegerPanel
+extends ScalarPanelTextFieldNumeric<BigInteger> {
 
     private static final long serialVersionUID = 1L;
 
     public JavaMathBigIntegerPanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, BigInteger.class, new BigIntegerConverter());
+        super(id, scalarModel, BigInteger.class);
     }
 
     @Override
     protected AbstractTextComponent<BigInteger> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<BigInteger> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<BigInteger>(id, textFieldValueModel, BigInteger.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == BigInteger.class? new BigIntegerConverter(): super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), BigInteger.class, getConverter(getModel()));
     }
 
     @Override
@@ -59,4 +51,9 @@ public class JavaMathBigIntegerPanel extends ScalarPanelTextFieldNumeric<BigInte
         return "javaMathBigIntegerPanel";
     }
 
+    @Override
+    protected IConverter<BigInteger> getConverter(final ScalarModel scalarModel) {
+        return new BigIntegerConverter();
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BytePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BytePanel.java
index e21008b..27a5faf 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BytePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BytePanel.java
@@ -19,41 +19,38 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.ByteConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link Byte} or <tt>byte</tt>.
  */
-public class BytePanel extends ScalarPanelTextFieldNumeric<Byte> {
+public class BytePanel
+extends ScalarPanelTextFieldNumeric<Byte> {
 
     private static final long serialVersionUID = 1L;
 
     public BytePanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, Byte.class, ByteConverter.INSTANCE);
+        super(id, scalarModel, Byte.class);
     }
 
     @Override
     protected AbstractTextComponent<Byte> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<Byte> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<Byte>(id, textFieldValueModel, Byte.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == Byte.class? ByteConverter.INSTANCE: super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), Byte.class, getConverter(getModel()));
     }
 
     @Override
     protected String getScalarPanelType() {
         return "bytePanel";
     }
+
+    @Override
+    protected IConverter<Byte> getConverter(final ScalarModel scalarModel) {
+        return ByteConverter.INSTANCE;
+    }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/DoublePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/DoublePanel.java
index 0fc6d7b..084b7f6 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/DoublePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/DoublePanel.java
@@ -19,13 +19,12 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.DoubleConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link Double} or <tt>double</tt>.
@@ -35,21 +34,13 @@ public class DoublePanel extends ScalarPanelTextFieldNumeric<Double> {
     private static final long serialVersionUID = 1L;
 
     public DoublePanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, Double.class, DoubleConverter.INSTANCE);
+        super(id, scalarModel, Double.class);
     }
 
     @Override
     protected AbstractTextComponent<Double> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<Double> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<Double>(id, textFieldValueModel, Double.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == Double.class? DoubleConverter.INSTANCE: super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), Double.class, getConverter(getModel()));
     }
 
     @Override
@@ -57,4 +48,9 @@ public class DoublePanel extends ScalarPanelTextFieldNumeric<Double> {
         return "doublePanel";
     }
 
+    @Override
+    protected IConverter<Double> getConverter(final ScalarModel scalarModel) {
+        return DoubleConverter.INSTANCE;
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/FloatPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/FloatPanel.java
index 41c0afa..41ad6ac 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/FloatPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/FloatPanel.java
@@ -19,13 +19,12 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.FloatConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link Float} or <tt>float</tt>.
@@ -35,21 +34,13 @@ public class FloatPanel extends ScalarPanelTextFieldNumeric<Float> {
     private static final long serialVersionUID = 1L;
 
     public FloatPanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, Float.class, FloatConverter.INSTANCE);
+        super(id, scalarModel, Float.class);
     }
 
     @Override
     protected AbstractTextComponent<Float> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<Float> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<Float>(id, textFieldValueModel, Float.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == Float.class? FloatConverter.INSTANCE: super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), Float.class, getConverter(getModel()));
     }
 
     @Override
@@ -57,5 +48,9 @@ public class FloatPanel extends ScalarPanelTextFieldNumeric<Float> {
         return "floatPanel";
     }
 
+    @Override
+    protected IConverter<Float> getConverter(final ScalarModel scalarModel) {
+        return FloatConverter.INSTANCE;
+    }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/IntegerPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/IntegerPanel.java
index a5d995c..ee4e678 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/IntegerPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/IntegerPanel.java
@@ -19,13 +19,12 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.IntegerConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link Integer} or <tt>int</tt>.
@@ -35,21 +34,13 @@ public class IntegerPanel extends ScalarPanelTextFieldNumeric<Integer> {
     private static final long serialVersionUID = 1L;
 
     public IntegerPanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, Integer.class, IntegerConverter.INSTANCE);
+        super(id, scalarModel, Integer.class);
     }
 
     @Override
     protected AbstractTextComponent<Integer> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<Integer> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<Integer>(id, textFieldValueModel, Integer.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == Integer.class? IntegerConverter.INSTANCE: super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), Integer.class, getConverter(getModel()));
     }
 
     @Override
@@ -57,4 +48,9 @@ public class IntegerPanel extends ScalarPanelTextFieldNumeric<Integer> {
         return "integerPanel";
     }
 
+    @Override
+    protected IConverter<Integer> getConverter(final ScalarModel scalarModel) {
+        return IntegerConverter.INSTANCE;
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/LongPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/LongPanel.java
index 96bf73e..6e0152c 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/LongPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/LongPanel.java
@@ -19,13 +19,12 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.LongConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link Long} or <tt>long</tt>.
@@ -35,21 +34,13 @@ public class LongPanel extends ScalarPanelTextFieldNumeric<Long> {
     private static final long serialVersionUID = 1L;
 
     public LongPanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, Long.class, LongConverter.INSTANCE);
+        super(id, scalarModel, Long.class);
     }
 
     @Override
     protected AbstractTextComponent<Long> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<Long> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<Long>(id, textFieldValueModel, Long.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == Long.class? LongConverter.INSTANCE: super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), Long.class, getConverter(getModel()));
     }
 
     @Override
@@ -57,4 +48,9 @@ public class LongPanel extends ScalarPanelTextFieldNumeric<Long> {
         return "longPanel";
     }
 
+    @Override
+    protected IConverter<Long> getConverter(final ScalarModel scalarModel) {
+        return LongConverter.INSTANCE;
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/ShortPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/ShortPanel.java
index 136c8da..f986d28 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/ShortPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/ShortPanel.java
@@ -19,13 +19,12 @@
 package org.apache.isis.viewer.wicket.ui.components.scalars.primitive;
 
 import org.apache.wicket.markup.html.form.AbstractTextComponent;
-import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.convert.converter.ShortConverter;
 
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldNumeric;
-import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
 /**
  * Panel for rendering scalars of type {@link Short} or <tt>short</tt>.
@@ -35,25 +34,22 @@ public class ShortPanel extends ScalarPanelTextFieldNumeric<Short> {
     private static final long serialVersionUID = 1L;
 
     public ShortPanel(final String id, final ScalarModel scalarModel) {
-        super(id, scalarModel, Short.class, ShortConverter.INSTANCE);
+        super(id, scalarModel, Short.class);
     }
 
     @Override
     protected AbstractTextComponent<Short> createTextFieldForRegular(final String id) {
-        final TextFieldValueModel<Short> textFieldValueModel = new TextFieldValueModel<>(this);
-        return new TextField<Short>(id, textFieldValueModel, Short.class) {
-            private static final long serialVersionUID = 1L;
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <C> IConverter<C> getConverter(Class<C> type) {
-                return (IConverter<C>) (type == Short.class? ShortConverter.INSTANCE: super.getConverter(type));
-            }
-        };
+        return Wkt.textFieldWithConverter(
+                id, newTextFieldValueModel(), Short.class, getConverter(getModel()));
     }
 
     @Override
     protected String getScalarPanelType() {
         return "shortPanel";
     }
+
+    @Override
+    protected IConverter<Short> getConverter(final ScalarModel scalarModel) {
+        return ShortConverter.INSTANCE;
+    }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
index 9abfe30..b5a289d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
@@ -20,11 +20,8 @@ package org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Locale;
 import java.util.stream.Collectors;
 
-import org.apache.wicket.Session;
-import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.string.Strings;
 import org.springframework.lang.Nullable;
 import org.wicketstuff.select2.ChoiceProvider;
@@ -40,7 +37,6 @@ import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
 import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
-import org.apache.isis.viewer.wicket.ui.components.scalars.IsisConverterLocator;
 
 import lombok.Getter;
 import lombok.val;
@@ -71,18 +67,7 @@ extends ChoiceProvider<ObjectMemento> {
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(choice)) {
             return "Internal error: broken memento " + choiceMemento;
         }
-        final IConverter<Object> converter = findConverter(choice);
-        return converter != null
-                ? converter.convertToString(choice.getPojo(), getLocale())
-                : choice.titleString();
-    }
-
-    protected Locale getLocale() {
-        return Session.exists() ? Session.get().getLocale() : Locale.ENGLISH;
-    }
-
-    protected IConverter<Object> findConverter(final ManagedObject choice) {
-        return IsisConverterLocator.findConverter(choice, getWicketViewerSettings());
+        return choice.titleString();
     }
 
     @Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
index 766e637..de3a1b4 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
@@ -37,10 +37,14 @@ import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.TextArea;
+import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.util.convert.IConverter;
+import org.apache.wicket.validation.IValidationError;
+import org.apache.wicket.validation.ValidationError;
 import org.danekja.java.util.function.serializable.SerializableBiConsumer;
 import org.danekja.java.util.function.serializable.SerializableBooleanSupplier;
 import org.danekja.java.util.function.serializable.SerializableConsumer;
@@ -309,6 +313,18 @@ public class Wkt {
         };
     }
 
+    public <T> Label labelWithConverter(
+            final String id, final IModel<T> model, final Class<T> type, final IConverter<T> converter) {
+        return new Label(id, model) {
+            private static final long serialVersionUID = 1L;
+            @SuppressWarnings("unchecked")
+            @Override public <C> IConverter<C> getConverter(final Class<C> cType) {
+                return cType == type
+                        ? (IConverter<C>) converter
+                        : super.getConverter(cType);}
+        };
+    }
+
     public Label labelAdd(final MarkupContainer container, final String id, final String label) {
         return add(container, label(id, label));
     }
@@ -321,6 +337,12 @@ public class Wkt {
         return add(container, labelNoTab(id, labelModel));
     }
 
+    public <T> Label labelAddWithConverter(
+            final MarkupContainer container,
+            final String id, final IModel<T> model, final Class<T> type, final IConverter<T> converter) {
+        return add(container, labelWithConverter(id, model, type, converter));
+    }
+
     // -- LINK
 
     public AjaxLink<Void> link(final String id, final SerializableConsumer<AjaxRequestTarget> onClick) {
@@ -425,6 +447,28 @@ public class Wkt {
         return add(container, textAreaNoTab(id, textModel));
     }
 
+    // -- TEXT FIELD
+
+    public <T> TextField<T> textFieldWithConverter(
+            final String id, final IModel<T> model, final Class<T> type, final IConverter<T> converter) {
+        return new TextField<T>(id, model, type) {
+            private static final long serialVersionUID = 1L;
+            @SuppressWarnings("unchecked")
+            @Override public <C> IConverter<C> getConverter(final Class<C> cType) {
+                return cType == type
+                        ? (IConverter<C>) converter
+                        : super.getConverter(cType);}
+            @Override public void error(final IValidationError error) {
+                if(error instanceof ValidationError) {
+                    // use plain error message from ConversionException, circumventing resource bundles.
+                    this.error(((ValidationError)error).getMessage());
+                } else {
+                    super.error(error);
+                }
+            }
+        };
+    }
+
     // -- FOCUS UTILITY
 
     /**
@@ -468,6 +512,4 @@ public class Wkt {
                 : String.format("Wicket.Event.publish(Isis.Topic.%s)", topic.name());
     }
 
-
-
 }
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
deleted file mode 100644
index 98b8040..0000000
--- a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdkmath/BigDecimalConverterWithScaleTest_roundtrip.java
+++ /dev/null
@@ -1,138 +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.viewer.wicket.ui.components.scalars.jdkmath;
-
-import java.math.BigDecimal;
-import java.util.Locale;
-
-import org.apache.wicket.util.convert.ConversionException;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-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);
-
-    final BigDecimal bd_789123_45_scale2 = new BigDecimal("789123.45").setScale(2);
-
-    final BigDecimal bd_123_45_scale4 = new BigDecimal("123.45").setScale(4);
-    final BigDecimal bd_123_4500_scale4 = new BigDecimal("123.4500").setScale(4);
-
-    private BigDecimalConverterWithScale converter;
-
-    @BeforeEach
-    void setUp() throws Exception {
-        converter = newConverter(2);
-    }
-
-    @Test
-    void scale2_english() {
-
-        // when
-        final BigDecimal actual = converter.convertToObject("123.45", Locale.ENGLISH);
-        assertEquals(bd_123_4500_scale2, actual);
-        assertEquals(bd_123_45_scale2, actual);
-
-        assertNotEquals(bd_123_4500_scale4, actual);
-        assertNotEquals(bd_123_45_scale4, actual);
-
-        // when
-        String actualStr = converter.convertToString(actual, Locale.ENGLISH);
-        assertEquals("123.45", actualStr);
-    }
-
-    @Test
-    void scale4_english() {
-        converter = newConverter(4);
-
-        final BigDecimal actual = converter.convertToObject("123.45", Locale.ENGLISH);
-        assertNotEquals(bd_123_4500_scale2, actual);
-        assertNotEquals(bd_123_45_scale2, actual);
-
-        assertEquals(bd_123_4500_scale4, actual);
-        assertEquals(bd_123_45_scale4, actual);
-
-        // when
-        String actualStr = converter.convertToString(actual, Locale.ENGLISH);
-        assertEquals("123.4500", actualStr);
-    }
-
-
-    @Test
-    void scaleNull_english() {
-        converter = newConverter(null);
-
-        final BigDecimal actual = converter.convertToObject("123.45", Locale.ENGLISH);
-        assertEquals(bd_123_4500_scale2, actual);
-        assertEquals(bd_123_45_scale2, actual);
-
-        final BigDecimal actual2 = converter.convertToObject("123.4500", Locale.ENGLISH);
-        assertEquals(bd_123_4500_scale4, actual2);
-        assertEquals(bd_123_45_scale4, actual2);
-    }
-
-
-    @Test
-    void scale2_italian() {
-
-        final BigDecimal actual = converter.convertToObject("123,45", Locale.ITALIAN);
-        assertEquals(bd_123_4500_scale2, actual);
-        assertEquals(bd_123_45_scale2, actual);
-
-        assertNotEquals(bd_123_4500_scale4, actual);
-        assertNotEquals(bd_123_45_scale4, actual);
-    }
-
-
-    @Test
-    void scale2_english_withThousandSeparators() {
-        assertThrows(ConversionException.class, ()->
-            converter.convertToObject("789,123.45", Locale.ENGLISH),
-            "Thousands separator ',' is not allowed in input");
-    }
-
-    @Test
-    void scale2_english_withoutThousandSeparators() {
-
-        // when
-        final BigDecimal actual = converter.convertToObject("789123.45", Locale.ENGLISH);
-        assertEquals(bd_789123_45_scale2, actual);
-
-        // when
-        String actualStr = converter.convertToString(actual, Locale.ENGLISH);
-        assertEquals("789123.45", actualStr);
-    }
-
-    @Test
-    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(final Integer scale) {
-        return new BigDecimalConverterWithScale(scale);
-    }
-
-}