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 2020/04/19 10:09:26 UTC
[isis] branch master updated: ISIS-2340: binding presentation to
domain model (yet missing validation)
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 ea4c1bc ISIS-2340: binding presentation to domain model (yet missing validation)
ea4c1bc is described below
commit ea4c1bc6eb2b3a58a3206f12995887a056a03ca5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Apr 19 12:09:12 2020 +0200
ISIS-2340: binding presentation to domain model (yet missing validation)
---
.../viewer/vaadin/ui/binding/BinderUtil.java | 114 +++++++++++++++++++++
.../ui/components/object/ObjectFormView.java | 14 ++-
.../vaadin/ui/components/temporal/DateField.java | 18 ++--
.../components/temporal/TemporalFieldFactory.java | 49 +++++----
.../common/model/binding/UiComponentFactory.java | 15 ++-
5 files changed, 180 insertions(+), 30 deletions(-)
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/binding/BinderUtil.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/binding/BinderUtil.java
new file mode 100644
index 0000000..a60c0cf
--- /dev/null
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/binding/BinderUtil.java
@@ -0,0 +1,114 @@
+/*
+ * 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.incubator.viewer.vaadin.ui.binding;
+
+import java.time.LocalDate;
+import java.util.Locale;
+
+import com.vaadin.flow.component.HasValue;
+import com.vaadin.flow.data.binder.Binder;
+import com.vaadin.flow.data.binder.ValueContext;
+import com.vaadin.flow.data.converter.Converter;
+import com.vaadin.flow.data.converter.DateToSqlDateConverter;
+import com.vaadin.flow.data.converter.LocalDateToDateConverter;
+
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
+import org.apache.isis.viewer.common.model.binding.UiComponentFactory.Request;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public final class BinderUtil {
+
+ public static <T> Binder<Request> requestBinder(
+ final HasValue<?, T> uiField,
+ final Class<T> fieldValueType) {
+
+ final Binder<Request> binder = new Binder<>();
+ binder.forField(uiField)
+ .bind(
+ request->request.getPojo(fieldValueType).orElse(null),
+ (request, newValue)->request.getPropagator(fieldValueType).apply(newValue));
+ return binder;
+ }
+
+ /**
+ *
+ * @param <T> field value type (presentation type)
+ * @param <U> model value type
+ * @param uiField
+ * @param modelValueType
+ * @param converter
+ * @return
+ */
+ public static <T, U> Binder<Request> requestBinderWithConverter(
+ final HasValue<?, T> uiField,
+ final Class<U> modelValueType,
+ final Converter<T, U> converter) {
+
+ final ValueContext valueContext = new ValueContext(Locale.getDefault());
+
+ final Binder<Request> binder = new Binder<>();
+
+ binder.forField(uiField)
+ .bind(
+ request->request
+ .getPojo(modelValueType)
+ .map(modelValue->converter.convertToPresentation(modelValue, valueContext))
+ .orElse(null),
+ (request, newValue)->request
+ .getPropagator(modelValueType)
+ .apply(converter
+ .convertToModel(newValue, valueContext)
+ .getOrThrow(message-> {
+ throw _Exceptions.illegalArgument("cannot convert due %s", message);
+ }))
+ );
+ return binder;
+ }
+
+ // -- SHORTCUTS
+
+ public static enum DateBinder {
+
+ JAVA_TIME_LOCAL_DATE{
+
+ @Override
+ public Binder<Request> bind(HasValue<?, LocalDate> uiField) {
+ return BinderUtil.requestBinder(uiField, LocalDate.class);
+ }
+
+ },
+ JAVA_SQL_DATE{
+
+ @Override
+ public Binder<Request> bind(HasValue<?, LocalDate> uiField) {
+ return BinderUtil.requestBinderWithConverter(uiField, java.sql.Date.class,
+ new LocalDateToDateConverter().chain(new DateToSqlDateConverter()));
+ }
+
+ };
+
+ public abstract Binder<Request> bind(final HasValue<?, LocalDate> uiField);
+
+ }
+
+
+
+}
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java
index 8884ba9..bef8517 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java
@@ -20,6 +20,7 @@ package org.apache.isis.incubator.viewer.vaadin.ui.components.object;
import java.util.Collection;
import java.util.Optional;
+import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import com.vaadin.flow.component.Component;
@@ -30,8 +31,10 @@ import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.MutableCurrentHolder;
import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
import org.apache.isis.incubator.viewer.vaadin.ui.components.UiComponentFactoryVaa;
@@ -74,7 +77,16 @@ public class ObjectFormView extends VerticalLayout {
tablesLayout.add(new Label(objectAssociation.getName()));
tablesLayout.add(createCollectionComponent(objectAssociation, assocObject));
} else {
- val uiComponentCreateRequest = UiComponentFactory.Request.of(assocObject, objectAssociation);
+
+ final UnaryOperator<ManagedObject> toDomainPropagator = proposedNewValue -> {
+ MutableCurrentHolder property = (MutableCurrentHolder) objectAssociation;
+ property.set(managedObject, proposedNewValue, InteractionInitiatedBy.USER);
+ // TODO where is the rule checking part?
+ return proposedNewValue;
+ };
+
+ val uiComponentCreateRequest = UiComponentFactory.Request
+ .of(assocObject, objectAssociation, toDomainPropagator);
val uiComponent = uiComponentFactory.componentFor(uiComponentCreateRequest);
formLayout.add(uiComponent);
}
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/DateField.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/DateField.java
index 1efb183..fcdce50 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/DateField.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/DateField.java
@@ -30,8 +30,8 @@ public class DateField extends CustomField<LocalDate> {
private static final long serialVersionUID = 1L;
private final DatePicker datePicker = new DatePicker();
- private LocalDate temporal;
-
+ private boolean isNull;
+
public DateField(String label) {
super();
setLabel(label);
@@ -40,20 +40,20 @@ public class DateField extends CustomField<LocalDate> {
@Override
protected LocalDate generateModelValue() {
- return temporal;
+ return datePicker.getValue();
}
@Override
- protected void setPresentationValue(@Nullable LocalDate temporal) {
- this.temporal = temporal;
+ protected void setPresentationValue(@Nullable LocalDate newValue) {
- if(temporal==null) {
+ this.isNull = newValue==null;
+ datePicker.setValue(newValue);
+
+ if(this.isNull) {
datePicker.setPlaceholder("no date");
- return;
}
- datePicker.setValue(temporal);
-
}
+
}
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/TemporalFieldFactory.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/TemporalFieldFactory.java
index e5852ed..9048b4b 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/TemporalFieldFactory.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/temporal/TemporalFieldFactory.java
@@ -19,16 +19,17 @@
package org.apache.isis.incubator.viewer.vaadin.ui.components.temporal;
import java.time.LocalDate;
-import java.time.temporal.Temporal;
-import java.util.Optional;
import com.vaadin.flow.component.Component;
+import com.vaadin.flow.data.binder.Binder;
import org.springframework.core.annotation.Order;
import org.apache.isis.applib.annotation.OrderPrecedence;
import org.apache.isis.core.commons.internal.exceptions._Exceptions;
import org.apache.isis.core.metamodel.facets.value.temporal.TemporalValueFacet;
+import org.apache.isis.core.metamodel.facets.value.temporal.TemporalValueFacet.TemporalCharacteristic;
+import org.apache.isis.incubator.viewer.vaadin.ui.binding.BinderUtil;
import org.apache.isis.incubator.viewer.vaadin.ui.components.UiComponentHandlerVaa;
import org.apache.isis.viewer.common.model.binding.UiComponentFactory.Request;
@@ -40,24 +41,44 @@ public class TemporalFieldFactory implements UiComponentHandlerVaa {
@Override
public boolean isHandling(Request request) {
- return request.hasFeatureFacet(TemporalValueFacet.class)
+ return request.isFeatureTypeEqualTo(java.sql.Date.class)
+ ||(request.hasFeatureFacet(TemporalValueFacet.class)
// TODO lift this restrictions, as we support more types
- && request.isFeatureTypeEqualTo(LocalDate.class);
+ && (
+ request.isFeatureTypeEqualTo(LocalDate.class)
+// || request.isFeatureTypeEqualTo(java.sql.Date.class)
+ ));
}
@Override
public Component handle(Request request) {
- val temporalFacet = request.getFeatureFacetElseFail(TemporalValueFacet.class);
- val temporalCharacteristic = temporalFacet.getTemporalCharacteristic();
- val offsetCharacteristic = temporalFacet.getOffsetCharacteristic();
- val temporal = request.getPojo(Temporal.class);
+ val temporalFacet = request.getFeatureFacet(TemporalValueFacet.class);
+ val temporalCharacteristic = temporalFacet
+ .map(TemporalValueFacet::getTemporalCharacteristic)
+ .orElse(TemporalCharacteristic.DATE_ONLY);
+ //val offsetCharacteristic = temporalFacet.getOffsetCharacteristic();
switch(temporalCharacteristic) {
case DATE_ONLY:{
+
val uiField = new DateField(request.getFeatureLabel());
- uiField.setValue(toLocalDate(temporal).orElse(null));
+
+ final Binder<Request> binder;
+ if(request.isFeatureTypeEqualTo(LocalDate.class)) {
+ binder = BinderUtil.DateBinder.JAVA_TIME_LOCAL_DATE.bind(uiField);
+ } else if(request.isFeatureTypeEqualTo(java.sql.Date.class)) {
+ binder = BinderUtil.DateBinder.JAVA_SQL_DATE.bind(uiField);
+ } else {
+ throw _Exceptions.unmatchedCase(request.getFeatureType());
+ }
+
+ binder.setBean(request);
return uiField;
+
+ //val uiField = DateField.bind(request);
+
+
}
case TIME_ONLY:{
// TODO ...
@@ -71,14 +92,4 @@ public class TemporalFieldFactory implements UiComponentHandlerVaa {
}
- private Optional<LocalDate> toLocalDate(Optional<Temporal> temporal) {
- return temporal.map(this::toLocalDate);
- }
-
- private LocalDate toLocalDate(Temporal temporal) {
- return (temporal instanceof LocalDate)
- ? (LocalDate) temporal
- : null;
- }
-
}
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java
index 344158e..1f954eb 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java
@@ -19,10 +19,12 @@
package org.apache.isis.viewer.common.model.binding;
import java.util.Optional;
+import java.util.function.UnaryOperator;
import javax.annotation.Nullable;
import org.apache.isis.core.commons.handler.ChainOfResponsibility;
+import org.apache.isis.core.commons.internal.base._Casts;
import org.apache.isis.core.commons.internal.exceptions._Exceptions;
import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -31,6 +33,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
import lombok.NonNull;
import lombok.Value;
+import lombok.val;
public interface UiComponentFactory<T> {
@@ -43,6 +46,7 @@ public interface UiComponentFactory<T> {
/** not null but the wrapped pojo is allowed to be null*/
@NonNull private final ManagedObject managedObject;
@NonNull private final ObjectFeature objectFeature;
+ @NonNull private final UnaryOperator<ManagedObject> toDomainPropagator;
// -- SHORTCUTS
@@ -113,7 +117,16 @@ public interface UiComponentFactory<T> {
return Optional.ofNullable(getManagedObject().getPojo())
.map(type::cast);
}
-
+
+ public <T> UnaryOperator<T> getPropagator(Class<T> pojoType) {
+ return (T newValueProposal)->{
+ val newValue = ManagedObject.of(getFeatureSpec(), newValueProposal);
+ return _Casts.uncheckedCast(
+ toDomainPropagator
+ .apply(newValue)
+ .getPojo());
+ };
+ }
}