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/causeway.git
The following commit(s) were added to refs/heads/master by this push:
new 6b90267d6e CAUSEWAY-3489: move temporal decomposition logic to value
semantics
6b90267d6e is described below
commit 6b90267d6e33c98b5ea30fae96c8e13be410d8c0
Author: Andi Huber <[email protected]>
AuthorDate: Fri Mar 15 09:50:32 2024 +0100
CAUSEWAY-3489: move temporal decomposition logic to value semantics
---
.../applib/value/semantics/TemporalSupport.java | 53 +++++++++++++
.../value/semantics/TemporalValueSemantics.java | 2 +-
.../metamodel/facets/object/value/ValueFacet.java | 5 ++
.../facets/object/value/ValueFacetAbstract.java | 30 ++++++--
.../core/metamodel/object/MmRenderUtils.java | 4 +-
.../core/metamodel/object/MmValueUtils.java | 88 ++++++++++++++++++++++
.../temporal/LocalDateTimeValueSemantics.java | 11 +++
.../temporal/LocalDateValueSemantics.java | 11 +++
.../temporal/LocalTimeValueSemantics.java | 11 +++
.../temporal/OffsetDateTimeValueSemantics.java | 14 ++++
.../temporal/OffsetTimeValueSemantics.java | 14 ++++
.../temporal/ZonedDateTimeValueSemantics.java | 14 ++++
.../valuetypes/TemporalSemanticsAdapter.java | 15 +++-
.../TemporalValueSemanticsProviderTest.java | 9 +++
.../ScalarPanelTextFieldWithTemporalPicker.java | 6 +-
...sition.java => TemporalDecompositionModel.java} | 65 +++++++---------
.../components/scalars/markup/MarkupComponent.java | 2 +-
.../ui/components/value/StandaloneValuePanel.java | 2 +-
18 files changed, 300 insertions(+), 56 deletions(-)
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalSupport.java
b/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalSupport.java
new file mode 100644
index 0000000000..ff3831a5f8
--- /dev/null
+++
b/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalSupport.java
@@ -0,0 +1,53 @@
+/*
+ * 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.causeway.applib.value.semantics;
+
+import java.io.Serializable;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.Temporal;
+import java.util.Optional;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.causeway.commons.functional.Either;
+
+import lombok.Value;
+import lombok.experimental.Accessors;
+
+/**
+ * Decomposes arbitrary time representing values of type T into a canonical
representation.
+ */
+public interface TemporalSupport<T> extends TemporalCharacteristicsProvider {
+
+ @Value @Accessors(fluent=true) // record candidate
+ public static class TemporalDecomposition implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final Temporal localTemporal;
+ private final Optional<Either<ZoneId, ZoneOffset>> zoneOrOffset;
+ TemporalCharacteristic temporalCharacteristic;
+ OffsetCharacteristic offsetCharacteristic;
+ }
+
+ /**
+ * Decomposes any temporal value into 2 parts, a 'local' {@link Temporal}
and a {@link ZoneId}.
+ */
+ Optional<TemporalDecomposition> decomposeTemporal(final @Nullable T
temporal);
+
+}
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalValueSemantics.java
b/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalValueSemantics.java
index b715413488..79c999c32d 100644
---
a/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalValueSemantics.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/value/semantics/TemporalValueSemantics.java
@@ -39,7 +39,7 @@ extends
OrderRelation<T, Duration>,
Parser<T>,
Renderer<T>,
- TemporalCharacteristicsProvider {
+ TemporalSupport<T> {
static enum EditingFormatDirection {
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacet.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacet.java
index c0206c1f47..c8883a929e 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacet.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacet.java
@@ -29,6 +29,7 @@ import
org.apache.causeway.applib.value.semantics.DefaultsProvider;
import org.apache.causeway.applib.value.semantics.OrderRelation;
import org.apache.causeway.applib.value.semantics.Parser;
import org.apache.causeway.applib.value.semantics.Renderer;
+import org.apache.causeway.applib.value.semantics.TemporalSupport;
import org.apache.causeway.applib.value.semantics.ValueSemanticsProvider;
import
org.apache.causeway.applib.value.semantics.ValueSemanticsProvider.Context;
import org.apache.causeway.commons.collections.Can;
@@ -159,6 +160,10 @@ extends
.orElseGet(()->fallbackRenderer(coll.getFeatureIdentifier()));
}
+ // -- TEMPORAL SUPPORT
+
+ Optional<TemporalSupport<T>> selectTemporalSupportForFeature(final
@Nullable ObjectFeature feature);
+
// -- COMPOSITE VALUE SUPPORT
Optional<ObjectAction> selectCompositeValueMixinForParameter(
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacetAbstract.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacetAbstract.java
index 7cac0c9ea3..84e475f7d4 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacetAbstract.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/value/ValueFacetAbstract.java
@@ -32,9 +32,11 @@ import
org.apache.causeway.applib.value.semantics.DefaultsProvider;
import org.apache.causeway.applib.value.semantics.OrderRelation;
import org.apache.causeway.applib.value.semantics.Parser;
import org.apache.causeway.applib.value.semantics.Renderer;
+import org.apache.causeway.applib.value.semantics.TemporalSupport;
import org.apache.causeway.applib.value.semantics.ValueSemanticsProvider;
import
org.apache.causeway.applib.value.semantics.ValueSemanticsProvider.Context;
import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.internal.base._Casts;
import org.apache.causeway.commons.internal.base._NullSafe;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.exceptions._Exceptions;
@@ -270,6 +272,18 @@ implements ValueFacet<T> {
return fallbackRenderer(getLogicalType(), featureIdentifier);
}
+ // -- TEMPORAL SUPPORT
+
+ @Override
+ public Optional<TemporalSupport<T>> selectTemporalSupportForFeature(final
@Nullable ObjectFeature feature) {
+ return (feature!=null
+ ? streamValueSemanticsHonoringQualifiers(feature)
+ : getAllValueSemantics().stream())
+ .filter(TemporalSupport.class::isInstance)
+
.map(temporalDecomposer->_Casts.<TemporalSupport<T>>uncheckedCast(temporalDecomposer))
+ .findFirst();
+ }
+
// -- COMPOSITE VALUE SUPPORT
@Override
@@ -320,18 +334,18 @@ implements ValueFacet<T> {
// -- HELPER
private Stream<ValueSemanticsProvider<T>>
streamValueSemanticsHonoringQualifiers(
- final FacetHolder feature) {
+ final @NonNull ObjectFeature feature) {
return getAllValueSemantics()
- .stream()
- .filter(isMatchingAnyOf(qualifiersAccepted(feature)));
+ .stream()
+ .filter(isMatchingAnyOf(qualifiersAccepted(feature)));
}
- private Can<String> qualifiersAccepted(final FacetHolder feature) {
+ private Can<String> qualifiersAccepted(final @NonNull ObjectFeature
feature) {
return feature.lookupFacet(ValueSemanticsSelectingFacet.class)
- .map(ValueSemanticsSelectingFacet::value)
- .map(_Strings::emptyToNull)
- .stream()
- .collect(Can.toCan());
+ .map(ValueSemanticsSelectingFacet::value)
+ .map(_Strings::emptyToNull)
+ .stream()
+ .collect(Can.toCan());
}
private Predicate<ValueSemanticsProvider<T>> isMatchingAnyOf(final
Can<String> qualifiersAccepted) {
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmRenderUtils.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmRenderUtils.java
index e381a30a9e..bf9ab404ee 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmRenderUtils.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmRenderUtils.java
@@ -30,8 +30,8 @@ import lombok.experimental.UtilityClass;
public class MmRenderUtils {
public String htmlStringForValueType(
- final @Nullable ManagedObject adapter,
- final @Nullable ObjectFeature feature) {
+ final @Nullable ObjectFeature feature,
+ final @Nullable ManagedObject adapter) {
if(!ManagedObjects.isSpecified(adapter)) {
return "";
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java
new file mode 100644
index 0000000000..4c18206279
--- /dev/null
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java
@@ -0,0 +1,88 @@
+/*
+ * 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.causeway.core.metamodel.object;
+
+import java.util.Optional;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.causeway.applib.value.semantics.TemporalSupport;
+import
org.apache.causeway.applib.value.semantics.TemporalSupport.TemporalDecomposition;
+import org.apache.causeway.applib.value.semantics.ValueSemanticsProvider;
+import org.apache.causeway.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectFeature;
+
+import lombok.val;
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class MmValueUtils {
+
+ // -- CONTEXT FACTORIES
+
+ //TODO[CAUSEWAY-3489] ever used ?
+ public Optional<ValueSemanticsProvider.Context>
createValueSemanticsContext(
+ final @Nullable ObjectFeature feature,
+ final @Nullable ObjectSpecification elementType) {
+ return valueFacet(elementType)
+
.map(valueFacet->valueFacet.createValueSemanticsContext(feature));
+ }
+
+ //TODO[CAUSEWAY-3489] ever used ?
+ public Optional<ValueSemanticsProvider.Context>
createValueSemanticsContext(
+ final @Nullable ObjectFeature feature,
+ final @Nullable ManagedObject valueObject) {
+ return valueFacet(valueObject)
+
.map(valueFacet->valueFacet.createValueSemanticsContext(feature));
+ }
+
+ // -- TEMPORAL DECOMPOSITION
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public Optional<TemporalDecomposition> temporalDecomposition(
+ final @Nullable ObjectFeature objectFeature,
+ final @Nullable ManagedObject valueObject) {
+ return valueFacet(valueObject)
+
.filter(valueFacet->!ManagedObjects.isNullOrUnspecifiedOrEmpty(valueObject))
+
.flatMap(valueFacet->(Optional<TemporalSupport>)valueFacet.selectTemporalSupportForFeature(objectFeature))
+ .flatMap((final TemporalSupport temporalDecomposer)->{
+ val pojo = MmUnwrapUtils.single(valueObject);
+ return temporalDecomposer.decomposeTemporal(pojo);
+ });
+ }
+
+ // -- HELPER
+
+ @SuppressWarnings({ "rawtypes" })
+ private Optional<ValueFacet> valueFacet(final @Nullable
ObjectSpecification elementType) {
+ return elementType!=null
+ ? elementType.valueFacet()
+ : Optional.empty();
+ }
+
+ @SuppressWarnings({ "rawtypes" })
+ private Optional<ValueFacet> valueFacet(final @Nullable ManagedObject
valueObject) {
+ if(!ManagedObjects.isSpecified(valueObject)) {
+ return Optional.empty();
+ }
+ return valueFacet(valueObject.getSpecification());
+ }
+
+}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateTimeValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateTimeValueSemantics.java
index dada946973..995f146977 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateTimeValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateTimeValueSemantics.java
@@ -20,9 +20,11 @@ package
org.apache.causeway.core.metamodel.valuesemantics.temporal;
import java.time.Duration;
import java.time.LocalDateTime;
+import java.util.Optional;
import javax.inject.Named;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.apache.causeway.applib.value.semantics.OrderRelation;
@@ -57,6 +59,15 @@ implements OrderRelation<LocalDateTime, Duration> {
TemporalAdjust::adjustLocalDateTime);
}
+ // -- TEMPORAL DECOMPOSITION
+
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final @Nullable
LocalDateTime temporal) {
+ return Optional.ofNullable(temporal)
+ .map(t->new TemporalDecomposition(temporal, Optional.empty(),
+ temporalCharacteristic, offsetCharacteristic));
+ }
+
// -- ORDER RELATION
@Override
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateValueSemantics.java
index 674f472e70..f2d8051159 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalDateValueSemantics.java
@@ -20,9 +20,11 @@ package
org.apache.causeway.core.metamodel.valuesemantics.temporal;
import java.time.Duration;
import java.time.LocalDate;
+import java.util.Optional;
import javax.inject.Named;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.apache.causeway.applib.value.semantics.OrderRelation;
@@ -57,6 +59,15 @@ implements OrderRelation<LocalDate, Duration> {
TemporalAdjust::adjustLocalDate);
}
+ // -- TEMPORAL DECOMPOSITION
+
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final @Nullable
LocalDate temporal) {
+ return Optional.ofNullable(temporal)
+ .map(t->new TemporalDecomposition(temporal, Optional.empty(),
+ temporalCharacteristic, offsetCharacteristic));
+ }
+
// -- ORDER RELATION
@Override
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalTimeValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalTimeValueSemantics.java
index f9b27980d2..ca1b7d3728 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalTimeValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/LocalTimeValueSemantics.java
@@ -20,9 +20,11 @@ package
org.apache.causeway.core.metamodel.valuesemantics.temporal;
import java.time.Duration;
import java.time.LocalTime;
+import java.util.Optional;
import javax.inject.Named;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.apache.causeway.commons.collections.Can;
@@ -55,6 +57,15 @@ extends TemporalValueSemanticsProvider<LocalTime> {
TemporalAdjust::adjustLocalTime);
}
+ // -- TEMPORAL DECOMPOSITION
+
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final @Nullable
LocalTime temporal) {
+ return Optional.ofNullable(temporal)
+ .map(t->new TemporalDecomposition(temporal, Optional.empty(),
+ temporalCharacteristic, offsetCharacteristic));
+ }
+
// -- ORDER RELATION
@Override
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetDateTimeValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetDateTimeValueSemantics.java
index 6abed17061..cf4e83d689 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetDateTimeValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetDateTimeValueSemantics.java
@@ -20,12 +20,15 @@ package
org.apache.causeway.core.metamodel.valuesemantics.temporal;
import java.time.Duration;
import java.time.OffsetDateTime;
+import java.util.Optional;
import javax.inject.Named;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.functional.Either;
import org.apache.causeway.commons.internal.base._Temporals;
import org.apache.causeway.schema.common.v2.ValueType;
@@ -55,6 +58,17 @@ extends TemporalValueSemanticsProvider<OffsetDateTime> {
TemporalAdjust::adjustOffsetDateTime);
}
+ // -- TEMPORAL DECOMPOSITION
+
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final @Nullable
OffsetDateTime temporal) {
+ return Optional.ofNullable(temporal)
+ .map(t->new TemporalDecomposition(
+ temporal.toLocalDateTime(),
+ Optional.of(Either.right(t.getOffset())),
+ temporalCharacteristic, offsetCharacteristic));
+ }
+
// -- ORDER RELATION
@Override
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetTimeValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetTimeValueSemantics.java
index 4a4b7d9c4d..0b4593fe72 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetTimeValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/OffsetTimeValueSemantics.java
@@ -20,12 +20,15 @@ package
org.apache.causeway.core.metamodel.valuesemantics.temporal;
import java.time.Duration;
import java.time.OffsetTime;
+import java.util.Optional;
import javax.inject.Named;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.functional.Either;
import org.apache.causeway.commons.internal.base._Temporals;
import org.apache.causeway.schema.common.v2.ValueType;
@@ -55,6 +58,17 @@ extends TemporalValueSemanticsProvider<OffsetTime> {
TemporalAdjust::adjustOffsetTime);
}
+ // -- TEMPORAL DECOMPOSITION
+
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final @Nullable
OffsetTime temporal) {
+ return Optional.ofNullable(temporal)
+ .map(t->new TemporalDecomposition(
+ temporal.toLocalTime(),
+ Optional.of(Either.right(t.getOffset())),
+ temporalCharacteristic, offsetCharacteristic));
+ }
+
// -- ORDER RELATION
@Override
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/ZonedDateTimeValueSemantics.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/ZonedDateTimeValueSemantics.java
index c9593acdec..fdbd616400 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/ZonedDateTimeValueSemantics.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/ZonedDateTimeValueSemantics.java
@@ -20,12 +20,15 @@ package
org.apache.causeway.core.metamodel.valuesemantics.temporal;
import java.time.Duration;
import java.time.ZonedDateTime;
+import java.util.Optional;
import javax.inject.Named;
+import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.functional.Either;
import org.apache.causeway.commons.internal.base._Temporals;
import org.apache.causeway.schema.common.v2.ValueType;
@@ -55,6 +58,17 @@ extends TemporalValueSemanticsProvider<ZonedDateTime> {
TemporalAdjust::adjustZonedDateTime);
}
+ // -- TEMPORAL DECOMPOSITION
+
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final @Nullable
ZonedDateTime temporal) {
+ return Optional.ofNullable(temporal)
+ .map(t->new TemporalDecomposition(
+ temporal.toLocalDateTime(),
+ Optional.of(Either.left(t.getZone())),
+ temporalCharacteristic, offsetCharacteristic));
+ }
+
// -- ORDER RELATION
@Override
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuetypes/TemporalSemanticsAdapter.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuetypes/TemporalSemanticsAdapter.java
index a6e265fd73..3d35e10af1 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuetypes/TemporalSemanticsAdapter.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/valuetypes/TemporalSemanticsAdapter.java
@@ -20,12 +20,25 @@ package org.apache.causeway.core.metamodel.valuetypes;
import java.time.Duration;
import java.time.temporal.Temporal;
+import java.util.Optional;
+
+import org.springframework.lang.Nullable;
import
org.apache.causeway.applib.value.semantics.TemporalCharacteristicsProvider;
+import org.apache.causeway.applib.value.semantics.TemporalSupport;
public abstract class TemporalSemanticsAdapter<T, D extends Temporal>
extends ValueSemanticsAdapter<T, D, Duration>
-implements TemporalCharacteristicsProvider {
+implements
+ TemporalSupport<T> {
+
+ // -- TEMPORAL DECOMPOSITION
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final Optional<TemporalDecomposition> decomposeTemporal(final
@Nullable T value) {
+ return
((TemporalSupport<D>)getDelegate()).decomposeTemporal(toDelegateValue(value));
+ }
// -- ORDER RELATION
diff --git
a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProviderTest.java
b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProviderTest.java
index 4567b585cd..cc9bdd0bcb 100644
---
a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProviderTest.java
+++
b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProviderTest.java
@@ -22,6 +22,7 @@ import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
+import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
@@ -29,6 +30,8 @@ import org.junit.jupiter.params.provider.EnumSource;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import org.springframework.lang.Nullable;
+
import org.apache.causeway.applib.annotation.TimePrecision;
import org.apache.causeway.applib.locale.UserLocale;
import
org.apache.causeway.applib.value.semantics.TemporalCharacteristicsProvider.OffsetCharacteristic;
@@ -37,6 +40,7 @@ import
org.apache.causeway.applib.value.semantics.TemporalValueSemantics;
import
org.apache.causeway.applib.value.semantics.TemporalValueSemantics.EditingFormatDirection;
import
org.apache.causeway.applib.value.semantics.TemporalValueSemantics.TemporalEditingPattern;
import
org.apache.causeway.applib.value.semantics.ValueSemanticsProvider.Context;
+import org.apache.causeway.commons.internal.exceptions._Exceptions;
import org.apache.causeway.core.config.CausewayConfiguration;
import org.apache.causeway.schema.common.v2.ValueType;
@@ -108,6 +112,11 @@ class TemporalValueSemanticsProviderTest {
return super.getTemporalEditingFormat(context,
temporalCharacteristic, offsetCharacteristic, timePrecision, direction,
editingPattern); }
+ @Override
+ public Optional<TemporalDecomposition> decomposeTemporal(final
@Nullable Temporal temporal) {
+ throw _Exceptions.notImplemented(); // method not tested yet
+ }
+
}
}
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
index 8cb8ee6e0d..18c616436a 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
@@ -35,7 +35,7 @@ import org.apache.causeway.core.metamodel.util.Facets;
import org.apache.causeway.viewer.wicket.model.models.ScalarModel;
import
org.apache.causeway.viewer.wicket.model.value.ConverterBasedOnValueSemantics;
import
org.apache.causeway.viewer.wicket.ui.components.scalars.ScalarFragmentFactory.InputFragment;
-import
org.apache.causeway.viewer.wicket.ui.components.scalars.datepicker.TemporalDecomposition;
+import
org.apache.causeway.viewer.wicket.ui.components.scalars.datepicker.TemporalDecompositionModel;
import
org.apache.causeway.viewer.wicket.ui.components.scalars.datepicker.TextFieldWithDateTimePicker;
import
org.apache.causeway.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
import org.apache.causeway.viewer.wicket.ui.util.Wkt;
@@ -51,7 +51,7 @@ extends ScalarPanelTextFieldWithValueSemantics<T> {
private static final long serialVersionUID = 1L;
- private TemporalDecomposition<T> temporalDecomposition;
+ private TemporalDecompositionModel<T> temporalDecomposition;
public ScalarPanelTextFieldWithTemporalPicker(
final String id, final ScalarModel scalarModel, final Class<T>
type) {
@@ -66,7 +66,7 @@ extends ScalarPanelTextFieldWithValueSemantics<T> {
protected final TextField<T> createTextField(final String id) {
val scalarModel = scalarModel();
- this.temporalDecomposition = TemporalDecomposition.create(type,
+ this.temporalDecomposition = TemporalDecompositionModel.create(type,
scalarModel,
offsetCharacteristic(),
(ConverterBasedOnValueSemantics<T>)converterElseFail());
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecomposition.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecompositionModel.java
similarity index 74%
rename from
viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecomposition.java
rename to
viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecompositionModel.java
index 869ea5f4a4..ab0eec9bdd 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecomposition.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecompositionModel.java
@@ -19,11 +19,8 @@
package org.apache.causeway.viewer.wicket.ui.components.scalars.datepicker;
import java.time.Instant;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
import java.time.temporal.Temporal;
import java.util.Locale;
@@ -32,13 +29,17 @@ import org.apache.wicket.util.convert.IConverter;
import org.apache.causeway.applib.services.iactnlayer.InteractionContext;
import
org.apache.causeway.applib.value.semantics.TemporalCharacteristicsProvider.OffsetCharacteristic;
+import
org.apache.causeway.applib.value.semantics.TemporalSupport.TemporalDecomposition;
import org.apache.causeway.applib.value.semantics.ValueSemanticsAbstract;
+import org.apache.causeway.commons.functional.Either;
import org.apache.causeway.commons.internal.assertions._Assert;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.base._Temporals;
+import org.apache.causeway.commons.internal.exceptions._Exceptions;
import org.apache.causeway.core.metamodel.commons.ViewOrEditMode;
import org.apache.causeway.core.metamodel.interactions.managed.ManagedValue;
-import org.apache.causeway.core.metamodel.object.MmUnwrapUtils;
+import org.apache.causeway.core.metamodel.object.MmValueUtils;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectFeature;
import org.apache.causeway.viewer.wicket.model.models.ScalarModel;
import
org.apache.causeway.viewer.wicket.model.value.ConverterBasedOnValueSemantics;
@@ -53,10 +54,10 @@ import lombok.Setter;
* based on existing widgets, that do not support zone or offset information.
*/
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
-public class TemporalDecomposition<T> implements IConverter<T> {
+public class TemporalDecompositionModel<T> implements IConverter<T> {
private static final long serialVersionUID = 1L;
- public static <T extends Temporal> TemporalDecomposition<T> create(final
Class<T> type,
+ public static <T extends Temporal> TemporalDecompositionModel<T>
create(final Class<T> type,
final ScalarModel scalarModel,
final OffsetCharacteristic offsetCharacteristic,
final ConverterBasedOnValueSemantics<T> fullConverter) {
@@ -77,7 +78,7 @@ public class TemporalDecomposition<T> implements
IConverter<T> {
.orElse(ZoneOffset.UTC)
: ZoneOffset.UTC; // not used
- var tempDecomp = new TemporalDecomposition<>(type,
+ var tempDecomp = new TemporalDecompositionModel<>(type,
offsetCharacteristic,
userZoneId,
fullConverter,
@@ -85,7 +86,7 @@ public class TemporalDecomposition<T> implements
IConverter<T> {
editingPattern);
if(needsDecomposition) {
- tempDecomp.initFrom(scalarModel.proposedValue());
+ tempDecomp.initFrom(scalarModel.getMetaModel(),
scalarModel.proposedValue());
}
return tempDecomp;
}
@@ -99,37 +100,23 @@ public class TemporalDecomposition<T> implements
IConverter<T> {
@Getter
private final String editingPattern;
- /**
- * @implNote only supports zoned types as known at the time of writing
- */
- private void initFrom(final ManagedValue proposedValue) {
- var temporalValue =
MmUnwrapUtils.single(proposedValue.getValue().getValue());
- if(temporalValue instanceof ZonedDateTime) {
- var zonedDateTime = (ZonedDateTime) temporalValue;
- this.zoneId = zonedDateTime.getZone();
- } else if(temporalValue instanceof OffsetDateTime) {
- var offsetDateTime = (OffsetDateTime) temporalValue;
- this.zoneOffset = offsetDateTime.getOffset();
- } else if(temporalValue instanceof OffsetTime) {
- var offsetTime = (OffsetTime) temporalValue;
- this.zoneOffset = offsetTime.getOffset();
- } else if(temporalValue instanceof org.joda.time.DateTime) {
- var jodaDateTime = (org.joda.time.DateTime) temporalValue;
- this.zoneId = jodaDateTime.getZone().toTimeZone().toZoneId();
- } else {
- // either temporalValue is null or unsupported
- switch (offsetCharacteristic) {
- case OFFSET:
- this.zoneOffset =
userZoneId.getRules().getOffset(Instant.now());
- break;
- case ZONED:
- this.zoneId = userZoneId;
- break;
- case LOCAL:
- default:
- break;
- }
- }
+ private void initFrom(final ObjectFeature objectFeature, final
ManagedValue proposedValue) {
+ var temporalValue = proposedValue.getValue().getValue();
+ var zoneOrOffset = MmValueUtils.temporalDecomposition(objectFeature,
temporalValue)
+ .flatMap(TemporalDecomposition::zoneOrOffset)
+ .orElseGet(()->{
+ // either temporalValue is null, empty or unsupported
+ switch (offsetCharacteristic) {
+ case ZONED:
+ return Either.left(userZoneId);
+ case OFFSET:
+ return
Either.right(userZoneId.getRules().getOffset(Instant.now()));
+ case LOCAL:
+ default:
+ throw _Exceptions.unexpectedCodeReach();
+ }
+ });
+ zoneOrOffset.accept(this::setZoneId, this::setZoneOffset);
}
// -- CONVERTER
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
index 7da8838098..d564ab7333 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/markup/MarkupComponent.java
@@ -106,7 +106,7 @@ public class MarkupComponent extends WebComponent {
if(modelObject instanceof ManagedObject) {
val adapter = (ManagedObject) modelObject;
val feature =
lookupObjectFeatureIn(getDefaultModel()).orElse(null);
- val asHtml = MmRenderUtils.htmlStringForValueType(adapter,
feature);
+ val asHtml = MmRenderUtils.htmlStringForValueType(feature,
adapter);
return asHtml != null
? asHtml
: fallback;
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/value/StandaloneValuePanel.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/value/StandaloneValuePanel.java
index e76216b8a9..9b2e2c31d7 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/value/StandaloneValuePanel.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/value/StandaloneValuePanel.java
@@ -51,7 +51,7 @@ extends PanelAbstract<ManagedObject, ValueModel> {
// (we probably need to remove StandaloneValuePanel and utilize the
ScalarPanel for standalone values instead)
if(isProbablySimpleInlineHtml(valueModel.getObjectMember().getElementType())) {
Wkt.markupAdd(this, ID_STANDALONE_VALUE, ()->
- MmRenderUtils.htmlStringForValueType(getModel().getObject(),
getModel().getObjectMember())
+
MmRenderUtils.htmlStringForValueType(getModel().getObjectMember(),
getModel().getObject())
);
} else {
// resort to (textual) title rendering