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 1ade9a86e8 ISIS-3121: fixes BigDecimal fractional digit rendering when
constraint
1ade9a86e8 is described below
commit 1ade9a86e8ac2be2a0525e20f7d3fcf561e0dc95
Author: Andi Huber <[email protected]>
AuthorDate: Wed Aug 24 13:43:28 2022 +0200
ISIS-3121: fixes BigDecimal fractional digit rendering when constraint
---
.../value/semantics/ValueSemanticsAbstract.java | 54 ++++++---
.../managed/nonscalar/DataTableModel.java | 1 +
.../apache/isis/core/metamodel/util/Facets.java | 10 ++
.../valuesemantics/BigDecimalValueSemantics.java | 27 +++--
.../bigdecimals/jdo/JavaMathBigDecimalJdo.java | 10 ++
.../bigdecimals/jpa/JavaMathBigDecimalJpa.java | 10 ++
.../isis/testdomain/value/ValueSemanticsTest.java | 70 ++++++++++-
.../model/valuetypes/ValueTypeExample.java | 130 ++++++++++++++++++++-
.../model/valuetypes/ValueTypeExampleService.java | 2 +-
9 files changed, 274 insertions(+), 40 deletions(-)
diff --git
a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
index 5346b132fc..506c858784 100644
---
a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
+++
b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/ValueSemanticsAbstract.java
@@ -63,7 +63,7 @@ import lombok.val;
*/
public abstract class ValueSemanticsAbstract<T>
implements
- ValueSemanticsProvider<T> {
+ValueSemanticsProvider<T> {
@SuppressWarnings("unchecked")
@Override
@@ -112,9 +112,9 @@ implements
*/
protected UserLocale getUserLocale(final @Nullable
ValueSemanticsProvider.Context context) {
return Optional.ofNullable(context)
- .map(ValueSemanticsProvider.Context::getInteractionContext)
- .map(InteractionContext::getLocale)
- .orElseGet(UserLocale::getDefault);
+ .map(ValueSemanticsProvider.Context::getInteractionContext)
+ .map(InteractionContext::getLocale)
+ .orElseGet(UserLocale::getDefault);
}
protected String renderTitle(final T value, final Function<T, String>
toString) {
@@ -139,8 +139,8 @@ implements
_Assert.assertEquals(getSchemaValueType(), ValueType.STRING);
return CommonDtoUtils.fundamentalTypeAsDecomposition(ValueType.STRING,
value!=null
- ? toString.apply(value)
- : onNull.get());
+ ? toString.apply(value)
+ : onNull.get());
}
protected T composeFromString(
@@ -149,7 +149,7 @@ implements
final @NonNull Supplier<T> onNullOrEmpty) {
val string = decomposition!=null
?
decomposition.left().map(ValueWithTypeDto::getString).orElse(null)
- : null;
+ : null;
return _Strings.isNotEmpty(string)
? fromString.apply(string)
: onNullOrEmpty.get();
@@ -165,8 +165,8 @@ implements
final @NonNull Supplier<F> onNull) {
return
CommonDtoUtils.fundamentalTypeAsDecomposition(getSchemaValueType(),
value!=null
- ? onNonNull.apply(value)
- : onNull.get());
+ ? onNonNull.apply(value)
+ : onNull.get());
}
/**
@@ -191,7 +191,7 @@ implements
/**
* @param context - nullable in support of JUnit testing
- * @return {@link NumberFormat} the default from from given context's
locale
+ * @return {@link NumberFormat} the default from given context's locale
* or else system's default locale
*
* @implNote the format's MaximumFractionDigits are initialized to 16, as
@@ -199,11 +199,19 @@ implements
* this is typically overruled later by implementations of
* {@link
#configureDecimalFormat(org.apache.isis.applib.adapters.ValueSemanticsProvider.Context,
DecimalFormat) configureDecimalFormat}
*/
- @SuppressWarnings("javadoc")
- protected DecimalFormat getNumberFormat(final @Nullable
ValueSemanticsProvider.Context context) {
+ @SuppressWarnings("javadoc")
+ protected DecimalFormat getNumberFormat(
+ final @Nullable ValueSemanticsProvider.Context context) {
+ return getNumberFormat(context, FormatUsageFor.RENDERING);
+ }
+
+ protected DecimalFormat getNumberFormat(
+ final @Nullable ValueSemanticsProvider.Context context,
+ final @NonNull FormatUsageFor usedFor) {
val format =
(DecimalFormat)NumberFormat.getNumberInstance(getUserLocale(context).getNumberFormatLocale());
// prime w/ 16 (64 bit IEEE 754 double has 15 decimal digits of
precision)
format.setMaximumFractionDigits(16);
+ configureDecimalFormat(context, format, usedFor);
return format;
}
@@ -216,7 +224,7 @@ implements
}
try {
return parseDecimal(context, input)
- .map(BigDecimal::toBigIntegerExact);
+ .map(BigDecimal::toBigIntegerExact);
} catch (final NumberFormatException | ArithmeticException e) {
throw new TextEntryParseException("Not an integer value " + text,
e);
}
@@ -229,9 +237,9 @@ implements
if(input==null) {
return Optional.empty();
}
- val format = getNumberFormat(context);
+ val format = getNumberFormat(context, FormatUsageFor.PARSING);
format.setParseBigDecimal(true);
- configureDecimalFormat(context, format);
+
val position = new ParsePosition(0);
try {
@@ -247,7 +255,7 @@ implements
&& number.scale()>format.getMaximumFractionDigits()) {
throw new TextEntryParseException(String.format(
"No more than %d digits can be entered after the
decimal separator, "
- + "got %d in '%s'.", maxFractionDigits,
number.scale(), input));
+ + "got %d in '%s'.", maxFractionDigits,
number.scale(), input));
}
return Optional.of(number);
} catch (final NumberFormatException | ParseException e) {
@@ -257,10 +265,18 @@ implements
}
}
+ protected static enum FormatUsageFor {
+ PARSING,
+ RENDERING;
+ public boolean isParsing() { return this==PARSING; }
+ public boolean isRendering() { return this==RENDERING; }
+ }
+
/**
- * Typically overridden by BigDecimalValueSemantics to set
MaximumFractionDigits.
+ * Typically overridden by BigDecimalValueSemantics to set min/max
fractional digits.
*/
- protected void configureDecimalFormat(final Context context, final
DecimalFormat format) {}
+ protected void configureDecimalFormat(
+ final Context context, final DecimalFormat format, final
FormatUsageFor usedFor) {}
// -- TEMPORAL RENDERING
@@ -295,7 +311,7 @@ implements
final @NonNull TemporalValueSemantics.TemporalCharacteristic
temporalCharacteristic,
final @NonNull TemporalValueSemantics.OffsetCharacteristic
offsetCharacteristic) {
- switch (offsetCharacteristic) {
+ switch (offsetCharacteristic) {
case LOCAL:
return Optional.empty();
case OFFSET:
diff --git
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
index fcc12236e1..8d3cc82ac1 100644
---
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
+++
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
@@ -126,6 +126,7 @@ implements MultiselectChoices {
dataElements.getValue().stream()
//XXX future extension: filter by searchArgument
.filter(this::ignoreHidden)
+ //FIXME[ISIS-3167] entities might be detached
.sorted(managedMember.getMetaModel().getElementComparator()
.orElseGet(()->(a, b)->0)) // else don't sort (no-op
comparator for streams)
.map(domainObject->new DataRow(this, domainObject))
diff --git
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/Facets.java
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/Facets.java
index cdb051aae3..c1cec8761e 100644
---
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/Facets.java
+++
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/Facets.java
@@ -59,6 +59,7 @@ import
org.apache.isis.core.metamodel.facets.object.value.ValueSerializer;
import
org.apache.isis.core.metamodel.facets.objectvalue.daterenderedadjust.DateRenderAdjustFacet;
import
org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacet;
import
org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxTotalDigitsFacet;
+import
org.apache.isis.core.metamodel.facets.objectvalue.digits.MinFractionalDigitsFacet;
import
org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
@@ -232,9 +233,18 @@ public final class Facets {
.orElse("label-left");
}
+ public OptionalInt minFractionalDigits(final FacetHolder facetHolder) {
+ return facetHolder.lookupFacet(MinFractionalDigitsFacet.class)
+ .map(MinFractionalDigitsFacet::getMinFractionalDigits)
+ .filter(digits->digits>-1)
+ .map(OptionalInt::of)
+ .orElseGet(OptionalInt::empty);
+ }
+
public OptionalInt maxFractionalDigits(final FacetHolder facetHolder) {
return facetHolder.lookupFacet(MaxFractionalDigitsFacet.class)
.map(MaxFractionalDigitsFacet::getMaxFractionalDigits)
+ .filter(digits->digits>-1)
.map(OptionalInt::of)
.orElseGet(OptionalInt::empty);
}
diff --git
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
index 1c35f413e2..9c11d05676 100644
---
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/BigDecimalValueSemantics.java
@@ -37,8 +37,8 @@ import
org.apache.isis.applib.value.semantics.ValueDecomposition;
import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
import org.apache.isis.applib.value.semantics.ValueSemanticsProvider;
import org.apache.isis.commons.collections.Can;
-import
org.apache.isis.core.metamodel.facets.objectvalue.digits.MaxFractionalDigitsFacet;
import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.metamodel.util.Facets;
import org.apache.isis.schema.common.v2.ValueType;
import org.apache.isis.schema.common.v2.ValueWithTypeDto;
@@ -134,7 +134,8 @@ implements
}
@Override
- protected void configureDecimalFormat(final Context context, final
DecimalFormat format) {
+ protected void configureDecimalFormat(
+ final Context context, final DecimalFormat format, final
FormatUsageFor usedFor) {
if(context==null) {
return;
}
@@ -146,16 +147,26 @@ implements
}
// evaluate any facets that provide the MaximumFractionDigits
- feature.lookupFacet(MaxFractionalDigitsFacet.class).stream()
- .mapToInt(MaxFractionalDigitsFacet::getMaxFractionalDigits)
- .filter(digits->digits>-1)
- .forEach(digits-> // cardinality 0 or 1
- format.setMaximumFractionDigits(digits));
+ Facets.maxFractionalDigits(feature)
+ .ifPresent(format::setMaximumFractionDigits);
+
+ // we skip this when PARSING,
+ // because we want to firstly parse any number value into a BigDecimal,
+ // no matter the minimumFractionDigits, which can always be filled up
with '0' digits later
+ if(usedFor.isRendering()) {
+ // evaluate any facets that provide the MinimumFractionDigits
+ Facets.minFractionalDigits(feature)
+ .ifPresent(format::setMinimumFractionDigits);
+ }
}
@Override
public Can<BigDecimal> getExamples() {
- return Can.of(new BigDecimal("-63.1"), BigDecimal.ZERO);
+ return Can.of(
+ new BigDecimal("1001"),
+ new BigDecimal("-63.1"),
+ new BigDecimal("0.001"),
+ BigDecimal.ZERO);
}
}
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 ea77d104f7..236f7edc81 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
@@ -33,6 +33,7 @@ import org.apache.isis.applib.annotation.Optionality;
import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.PropertyLayout;
import org.apache.isis.applib.annotation.Title;
+import org.apache.isis.applib.annotation.ValueSemantics;
import lombok.Getter;
import lombok.Setter;
@@ -53,6 +54,7 @@ public class JavaMathBigDecimalJdo
// <
this.readOnlyProperty = initialValue;
this.readWriteProperty = initialValue;
this.withMax2FractionDigits = initialValue;
+ this.withFixed2FractionDigits = initialValue;
}
//tag::class[]
@@ -75,6 +77,14 @@ public class JavaMathBigDecimalJdo
// <
@Getter @Setter
private java.math.BigDecimal withMax2FractionDigits;
+ @Property(editing = Editing.ENABLED)
+ @ValueSemantics(minFractionalDigits = 2)
+ @PropertyLayout(fieldSetId = "editable-properties", sequence = "3",
+ describedAs = "has 2 fixed fraction digits (scale=2)")
+ @Column(allowsNull = "false", scale = 2)
+ @Getter @Setter
+ private java.math.BigDecimal withFixed2FractionDigits;
+
@Property(optionality = Optionality.OPTIONAL) //
<.>
@PropertyLayout(fieldSetId = "optional-properties", sequence = "1")
@Column(allowsNull = "true") //
<.>
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 ca23e1d33d..b7d3d64c23 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
@@ -34,6 +34,7 @@ import org.apache.isis.applib.annotation.Optionality;
import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.PropertyLayout;
import org.apache.isis.applib.annotation.Title;
+import org.apache.isis.applib.annotation.ValueSemantics;
import org.apache.isis.persistence.jpa.applib.integration.IsisEntityListener;
import lombok.Getter;
@@ -61,6 +62,7 @@ public class JavaMathBigDecimalJpa
//
this.readOnlyProperty = initialValue;
this.readWriteProperty = initialValue;
this.withMax2FractionDigits = initialValue;
+ this.withFixed2FractionDigits = initialValue;
}
//tag::class[]
@@ -87,6 +89,14 @@ public class JavaMathBigDecimalJpa
//
@Getter @Setter
private java.math.BigDecimal withMax2FractionDigits;
+ @Property(editing = Editing.ENABLED)
+ @ValueSemantics(minFractionalDigits = 2)
+ @PropertyLayout(fieldSetId = "editable-properties", sequence = "3",
+ describedAs = "has 2 fixed fraction digits (scale=2)")
+ @Column(nullable = false, scale = 2)
+ @Getter @Setter
+ private java.math.BigDecimal withFixed2FractionDigits;
+
@Property(optionality = Optionality.OPTIONAL) //
<.>
@PropertyLayout(fieldSetId = "optional-properties", sequence = "1")
@Column(nullable = true) //
<.>
diff --git
a/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
b/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
index 60e7d6f32e..0be7e4aa65 100644
---
a/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
+++
b/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.isis.testdomain.value;
+import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.util.Locale;
@@ -37,6 +38,11 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import org.apache.isis.applib.annotation.Where;
import org.apache.isis.applib.graph.tree.TreeNode;
import org.apache.isis.applib.locale.UserLocale;
@@ -70,11 +76,6 @@ import
org.apache.isis.testdomain.value.ValueSemanticsTester.PropertyInteraction
import org.apache.isis.valuetypes.asciidoc.applib.value.AsciiDoc;
import org.apache.isis.valuetypes.markdown.applib.value.Markdown;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
import lombok.val;
@SpringBootTest(
@@ -232,8 +233,51 @@ class ValueSemanticsTest {
final ValueSemanticsProvider.Context context,
final Parser<T> parser) {
+ example.getParseExpectations()
+ .forEach(parseExpectation->{
+ val value = parseExpectation.getValue();
+
+ if(parseExpectation.getExpectedThrows()!=null) {
+
+ // test parsing that should throw
+ parseExpectation.getInputSamples()
+ .forEach(in->{
+
Assertions.assertThrows(parseExpectation.getExpectedThrows(), ()->{
+
parser.parseTextRepresentation(context, in);
+ });
+ });
+
+ } else {
+
+ // test parsing that should not throw
+ parseExpectation.getInputSamples()
+ .forEach(in->{
+ val parsedValue =
parser.parseTextRepresentation(context, in);
+
+ if(value instanceof BigDecimal) {
+ assertNumberEquals((BigDecimal)value,
(BigDecimal)parsedValue);
+ } else {
+ assertEquals(value, parsedValue);
+ }
+
+ });
+
+ // test formatting
+ assertEquals(
+ parseExpectation.getExpectedOutput(),
+
parser.parseableTextRepresentation(context, value));
+
+ }
+
+ });
+
+ if(example.getParseExpectations().isNotEmpty()) {
+ return; // skip round-trip test
+ }
+
+ //TODO eventually all examples should have their
ParseExpectations, so we can remove
// Parser round-trip test
- for(val value : example.getExamples()) {
+ for(val value : example.getParserRoundtripExamples()) {
val stringified =
parser.parseableTextRepresentation(context, value);
@@ -276,7 +320,14 @@ class ValueSemanticsTest {
final ValueSemanticsProvider.Context context,
final Renderer<T> renderer) {
+ example.getRenderExpectations()
+ .forEach(renderExpectation->{
+ val value = renderExpectation.getValue();
+ assertEquals(renderExpectation.getTitle(),
renderer.titlePresentation(context, value));
+ assertEquals(renderExpectation.getHtml(),
renderer.htmlPresentation(context, value));
+ });
}
+
@Override
public void testCommand(
final ValueSemanticsProvider.Context context,
@@ -336,6 +387,13 @@ class ValueSemanticsTest {
// -- HELPER
+ private static void assertNumberEquals(final BigDecimal a, final
BigDecimal b) {
+ val maxScale = Math.max(a.scale(), b.scale());
+ assertEquals(
+ a.setScale(maxScale),
+ b.setScale(maxScale));
+ }
+
private InteractionContext interactionContext() {
return
InteractionContext.builder().locale(UserLocale.valueOf(Locale.ENGLISH)).build();
}
diff --git
a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExample.java
b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExample.java
index ae516979d1..7d00e72ce4 100644
---
a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExample.java
+++
b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExample.java
@@ -45,6 +45,8 @@ import org.apache.isis.applib.annotation.DomainObject;
import org.apache.isis.applib.annotation.Nature;
import org.apache.isis.applib.annotation.Programmatic;
import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.ValueSemantics;
+import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
import org.apache.isis.applib.graph.tree.TreeAdapter;
import org.apache.isis.applib.graph.tree.TreeNode;
import org.apache.isis.applib.graph.tree.TreeState;
@@ -58,6 +60,7 @@ import
org.apache.isis.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.isis.applib.value.Password;
import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract;
import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Refs;
import org.apache.isis.commons.internal.base._Temporals;
import
org.apache.isis.core.metamodel.valuesemantics.ApplicationFeatureIdValueSemantics;
import org.apache.isis.extensions.fullcalendar.applib.value.CalendarEvent;
@@ -67,9 +70,12 @@ import org.apache.isis.schema.cmd.v2.CommandDto;
import org.apache.isis.schema.common.v2.OidDto;
import org.apache.isis.schema.ixn.v2.InteractionDto;
+import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
+import lombok.Singular;
import lombok.SneakyThrows;
+import lombok.val;
public abstract class ValueTypeExample<T> {
@@ -85,9 +91,21 @@ public abstract class ValueTypeExample<T> {
setValue(value);
}
+ /**
+ * Name of the value-type plus suffix if any, as extracted from the
implementing example name.
+ */
+ @Programmatic
+ public final String getName() {
+ val nameSuffix = extractSuffix(getClass().getSimpleName())
+ .map(s->"_" + s)
+ .orElse("");
+ val name = String.format("%s%s", getValueType().getName(), nameSuffix);
+ return name;
+ }
+
@Autowired(required = false) List<ValueSemanticsAbstract<T>> semanticsList;
@Programmatic
- public Can<T> getExamples() {
+ public Can<T> getParserRoundtripExamples() {
return Can.ofCollection(semanticsList)
.getFirst()
.map(semantics->semantics.getExamples())
@@ -105,6 +123,47 @@ public abstract class ValueTypeExample<T> {
return (Class<T>) getValue().getClass();
}
+ // -- PARSING
+
+ @lombok.Value @Builder
+ public static class ParseExpectation<T> {
+ final T value;
+ @Singular
+ final List<String> inputSamples;
+ final String expectedOutput;
+ final Class<? extends Throwable> expectedThrows;
+ }
+
+ public Can<ParseExpectation<T>> getParseExpectations() {
+ System.err.printf("skipping parsing test for %s%n", getName());
+ return Can.empty();
+ }
+
+ // -- RENDERING
+
+ @lombok.Value @Builder
+ public static class RenderExpectation<T> {
+ final T value;
+ final String title;
+ final String html;
+ }
+
+ public Can<RenderExpectation<T>> getRenderExpectations() {
+ System.err.printf("skipping rendering test for %s%n", getName());
+ return Can.empty();
+ }
+
+ // -- HELPER
+
+ private static Optional<String> extractSuffix(final String name) {
+ if(!name.contains("_")) {
+ return Optional.empty();
+ }
+ val ref = _Refs.stringRef(name);
+ ref.cutAtIndexOfAndDrop("_");
+ return Optional.of(ref.getValue());
+ }
+
// -- EXAMPLES - BASIC
@Named("isis.testdomain.valuetypes.ValueTypeExampleBoolean")
@@ -302,7 +361,7 @@ public abstract class ValueTypeExample<T> {
//FIXME does not handle example Float.MIN_VALUE well
@Deprecated // remove override once fixed
- @Override public Can<Float> getExamples() {
+ @Override public Can<Float> getParserRoundtripExamples() {
return Can.of(value, updateValue);
}
}
@@ -319,11 +378,13 @@ public abstract class ValueTypeExample<T> {
//FIXME does not handle example Double.MIN_VALUE well
@Deprecated // remove override once fixed
- @Override public Can<Double> getExamples() {
+ @Override public Can<Double> getParserRoundtripExamples() {
return Can.of(value, updateValue);
}
}
+ // -- BIG INTEGER
+
@Named("isis.testdomain.valuetypes.ValueTypeExampleBigInteger")
@DomainObject(
nature = Nature.BEAN)
@@ -335,15 +396,72 @@ public abstract class ValueTypeExample<T> {
private BigInteger updateValue = BigInteger.ZERO;
}
- @Named("isis.testdomain.valuetypes.ValueTypeExampleBigDecimal")
+ // -- BIG DECIMAL
+
+ @Named("isis.testdomain.valuetypes.ValueTypeExampleBigDecimal_default")
@DomainObject(
nature = Nature.BEAN)
- public static class ValueTypeExampleBigDecimal
+ public static class ValueTypeExampleBigDecimal_default
extends ValueTypeExample<BigDecimal> {
@Property @Getter @Setter
- private BigDecimal value = new BigDecimal("-63.1");
+ private BigDecimal value = new BigDecimal("-63.123456");
+ @Getter
+ private BigDecimal updateValue = BigDecimal.ZERO;
+ }
+
+
@Named("isis.testdomain.valuetypes.ValueTypeExampleBigDecimal_fixedFractionalDigits")
+ @DomainObject(
+ nature = Nature.BEAN)
+ public static class ValueTypeExampleBigDecimal_fixedFractionalDigits
+ extends ValueTypeExample<BigDecimal> {
+ @Property @ValueSemantics(minFractionalDigits = 2, maxFractionalDigits
= 2)
+ @Getter @Setter
+ private BigDecimal value = new BigDecimal("-63.12");
@Getter
private BigDecimal updateValue = BigDecimal.ZERO;
+
+ // with this example maxFractionalDigits = 2 must not be exceeded
+ @Override public Can<BigDecimal> getParserRoundtripExamples() {
+ return Can.of(value, updateValue, new BigDecimal("0.1"));
+ }
+
+ @Override
+ public Can<ParseExpectation<BigDecimal>> getParseExpectations() {
+ return Can.of(
+ ParseExpectation.<BigDecimal>builder()
+ .value(new BigDecimal("123"))
+ .inputSample("123")
+ .inputSample("123.0")
+ .inputSample("123.00")
+ .expectedOutput("123.00")
+ .build(),
+ ParseExpectation.<BigDecimal>builder()
+ .value(new BigDecimal("123.45"))
+ .inputSample("123.45")
+ .expectedOutput("123.45")
+ .build(),
+ ParseExpectation.<BigDecimal>builder()
+ .value(new BigDecimal("123.45"))
+ .inputSample("123.456")
+
//org.apache.isis.applib.exceptions.recoverable.TextEntryParseException:
+ // No more than 2 digits can be entered after the
decimal separator, got 3 in '123.456'.
+ .expectedThrows(TextEntryParseException.class)
+ .build()
+ );
+ }
+
+ @Override
+ public Can<RenderExpectation<BigDecimal>> getRenderExpectations() {
+ return Can.of(
+ RenderExpectation.<BigDecimal>builder()
+ .value(new
BigDecimal("123")).title("123.00").html("123.00").build(),
+ RenderExpectation.<BigDecimal>builder()
+ .value(new
BigDecimal("0")).title("0.00").html("0.00").build(),
+ RenderExpectation.<BigDecimal>builder()
+ .value(new
BigDecimal("123.456")).title("123.46").html("123.46").build()
+ );
+ }
+
}
// -- EXAMPLES - TEMPORAL - LEGACY
diff --git
a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExampleService.java
b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExampleService.java
index 7747b4f5f3..87d9e08081 100644
---
a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExampleService.java
+++
b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/valuetypes/ValueTypeExampleService.java
@@ -43,7 +43,7 @@ public class ValueTypeExampleService {
@Value(staticConstructor = "of")
public static class Scenario implements Comparable<Scenario> {
static Scenario of(final ValueTypeExample<?> example) {
- val name = String.format("%s", example.getValueType().getName());
+ val name = example.getName();
return Scenario.of(name, Arguments.of(
name,
example.getValueType(),