aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorDenis <denis@vaadin.com>2017-01-10 12:22:34 +0200
committerGitHub <noreply@github.com>2017-01-10 12:22:34 +0200
commit3ef30789d6ac773eed7346dcaa670426fa6f662c (patch)
tree2e5aee20b96e3a66088aa6cde13796256ec2bcf1 /server
parentb4af93bebf1b7e51d33330c42e3c89d5e3e4fd45 (diff)
downloadvaadin-framework-3ef30789d6ac773eed7346dcaa670426fa6f662c.tar.gz
vaadin-framework-3ef30789d6ac773eed7346dcaa670426fa6f662c.zip
Refactor AbstractDateField. (#8146)
First round for #8132.
Diffstat (limited to 'server')
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractComponent.java7
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractDateField.java283
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java139
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java58
-rw-r--r--server/src/main/java/com/vaadin/ui/DateField.java14
-rw-r--r--server/src/main/java/com/vaadin/ui/InlineDateField.java4
-rw-r--r--server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java11
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/abstractdatefield/AbstractLocalDateFieldDeclarativeTest.java (renamed from server/src/test/java/com/vaadin/tests/server/component/abstractdatefield/AbstractDateFieldDeclarativeTest.java)8
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldDeclarativeTest.java4
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java39
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/datefield/InlineDateFieldDeclarativeTest.java4
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/datefield/ResolutionTest.java32
-rw-r--r--server/src/test/java/com/vaadin/ui/DateFieldTestCase.java4
13 files changed, 448 insertions, 159 deletions
diff --git a/server/src/main/java/com/vaadin/ui/AbstractComponent.java b/server/src/main/java/com/vaadin/ui/AbstractComponent.java
index 88bdc6f3dc..03a7c14eb5 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractComponent.java
@@ -1223,9 +1223,10 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Returns a collection of attributes that should not be handled by the
- * basic implementation of the {@link #readDesign(Element, DesignContext)} and {@link #writeDesign(Element, DesignContext)}
- * methods. Typically these are handled in a custom way in the overridden
- * versions of the above methods
+ * basic implementation of the {@link #readDesign(Element, DesignContext)}
+ * and {@link #writeDesign(Element, DesignContext)} methods. Typically these
+ * are handled in a custom way in the overridden versions of the above
+ * methods
*
* @since 7.4
*
diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java
index 53415f45a6..0a6cf8fc51 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java
@@ -15,24 +15,31 @@
*/
package com.vaadin.ui;
+import java.io.Serializable;
+import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
-import java.time.Instant;
import java.time.LocalDate;
-import java.time.ZoneOffset;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
import java.util.Calendar;
import java.util.Date;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.jsoup.nodes.Element;
+import com.googlecode.gentyref.GenericTypeReflector;
import com.vaadin.data.Result;
import com.vaadin.data.ValidationResult;
import com.vaadin.data.ValueContext;
-import com.vaadin.data.validator.DateRangeValidator;
+import com.vaadin.data.validator.RangeValidator;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
@@ -43,9 +50,9 @@ import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.server.UserError;
import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.datefield.AbstractDateFieldState;
import com.vaadin.shared.ui.datefield.DateFieldConstants;
-import com.vaadin.shared.ui.datefield.Resolution;
-import com.vaadin.shared.ui.datefield.TextualDateFieldState;
+import com.vaadin.shared.ui.datefield.DateResolution;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
@@ -55,20 +62,26 @@ import com.vaadin.ui.declarative.DesignContext;
* @author Vaadin Ltd
*
* @since 8.0
- *
+ *
+ * @param <T>
+ * type of date ({@code LocalDate} or {@code LocalDateTime}).
+ * @param <R>
+ * resolution enumeration type
+ *
*/
-public abstract class AbstractDateField extends AbstractField<LocalDate>
+public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & Serializable & Comparable<? super T>, R extends Enum<R>>
+ extends AbstractField<T>
implements LegacyComponent, FocusNotifier, BlurNotifier {
/**
* Value of the field.
*/
- private LocalDate value;
+ private T value;
/**
* Specified smallest modifiable unit for the date field.
*/
- private Resolution resolution = Resolution.DAY;
+ private R resolution;
/**
* Overridden format string
@@ -94,8 +107,6 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
private String defaultParseErrorMessage = "Date format not recognized";
- private static Map<Resolution, String> variableNameForResolution = new HashMap<>();
-
private String dateOutOfRangeMessage = "Date is out of allowed range";
/**
@@ -105,42 +116,46 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
*/
private boolean preventValueChangeEvent;
- static {
- variableNameForResolution.put(Resolution.DAY, "day");
- variableNameForResolution.put(Resolution.MONTH, "month");
- variableNameForResolution.put(Resolution.YEAR, "year");
- }
-
/* Constructors */
/**
- * Constructs an empty <code>DateField</code> with no caption.
+ * Constructs an empty <code>AbstractDateField</code> with no caption and
+ * specified {@code resolution}.
+ *
+ * @param resolution
+ * initial resolution for the field
*/
- public AbstractDateField() {
+ public AbstractDateField(R resolution) {
+ this.resolution = resolution;
}
/**
- * Constructs an empty <code>DateField</code> with caption.
+ * Constructs an empty <code>AbstractDateField</code> with caption.
*
* @param caption
* the caption of the datefield.
+ * @param resolution
+ * initial resolution for the field
*/
- public AbstractDateField(String caption) {
+ public AbstractDateField(String caption, R resolution) {
+ this(resolution);
setCaption(caption);
}
/**
- * Constructs a new <code>DateField</code> with the given caption and
- * initial text contents.
+ * Constructs a new <code>AbstractDateField</code> with the given caption
+ * and initial text contents.
*
* @param caption
* the caption <code>String</code> for the editor.
* @param value
- * the LocalDate value.
+ * the date/time value.
+ * @param resolution
+ * initial resolution for the field
*/
- public AbstractDateField(String caption, LocalDate value) {
+ public AbstractDateField(String caption, T value, R resolution) {
+ this(caption, resolution);
setValue(value);
- setCaption(caption);
}
/* Component basic features */
@@ -174,17 +189,16 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
* app or refresh.
*/
- final LocalDate currentDate = getValue();
+ final T currentDate = getValue();
// Only paint variables for the resolution and up, e.g. Resolution DAY
// paints DAY,MONTH,YEAR
- for (Resolution res : Resolution
- .getResolutionsHigherOrEqualTo(resolution)) {
+ for (R res : getResolutionsHigherOrEqualTo(getResolution())) {
int value = -1;
if (currentDate != null) {
- value = getDateValue(currentDate, res);
+ value = getDatePart(currentDate, res);
}
- target.addVariable(this, variableNameForResolution.get(res), value);
+ target.addVariable(this, getResolutionVariable(res), value);
}
}
@@ -195,15 +209,15 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
*/
@Override
public void changeVariables(Object source, Map<String, Object> variables) {
-
- if (!isReadOnly() && (variables.containsKey("year")
- || variables.containsKey("month")
- || variables.containsKey("day")
+ Set<String> resolutionNames = getResolutions()
+ .map(this::getResolutionVariable).collect(Collectors.toSet());
+ resolutionNames.retainAll(variables.keySet());
+ if (!isReadOnly() && (!resolutionNames.isEmpty()
|| variables.containsKey("dateString"))) {
// Old and new dates
- final LocalDate oldDate = getValue();
- LocalDate newDate = null;
+ final T oldDate = getValue();
+ T newDate = null;
// this enables analyzing invalid input on the server
final String newDateString = (String) variables.get("dateString");
@@ -211,15 +225,15 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
// Gets the new date in parts
boolean hasChanges = false;
- Map<Resolution, Integer> calendarFields = new HashMap<>();
+ Map<R, Integer> calendarFields = new HashMap<>();
- for (Resolution resolution : Resolution
- .getResolutionsHigherOrEqualTo(getResolution())) {
+ for (R resolution : getResolutionsHigherOrEqualTo(
+ getResolution())) {
// Only handle what the client is allowed to send. The same
// resolutions that are painted
- String variableName = variableNameForResolution.get(resolution);
+ String variableName = getResolutionVariable(resolution);
- Integer value = getDateValue(oldDate, resolution);
+ int value = getDatePart(oldDate, resolution);
if (variables.containsKey(variableName)) {
Integer newValue = (Integer) variables.get(variableName);
if (newValue >= 0) {
@@ -234,15 +248,12 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
if (!hasChanges) {
newDate = null;
} else {
- newDate = LocalDate.of(calendarFields.get(Resolution.YEAR),
- calendarFields.getOrDefault(Resolution.MONTH, 1),
- calendarFields.getOrDefault(Resolution.DAY, 1));
+ newDate = buildDate(calendarFields);
}
if (newDate == null && dateString != null
&& !dateString.isEmpty()) {
- Result<LocalDate> parsedDate = handleUnparsableDateString(
- dateString);
+ Result<T> parsedDate = handleUnparsableDateString(dateString);
if (parsedDate.isError()) {
/*
@@ -332,8 +343,8 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
* @param startDate
* - the allowed range's start date
*/
- public void setRangeStart(LocalDate startDate) {
- Date date = convertLocalDate(startDate);
+ public void setRangeStart(T startDate) {
+ Date date = convertToDate(startDate);
if (date != null && getState().rangeEnd != null
&& date.after(getState().rangeEnd)) {
throw new IllegalStateException(
@@ -367,21 +378,21 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
/**
* Gets the resolution.
*
- * @return int
+ * @return the date/time field resolution
*/
- public Resolution getResolution() {
+ public R getResolution() {
return resolution;
}
/**
* Sets the resolution of the DateField.
*
- * The default resolution is {@link Resolution#DAY} since Vaadin 7.0.
+ * The default resolution is {@link DateResolution#DAY} since Vaadin 7.0.
*
* @param resolution
- * the resolution to set.
+ * the resolution to set, not {@code null}
*/
- public void setResolution(Resolution resolution) {
+ public void setResolution(R resolution) {
this.resolution = resolution;
markAsDirty();
}
@@ -396,8 +407,8 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
* - the allowed range's end date (inclusive, based on the
* current resolution)
*/
- public void setRangeEnd(LocalDate endDate) {
- Date date = convertLocalDate(endDate);
+ public void setRangeEnd(T endDate) {
+ Date date = convertToDate(endDate);
if (date != null && getState().rangeStart != null
&& getState().rangeStart.after(date)) {
throw new IllegalStateException(
@@ -412,8 +423,8 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
*
* @return the precise rangeStart used, may be null.
*/
- public LocalDate getRangeStart() {
- return convertDate(getState(false).rangeStart);
+ public T getRangeStart() {
+ return convertFromDate(getState(false).rangeStart);
}
/**
@@ -421,8 +432,8 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
*
* @return the precise rangeEnd used, may be null.
*/
- public LocalDate getRangeEnd() {
- return convertDate(getState(false).rangeEnd);
+ public T getRangeEnd() {
+ return convertFromDate(getState(false).rangeEnd);
}
/**
@@ -482,7 +493,7 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
}
@Override
- public LocalDate getValue() {
+ public T getValue() {
return value;
}
@@ -494,7 +505,7 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
* the new value, may be {@code null}
*/
@Override
- public void setValue(LocalDate value) {
+ public void setValue(T value) {
/*
* First handle special case when the client side component have a date
* string but value is null (e.g. unparsable date string typed in by the
@@ -580,17 +591,28 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
}
@Override
+ @SuppressWarnings("unchecked")
public void readDesign(Element design, DesignContext designContext) {
super.readDesign(design, designContext);
if (design.hasAttr("value") && !design.attr("value").isEmpty()) {
- LocalDate date = DesignAttributeHandler.getFormatter()
- .parse(design.attr("value"), LocalDate.class);
- // formatting will return null if it cannot parse the string
- if (date == null) {
- Logger.getLogger(AbstractDateField.class.getName()).info(
- "cannot parse " + design.attr("value") + " as date");
+ Type dateType = GenericTypeReflector.getTypeParameter(getClass(),
+ AbstractDateField.class.getTypeParameters()[0]);
+ if (dateType instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) dateType;
+ T date = (T) DesignAttributeHandler.getFormatter()
+ .parse(design.attr("value"), clazz);
+ // formatting will return null if it cannot parse the string
+ if (date == null) {
+ Logger.getLogger(AbstractDateField.class.getName())
+ .info("cannot parse " + design.attr("value")
+ + " as date");
+ }
+ doSetValue(date);
+ } else {
+ throw new RuntimeException("Cannot detect resoluton type "
+ + Optional.ofNullable(dateType).map(Type::getTypeName)
+ .orElse(null));
}
- doSetValue(date);
}
}
@@ -629,22 +651,22 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
* date string to handle
* @return result that contains parsed Date as a value or an error
*/
- protected Result<LocalDate> handleUnparsableDateString(String dateString) {
+ protected Result<T> handleUnparsableDateString(String dateString) {
return Result.error(getParseErrorMessage());
}
@Override
- protected TextualDateFieldState getState() {
- return (TextualDateFieldState) super.getState();
+ protected AbstractDateFieldState getState() {
+ return (AbstractDateFieldState) super.getState();
}
@Override
- protected TextualDateFieldState getState(boolean markAsDirty) {
- return (TextualDateFieldState) super.getState(markAsDirty);
+ protected AbstractDateFieldState getState(boolean markAsDirty) {
+ return (AbstractDateFieldState) super.getState(markAsDirty);
}
@Override
- protected void doSetValue(LocalDate value) {
+ protected void doSetValue(T value) {
// Also set the internal dateString
if (value != null) {
dateString = value.toString();
@@ -659,10 +681,7 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
uiHasValidDateString = true;
setComponentError(new UserError(currentParseErrorMessage));
} else {
- DateRangeValidator validator = new DateRangeValidator(
- getDateOutOfRangeMessage(),
- getDate(getRangeStart(), getResolution()),
- getDate(getRangeEnd(), getResolution()));
+ RangeValidator<T> validator = getRangeValidator();
ValidationResult result = validator.apply(value,
new ValueContext(this));
if (result.isError()) {
@@ -671,50 +690,80 @@ public abstract class AbstractDateField extends AbstractField<LocalDate>
}
}
- private LocalDate getDate(LocalDate date, Resolution forResolution) {
- if (date == null) {
- return null;
- }
- if (forResolution == Resolution.YEAR) {
- return date.withDayOfYear(1);
- } else if (forResolution == Resolution.MONTH) {
- return date.withDayOfMonth(1);
- } else {
- return date;
- }
- }
+ /**
+ * Returns a date integer value part for the given {@code date} for the
+ * given {@code resolution}.
+ *
+ * @param date
+ * the given date
+ * @param resolution
+ * the resolution to extract a value from the date by
+ * @return the integer value part of the date by the given resolution
+ */
+ protected abstract int getDatePart(T date, R resolution);
- private int getDateValue(LocalDate date, Resolution resolution) {
- LocalDate value = date;
- if (value == null) {
- value = LocalDate.of(1, 1, 1);
- }
- switch (resolution) {
- case DAY:
- return value.getDayOfMonth();
- case MONTH:
- return value.getMonthValue();
- case YEAR:
- return value.getYear();
- default:
- assert false : "Unexpected resolution argument " + resolution;
- return -1;
- }
+ /**
+ * Builds date by the given {@code resolutionValues} which is a map whose
+ * keys are resolution and integer values.
+ * <p>
+ * This is the opposite to {@link #getDatePart(Temporal, Enum)}.
+ *
+ * @param resolutionValues
+ * date values to construct a date
+ * @return date built from the given map of date values
+ */
+ protected abstract T buildDate(Map<R, Integer> resolutionValues);
+
+ /**
+ * Returns a custom date range validator which is applicable for the type
+ * {@code T}.
+ *
+ * @return the date range validator
+ */
+ protected abstract RangeValidator<T> getRangeValidator();
+
+ /**
+ * Converts {@link Date} to date type {@code T}.
+ *
+ * @param date
+ * a date to convert
+ * @return object of type {@code T} representing the {@code date}
+ */
+ protected abstract T convertFromDate(Date date);
+
+ /**
+ * Converts the object of type {@code T} to {@link Date}.
+ * <p>
+ * This is the opposite to {@link #convertFromDate(Date)}.
+ *
+ * @param date
+ * the date of type {@code T}
+ * @return converted date of type {@code Date}
+ */
+ protected abstract Date convertToDate(T date);
+
+ private String getResolutionVariable(R resolution) {
+ return resolution.name().toLowerCase(Locale.ENGLISH);
}
- private Date convertLocalDate(LocalDate date) {
- if (date == null) {
- return null;
+ @SuppressWarnings("unchecked")
+ private Stream<R> getResolutions() {
+ Type resolutionType = GenericTypeReflector.getTypeParameter(getClass(),
+ AbstractDateField.class.getTypeParameters()[1]);
+ if (resolutionType instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) resolutionType;
+ return Stream.of(clazz.getEnumConstants())
+ .map(object -> (R) object);
+ } else {
+ throw new RuntimeException("Cannot detect resoluton type "
+ + Optional.ofNullable(resolutionType).map(Type::getTypeName)
+ .orElse(null));
}
- return Date.from(date.atStartOfDay(ZoneOffset.UTC).toInstant());
}
- private LocalDate convertDate(Date date) {
- if (date == null) {
- return null;
- }
- return Instant.ofEpochMilli(date.getTime()).atZone(ZoneOffset.UTC)
- .toLocalDate();
+ private Iterable<R> getResolutionsHigherOrEqualTo(R resoution) {
+ return getResolutions().skip(resolution.ordinal())
+ .collect(Collectors.toList());
}
}
diff --git a/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java b/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java
new file mode 100644
index 0000000000..ab99fe0f28
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed 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 com.vaadin.ui;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.util.Date;
+import java.util.Map;
+
+import com.vaadin.data.validator.DateRangeValidator;
+import com.vaadin.data.validator.RangeValidator;
+import com.vaadin.shared.ui.datefield.AbstractTextualDateFieldState;
+import com.vaadin.shared.ui.datefield.DateResolution;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public abstract class AbstractLocalDateField
+ extends AbstractDateField<LocalDate, DateResolution> {
+
+ /**
+ * Constructs an empty <code>AbstractLocalDateField</code> with no caption.
+ */
+ public AbstractLocalDateField() {
+ super(DateResolution.DAY);
+ }
+
+ /**
+ * Constructs an empty <code>AbstractLocalDateField</code> with caption.
+ *
+ * @param caption
+ * the caption of the datefield.
+ */
+ public AbstractLocalDateField(String caption) {
+ super(caption, DateResolution.DAY);
+ }
+
+ /**
+ * Constructs a new <code>AbstractLocalDateField</code> with the given
+ * caption and initial text contents.
+ *
+ * @param caption
+ * the caption <code>String</code> for the editor.
+ * @param value
+ * the LocalDate value.
+ */
+ public AbstractLocalDateField(String caption, LocalDate value) {
+ super(caption, value, DateResolution.DAY);
+ }
+
+ @Override
+ protected int getDatePart(LocalDate date, DateResolution resolution) {
+ LocalDate value = date;
+ if (value == null) {
+ value = LocalDate.of(1, 1, 1);
+ }
+ switch (resolution) {
+ case DAY:
+ return value.getDayOfMonth();
+ case MONTH:
+ return value.getMonthValue();
+ case YEAR:
+ return value.getYear();
+ default:
+ assert false : "Unexpected resolution argument " + resolution;
+ return -1;
+ }
+ }
+
+ @Override
+ protected LocalDate buildDate(
+ Map<DateResolution, Integer> resolutionValues) {
+ return LocalDate.of(resolutionValues.get(DateResolution.YEAR),
+ resolutionValues.getOrDefault(DateResolution.MONTH, 1),
+ resolutionValues.getOrDefault(DateResolution.DAY, 1));
+ }
+
+ @Override
+ protected RangeValidator<LocalDate> getRangeValidator() {
+ return new DateRangeValidator(getDateOutOfRangeMessage(),
+ getDate(getRangeStart(), getResolution()),
+ getDate(getRangeEnd(), getResolution()));
+ }
+
+ @Override
+ protected AbstractTextualDateFieldState getState() {
+ return (AbstractTextualDateFieldState) super.getState();
+ }
+
+ @Override
+ protected AbstractTextualDateFieldState getState(boolean markAsDirty) {
+ return (AbstractTextualDateFieldState) super.getState(markAsDirty);
+ }
+
+ @Override
+ protected LocalDate convertFromDate(Date date) {
+ if (date == null) {
+ return null;
+ }
+ return Instant.ofEpochMilli(date.getTime()).atZone(ZoneOffset.UTC)
+ .toLocalDate();
+ }
+
+ @Override
+ protected Date convertToDate(LocalDate date) {
+ if (date == null) {
+ return null;
+ }
+ return Date.from(date.atStartOfDay(ZoneOffset.UTC).toInstant());
+ }
+
+ private LocalDate getDate(LocalDate date, DateResolution forResolution) {
+ if (date == null) {
+ return null;
+ }
+ if (forResolution == DateResolution.YEAR) {
+ return date.withDayOfYear(1);
+ } else if (forResolution == DateResolution.MONTH) {
+ return date.withDayOfMonth(1);
+ } else {
+ return date;
+ }
+ }
+}
diff --git a/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java b/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java
new file mode 100644
index 0000000000..9be77444c6
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed 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 com.vaadin.ui;
+
+import java.time.LocalDateTime;
+
+import com.vaadin.shared.ui.datefield.DateTimeResolution;
+import com.vaadin.shared.ui.datefield.LocalDateTimeFieldState;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public abstract class AbstractLocalDateTimeField
+ extends AbstractDateField<LocalDateTime, DateTimeResolution> {
+
+ /**
+ * Constructs an empty <code>AbstractLocalDateTimeField</code> with no
+ * caption.
+ */
+ public AbstractLocalDateTimeField() {
+ super(DateTimeResolution.MINUTE);
+ }
+
+ /**
+ * Constructs an empty <code>AbstractLocalDateTimeField</code> with caption.
+ *
+ * @param caption
+ * the caption of the datefield.
+ */
+ public AbstractLocalDateTimeField(String caption) {
+ super(caption, DateTimeResolution.MINUTE);
+ }
+
+ @Override
+ protected LocalDateTimeFieldState getState() {
+ return (LocalDateTimeFieldState) super.getState();
+ }
+
+ @Override
+ protected LocalDateTimeFieldState getState(boolean markAsDirty) {
+ return (LocalDateTimeFieldState) super.getState(markAsDirty);
+ }
+
+}
diff --git a/server/src/main/java/com/vaadin/ui/DateField.java b/server/src/main/java/com/vaadin/ui/DateField.java
index fd241f7504..2ee1c478d9 100644
--- a/server/src/main/java/com/vaadin/ui/DateField.java
+++ b/server/src/main/java/com/vaadin/ui/DateField.java
@@ -17,17 +17,17 @@ package com.vaadin.ui;
import java.time.LocalDate;
-import com.vaadin.shared.ui.datefield.DateFieldState;
+import com.vaadin.shared.ui.datefield.LocalDateFieldState;
/**
* A date entry component, which displays the actual date selector as a popup.
*
- * @see AbstractDateField
+ * @see AbstractLocalDateField
* @see InlineDateField
* @author Vaadin Ltd.
* @since 8.0
*/
-public class DateField extends AbstractDateField {
+public class DateField extends AbstractLocalDateField {
/**
* Constructs an empty <code>DateField</code> with no caption.
@@ -81,13 +81,13 @@ public class DateField extends AbstractDateField {
}
@Override
- protected DateFieldState getState() {
- return (DateFieldState) super.getState();
+ protected LocalDateFieldState getState() {
+ return (LocalDateFieldState) super.getState();
}
@Override
- protected DateFieldState getState(boolean markAsDirty) {
- return (DateFieldState) super.getState(markAsDirty);
+ protected LocalDateFieldState getState(boolean markAsDirty) {
+ return (LocalDateFieldState) super.getState(markAsDirty);
}
/**
diff --git a/server/src/main/java/com/vaadin/ui/InlineDateField.java b/server/src/main/java/com/vaadin/ui/InlineDateField.java
index cf5017bf34..2db9d7f1db 100644
--- a/server/src/main/java/com/vaadin/ui/InlineDateField.java
+++ b/server/src/main/java/com/vaadin/ui/InlineDateField.java
@@ -22,12 +22,12 @@ import com.vaadin.shared.ui.datefield.InlineDateFieldState;
/**
* A date entry component, which displays the actual date selector inline.
*
- * @see AbstractDateField
+ * @see AbstractLocalDateField
* @see DateField
* @author Vaadin Ltd.
* @since 8.0
*/
-public class InlineDateField extends AbstractDateField {
+public class InlineDateField extends AbstractLocalDateField {
/**
* Constructs an empty <code>InlineDateField</code> with no caption.
diff --git a/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java b/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java
index 4c7a2da9a8..42ffe303ef 100644
--- a/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java
+++ b/server/src/main/java/com/vaadin/ui/declarative/DesignAttributeHandler.java
@@ -21,6 +21,7 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -36,6 +37,7 @@ import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
+import com.googlecode.gentyref.GenericTypeReflector;
import com.vaadin.data.Converter;
import com.vaadin.data.ValueContext;
import com.vaadin.shared.ui.AlignmentInfo;
@@ -115,8 +117,9 @@ public class DesignAttributeHandler implements Serializable {
success = false;
} else {
// we have a value from design attributes, let's use that
- Object param = getFormatter().parse(value,
- setter.getParameterTypes()[0]);
+ Type[] types = GenericTypeReflector
+ .getExactParameterTypes(setter, target.getClass());
+ Object param = getFormatter().parse(value, (Class<?>) types[0]);
setter.invoke(target, param);
success = true;
}
@@ -208,7 +211,9 @@ public class DesignAttributeHandler implements Serializable {
Object value = getter.invoke(component);
Object defaultValue = getter.invoke(defaultInstance);
writeAttribute(attribute, attr, value, defaultValue,
- (Class) getter.getReturnType(), context);
+ (Class) GenericTypeReflector.getExactReturnType(getter,
+ component.getClass()),
+ context);
} catch (Exception e) {
getLogger().log(Level.SEVERE,
"Failed to invoke getter for attribute " + attribute,
diff --git a/server/src/test/java/com/vaadin/tests/server/component/abstractdatefield/AbstractDateFieldDeclarativeTest.java b/server/src/test/java/com/vaadin/tests/server/component/abstractdatefield/AbstractLocalDateFieldDeclarativeTest.java
index dcda449615..80040804cd 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/abstractdatefield/AbstractDateFieldDeclarativeTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/abstractdatefield/AbstractLocalDateFieldDeclarativeTest.java
@@ -20,9 +20,9 @@ import java.util.Locale;
import org.junit.Test;
-import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.shared.ui.datefield.DateResolution;
import com.vaadin.tests.server.component.abstractfield.AbstractFieldDeclarativeTest;
-import com.vaadin.ui.AbstractDateField;
+import com.vaadin.ui.AbstractLocalDateField;
/**
* Abstract test class which contains tests for declarative format for
@@ -36,7 +36,7 @@ import com.vaadin.ui.AbstractDateField;
* @author Vaadin Ltd
*
*/
-public abstract class AbstractDateFieldDeclarativeTest<T extends AbstractDateField>
+public abstract class AbstractLocalDateFieldDeclarativeTest<T extends AbstractLocalDateField>
extends AbstractFieldDeclarativeTest<T, LocalDate> {
@Override
@@ -60,7 +60,7 @@ public abstract class AbstractDateFieldDeclarativeTest<T extends AbstractDateFie
LocalDate end = LocalDate.of(2019, 01, 15);
LocalDate start = LocalDate.of(2001, 02, 11);
String dateOutOfRange = "test date out of range";
- Resolution resolution = Resolution.MONTH;
+ DateResolution resolution = DateResolution.MONTH;
String dateFormat = "test format";
boolean lenient = true;
String parseErrorMsg = "test parse error";
diff --git a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldDeclarativeTest.java b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldDeclarativeTest.java
index ea7971b84e..7b55015717 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldDeclarativeTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldDeclarativeTest.java
@@ -17,7 +17,7 @@ package com.vaadin.tests.server.component.datefield;
import org.junit.Test;
-import com.vaadin.tests.server.component.abstractdatefield.AbstractDateFieldDeclarativeTest;
+import com.vaadin.tests.server.component.abstractdatefield.AbstractLocalDateFieldDeclarativeTest;
import com.vaadin.ui.DateField;
/**
@@ -27,7 +27,7 @@ import com.vaadin.ui.DateField;
* @author Vaadin Ltd
*/
public class DateFieldDeclarativeTest
- extends AbstractDateFieldDeclarativeTest<DateField> {
+ extends AbstractLocalDateFieldDeclarativeTest<DateField> {
@Test
public void remainingAttributes()
diff --git a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java
index 990fd9ceba..cab1addf58 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java
@@ -1,7 +1,14 @@
package com.vaadin.tests.server.component.datefield;
+import java.io.Serializable;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
+import java.util.Date;
+import java.util.Map;
+
import org.junit.Test;
+import com.vaadin.data.validator.RangeValidator;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusEvent;
@@ -11,7 +18,37 @@ import com.vaadin.ui.AbstractDateField;
public class DateFieldListenersTest extends AbstractListenerMethodsTestBase {
- public static class TestDateField extends AbstractDateField {
+ public static class TestDateField<T extends Temporal & TemporalAdjuster & Serializable & Comparable<? super T>, R extends Enum<R>>
+ extends AbstractDateField<T, R> {
+
+ public TestDateField() {
+ super(null);
+ }
+
+ @Override
+ protected int getDatePart(T date, R resolution) {
+ return 0;
+ }
+
+ @Override
+ protected T buildDate(Map<R, Integer> resolutionValues) {
+ return null;
+ }
+
+ @Override
+ protected RangeValidator<T> getRangeValidator() {
+ return null;
+ }
+
+ @Override
+ protected T convertFromDate(Date date) {
+ return null;
+ }
+
+ @Override
+ protected Date convertToDate(T date) {
+ return null;
+ }
}
diff --git a/server/src/test/java/com/vaadin/tests/server/component/datefield/InlineDateFieldDeclarativeTest.java b/server/src/test/java/com/vaadin/tests/server/component/datefield/InlineDateFieldDeclarativeTest.java
index 4e056d3c63..116bc43c9c 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/datefield/InlineDateFieldDeclarativeTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/datefield/InlineDateFieldDeclarativeTest.java
@@ -21,7 +21,7 @@ import java.time.LocalDate;
import org.junit.Test;
-import com.vaadin.tests.server.component.abstractdatefield.AbstractDateFieldDeclarativeTest;
+import com.vaadin.tests.server.component.abstractdatefield.AbstractLocalDateFieldDeclarativeTest;
import com.vaadin.ui.AbstractDateField;
import com.vaadin.ui.InlineDateField;
import com.vaadin.ui.declarative.Design;
@@ -34,7 +34,7 @@ import com.vaadin.ui.declarative.Design;
* @author Vaadin Ltd
*/
public class InlineDateFieldDeclarativeTest
- extends AbstractDateFieldDeclarativeTest<InlineDateField> {
+ extends AbstractLocalDateFieldDeclarativeTest<InlineDateField> {
@Test
public void testInlineDateFieldToFromDesign() throws Exception {
diff --git a/server/src/test/java/com/vaadin/tests/server/component/datefield/ResolutionTest.java b/server/src/test/java/com/vaadin/tests/server/component/datefield/ResolutionTest.java
index cb8b6f4914..0db8fbe86f 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/datefield/ResolutionTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/datefield/ResolutionTest.java
@@ -4,39 +4,39 @@ import java.util.ArrayList;
import org.junit.Test;
-import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.shared.ui.datefield.DateResolution;
import com.vaadin.tests.util.TestUtil;
public class ResolutionTest {
@Test
public void testResolutionHigherOrEqualToYear() {
- Iterable<Resolution> higherOrEqual = Resolution
- .getResolutionsHigherOrEqualTo(Resolution.YEAR);
- ArrayList<Resolution> expected = new ArrayList<>();
- expected.add(Resolution.YEAR);
+ Iterable<DateResolution> higherOrEqual = DateResolution
+ .getResolutionsHigherOrEqualTo(DateResolution.YEAR);
+ ArrayList<DateResolution> expected = new ArrayList<>();
+ expected.add(DateResolution.YEAR);
TestUtil.assertIterableEquals(expected, higherOrEqual);
}
@Test
public void testResolutionHigherOrEqualToDay() {
- Iterable<Resolution> higherOrEqual = Resolution
- .getResolutionsHigherOrEqualTo(Resolution.DAY);
- ArrayList<Resolution> expected = new ArrayList<>();
- expected.add(Resolution.DAY);
- expected.add(Resolution.MONTH);
- expected.add(Resolution.YEAR);
+ Iterable<DateResolution> higherOrEqual = DateResolution
+ .getResolutionsHigherOrEqualTo(DateResolution.DAY);
+ ArrayList<DateResolution> expected = new ArrayList<>();
+ expected.add(DateResolution.DAY);
+ expected.add(DateResolution.MONTH);
+ expected.add(DateResolution.YEAR);
TestUtil.assertIterableEquals(expected, higherOrEqual);
}
@Test
public void testResolutionLowerThanYear() {
- Iterable<Resolution> higherOrEqual = Resolution
- .getResolutionsLowerThan(Resolution.YEAR);
- ArrayList<Resolution> expected = new ArrayList<>();
- expected.add(Resolution.MONTH);
- expected.add(Resolution.DAY);
+ Iterable<DateResolution> higherOrEqual = DateResolution
+ .getResolutionsLowerThan(DateResolution.YEAR);
+ ArrayList<DateResolution> expected = new ArrayList<>();
+ expected.add(DateResolution.MONTH);
+ expected.add(DateResolution.DAY);
TestUtil.assertIterableEquals(expected, higherOrEqual);
}
diff --git a/server/src/test/java/com/vaadin/ui/DateFieldTestCase.java b/server/src/test/java/com/vaadin/ui/DateFieldTestCase.java
index 8abb16af6c..e67d7bde13 100644
--- a/server/src/test/java/com/vaadin/ui/DateFieldTestCase.java
+++ b/server/src/test/java/com/vaadin/ui/DateFieldTestCase.java
@@ -12,12 +12,12 @@ import org.junit.Test;
public class DateFieldTestCase {
- private AbstractDateField dateField;
+ private AbstractLocalDateField dateField;
private LocalDate date;
@Before
public void setup() {
- dateField = new AbstractDateField() {
+ dateField = new AbstractLocalDateField() {
};
date = LocalDate.now();
}