You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2018/01/05 09:49:22 UTC
[isis] 01/04: ISIS-1636 UI enhancement - java 8 Time
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-1740-where-am-i
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 18562c46c8ab91cac592db86fe7298dde59d082d
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Oct 6 22:49:37 2017 +0200
ISIS-1636 UI enhancement - java 8 Time
---
.../value/datejdk8local/Jdk8LocalDateUtil.java | 169 +++++++++++++
.../datejdk8local/Jdk8LocalDateValueFacet.java | 33 +++
...ateValueFacetUsingSemanticsProviderFactory.java | 45 ++++
.../Jdk8LocalDateValueSemanticsProvider.java | 274 ++++++++++++++++++++
.../facets/value/datejdk8local/TimeFormatter.java | 27 ++
.../facets/value/datejdk8local/TimeParser.java | 27 ++
.../datetimejdk8local/Jdk8LocalDateTimeUtil.java | 157 ++++++++++++
.../Jdk8LocalDateTimeValueFacet.java | 33 +++
...imeValueFacetUsingSemanticsProviderFactory.java | 45 ++++
.../Jdk8LocalDateTimeValueSemanticsProvider.java | 275 +++++++++++++++++++++
.../value/datetimejdk8local/TimeFormatter.java | 27 ++
.../facets/value/datetimejdk8local/TimeParser.java | 27 ++
.../Jdk8OffsetDateTimeValueFacet.java | 33 +++
...imeValueFacetUsingSemanticsProviderFactory.java | 45 ++++
.../Jdk8OffsetDateTimeValueSemanticsProvider.java | 104 ++++++++
...fsetDateTimeValueSemanticsProviderAbstract.java | 120 +++++++++
.../dflt/ProgrammingModelFacetsJava5.java | 10 +-
.../ComponentFactoryRegistrarDefault.java | 7 +
.../jdk8time/DateConverterForJdk8Abstract.java | 62 +++++
.../jdk8time/DateConverterForJdk8LocalDate.java | 64 +++++
.../DateConverterForJdk8LocalDateTime.java | 76 ++++++
.../DateConverterForJdk8OffsetDateTime.java | 92 +++++++
.../scalars/jdk8time/Jdk8LocalDatePanel.java | 42 ++++
.../jdk8time/Jdk8LocalDatePanelFactory.java | 47 ++++
.../scalars/jdk8time/Jdk8LocalDateTimePanel.java | 52 ++++
.../jdk8time/Jdk8LocalDateTimePanelFactory.java | 45 ++++
.../scalars/jdk8time/Jdk8OffsetDateTimePanel.java | 51 ++++
.../jdk8time/Jdk8OffsetDateTimePanelFactory.java | 45 ++++
.../DateConverterForJdk8LocalDateTest.java | 75 ++++++
.../DateConverterForJdk8LocalDateTimeTest.java | 97 ++++++++
.../DateConverterForJdk8OffsetDateTimeTest.java | 107 ++++++++
31 files changed, 2311 insertions(+), 2 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateUtil.java
new file mode 100644
index 0000000..bff3e30
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateUtil.java
@@ -0,0 +1,169 @@
+/*
+ * 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.core.metamodel.facets.value.datejdk8local;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
+import org.joda.time.format.DateTimeFormat;
+
+final class Jdk8LocalDateUtil {
+
+ private Jdk8LocalDateUtil(){}
+
+ // -- CONVERSION (LEGACY OF JODA TIME LIBRARY)
+
+ static TimeParser parserOfStyle(String style) {
+ return parserOf(DateTimeFormat.forStyle(style));
+ }
+
+ private static TimeParser parserOf(org.joda.time.format.DateTimeFormatter jodaFormatter) {
+ return t->
+ toJava8(jodaFormatter.withLocale(Locale.getDefault()).parseLocalDate(t));
+ }
+
+ private static LocalDate toJava8(org.joda.time.LocalDate x) {
+ return LocalDate.of(x.getYear(), x.getMonthOfYear(), x.getDayOfMonth());
+ }
+
+ static TimeFormatter formatterOfStyle(String style) {
+ return formatterOf(DateTimeFormat.forStyle(style));
+ }
+
+ private static TimeFormatter formatterOf(org.joda.time.format.DateTimeFormatter jodaFormatter) {
+ return t->
+ jodaFormatter.withLocale(Locale.getDefault()).print(toJoda(t));
+ }
+
+ private static org.joda.time.LocalDate toJoda(LocalDate x) {
+ return new org.joda.time.LocalDate(x.getYear(), x.getMonthValue(), x.getDayOfMonth());
+ }
+
+ // -- PARSING AND FORMATING GENERALIZATION
+
+ static TimeFormatter formatterOf(DateTimeFormatter formatter) {
+ return t->
+ formatter.withLocale(Locale.getDefault()).format(t);
+ }
+
+ static TimeParser parserOf(DateTimeFormatter formatter) {
+ return text->
+ LocalDate.parse(text, formatter.withLocale(Locale.getDefault()));
+ }
+
+ // //////////////////////////////////////
+
+ static LocalDate parseDate(
+ final String dateStr,
+ List<TimeParser> parsers) {
+ LocalDate parsedDate = _parseDate(dateStr, parsers);
+ return parsedDate;
+ }
+
+ private static LocalDate _parseDate(String dateStr, Iterable<TimeParser> parsers) {
+ for(TimeParser parser: parsers) {
+ try {
+ return parser.apply(dateStr);
+ } catch (final IllegalArgumentException e) {
+ // continue to next
+ }
+ }
+ throw new TextEntryParseException("Not recognised as a date: " + dateStr);
+ }
+
+ // //////////////////////////////////////
+
+ static LocalDate relativeDate(final LocalDate contextDate, final String str, final boolean add) {
+ LocalDate relativeDate = contextDate;
+ if (str.equals("")) {
+ return contextDate;
+ }
+
+ try {
+ final StringTokenizer st = new StringTokenizer(str.substring(1), " ");
+ while (st.hasMoreTokens()) {
+ final String token = st.nextToken();
+ relativeDate = adjustDate(relativeDate, token, add);
+ }
+ return relativeDate;
+ } catch (final Exception e) {
+ return contextDate;
+ }
+ }
+
+ private static LocalDate adjustDate(final LocalDate contextDate, String str, final boolean add) {
+ int hours = 0;
+ int minutes = 0;
+ int days = 0;
+ int months = 0;
+ int years = 0;
+
+ if (str.endsWith("H")) {
+ str = str.substring(0, str.length() - 1);
+ hours = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("M")) {
+ str = str.substring(0, str.length() - 1);
+ minutes = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("w")) {
+ str = str.substring(0, str.length() - 1);
+ days = 7 * Integer.valueOf(str).intValue();
+ } else if (str.endsWith("y")) {
+ str = str.substring(0, str.length() - 1);
+ years = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("m")) {
+ str = str.substring(0, str.length() - 1);
+ months = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("d")) {
+ str = str.substring(0, str.length() - 1);
+ days = Integer.valueOf(str).intValue();
+ } else {
+ days = Integer.valueOf(str).intValue();
+ }
+
+ if (add) {
+ return add(contextDate, years, months, days, hours, minutes);
+ } else {
+ return add(contextDate, -years, -months, -days, -hours, -minutes);
+ }
+ }
+
+ private static LocalDate add(final LocalDate original, final int years, final int months, final int days, final int hours, final int minutes) {
+ if(hours != 0 || minutes != 0) {
+ throw new IllegalArgumentException("cannot add non-zero hours or minutes to a LocalDate");
+ }
+ return original.plusYears(years).plusMonths(months).plusDays(days);
+ }
+
+
+ // //////////////////////////////////////
+
+ public static String titleString(final TimeFormatter formatter, final LocalDate date) {
+ return date == null ? "" : formatter.apply(date);
+ }
+
+
+
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueFacet.java
new file mode 100644
index 0000000..4deedc3
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueFacet.java
@@ -0,0 +1,33 @@
+/*
+ * 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.core.metamodel.facets.value.datejdk8local;
+
+import java.time.LocalDate;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+
+public interface Jdk8LocalDateValueFacet extends Facet {
+
+ LocalDate dateValue(ObjectAdapter object);
+
+ ObjectAdapter createValue(LocalDate date);
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueFacetUsingSemanticsProviderFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueFacetUsingSemanticsProviderFactory.java
new file mode 100644
index 0000000..65aa714
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueFacetUsingSemanticsProviderFactory.java
@@ -0,0 +1,45 @@
+/*
+ * 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.core.metamodel.facets.value.datejdk8local;
+
+import java.time.LocalDate;
+
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.value.vsp.ValueFacetUsingSemanticsProviderFactory;
+
+public class Jdk8LocalDateValueFacetUsingSemanticsProviderFactory extends ValueFacetUsingSemanticsProviderFactory<LocalDate> {
+
+ public Jdk8LocalDateValueFacetUsingSemanticsProviderFactory() {
+ // as per inherited DateTimeValueSemanticsProvider#facetType
+ super();
+ }
+
+ @Override
+ public void process(final ProcessClassContext processClassContext) {
+ final Class<?> type = processClassContext.getCls();
+ final FacetHolder holder = processClassContext.getFacetHolder();
+
+ if (type != LocalDate.class) {
+ return;
+ }
+ addFacets(new Jdk8LocalDateValueSemanticsProvider(holder, getContext()));
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueSemanticsProvider.java
new file mode 100644
index 0000000..a1e1e21
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/Jdk8LocalDateValueSemanticsProvider.java
@@ -0,0 +1,274 @@
+/*
+ * 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.core.metamodel.facets.value.datejdk8local;
+
+import static org.apache.isis.core.metamodel.facets.value.datejdk8local.Jdk8LocalDateUtil.formatterOf;
+import static org.apache.isis.core.metamodel.facets.value.datejdk8local.Jdk8LocalDateUtil.formatterOfStyle;
+import static org.apache.isis.core.metamodel.facets.value.datejdk8local.Jdk8LocalDateUtil.parserOf;
+import static org.apache.isis.core.metamodel.facets.value.datejdk8local.Jdk8LocalDateUtil.parserOfStyle;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.isis.applib.adapters.EncoderDecoder;
+import org.apache.isis.applib.adapters.EncodingException;
+import org.apache.isis.core.commons.config.ConfigurationConstants;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.value.vsp.ValueSemanticsProviderAndFacetAbstract;
+import org.apache.isis.core.metamodel.facets.value.datejodalocal.JodaLocalDateValueFacet;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public class Jdk8LocalDateValueSemanticsProvider extends ValueSemanticsProviderAndFacetAbstract<LocalDate> implements Jdk8LocalDateValueFacet {
+
+ public static final int MAX_LENGTH = 12;
+ public static final int TYPICAL_LENGTH = MAX_LENGTH;
+
+ /**
+ * Introduced to allow BDD tests to provide a different format string "mid-flight".
+ *
+ * <p>
+ * REVIEW: This seems only to have any effect if 'propertyType' is set to 'date'.
+ *
+ * @see #setTitlePatternOverride(String)
+ * @deprecated - because 'propertyType' parameter is never used
+ */
+ @Deprecated
+ public static void setFormat(final String propertyType, final String pattern) {
+ setTitlePatternOverride(pattern);
+ }
+ /**
+ * A replacement for {@link #setFormat(String, String)}.
+ */
+ public static void setTitlePatternOverride(final String pattern) {
+ OVERRIDE_TITLE_PATTERN.set(pattern);
+ }
+
+ /**
+ * Key to indicate how LocalDate should be parsed/rendered.
+ *
+ * <p>
+ * eg:
+ * <pre>
+ * isis.value.format.date=iso
+ * </pre>
+ *
+ * <p>
+ * A pre-determined list of values is available, specifically 'iso_encoding', 'iso' and 'medium' (see
+ * {@link #NAMED_TITLE_FORMATTERS}). Alternatively, can also specify a mask, eg <tt>dd-MMM-yyyy</tt>.
+ *
+ * @see #NAMED_TITLE_FORMATTERS
+ */
+ public final static String CFG_FORMAT_KEY = ConfigurationConstants.ROOT + "value.format.date";
+
+
+ /**
+ * Keys represent the values which can be configured, and which are used for the rendering of dates.
+ *
+ */
+ private static Map<String, TimeFormatter> NAMED_TITLE_FORMATTERS = Maps.newHashMap();
+ static {
+ NAMED_TITLE_FORMATTERS.put("iso_encoding", formatterOf(DateTimeFormatter.ofPattern("yyyyMMdd")));
+ NAMED_TITLE_FORMATTERS.put("iso", formatterOf(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+ NAMED_TITLE_FORMATTERS.put("long", formatterOfStyle("L-"));
+ NAMED_TITLE_FORMATTERS.put("medium", formatterOfStyle("M-"));
+ NAMED_TITLE_FORMATTERS.put("short", formatterOfStyle("S-"));
+ }
+
+ private final static ThreadLocal<String> OVERRIDE_TITLE_PATTERN = new ThreadLocal<String>() {
+ @Override
+ protected String initialValue() {
+ return null;
+ }
+ };
+
+
+ private final static List<TimeParser> PARSE_FORMATTERS = Lists.newArrayList();
+ static {
+ PARSE_FORMATTERS.add(parserOfStyle("L-"));
+ PARSE_FORMATTERS.add(parserOfStyle("M-"));
+ PARSE_FORMATTERS.add(parserOfStyle("S-"));
+ PARSE_FORMATTERS.add(parserOf(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+ PARSE_FORMATTERS.add(parserOf(DateTimeFormatter.ofPattern("yyyyMMdd")));
+ }
+
+ public static Class<? extends Facet> type() {
+ return JodaLocalDateValueFacet.class;
+ }
+
+
+ // no default
+ private static final LocalDate DEFAULT_VALUE = null;
+
+
+ private final DateTimeFormatter encodingFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+ private TimeFormatter titleStringFormatter;
+ private String titleStringFormatNameOrPattern;
+
+
+ // //////////////////////////////////////
+ // constructor
+ // //////////////////////////////////////
+
+ /**
+ * Required because implementation of {@link TimeParser} and
+ * {@link EncoderDecoder}.
+ */
+ public Jdk8LocalDateValueSemanticsProvider() {
+ this(null, null);
+ }
+
+ /**
+ * Uses {@link #type()} as the facet type.
+ */
+ public Jdk8LocalDateValueSemanticsProvider(final FacetHolder holder, final ServicesInjector context) {
+ super(type(), holder, LocalDate.class, TYPICAL_LENGTH, MAX_LENGTH, Immutability.IMMUTABLE, EqualByContent.HONOURED, DEFAULT_VALUE, context);
+
+ String configuredNameOrPattern = getConfiguration().getString(CFG_FORMAT_KEY, "medium").trim();
+ updateTitleStringFormatter(configuredNameOrPattern);
+ }
+
+
+ private void updateTitleStringFormatter(String titleStringFormatNameOrPattern) {
+ titleStringFormatter = NAMED_TITLE_FORMATTERS.get(titleStringFormatNameOrPattern);
+ if (titleStringFormatter == null) {
+ titleStringFormatter = formatterOf(DateTimeFormatter.ofPattern(titleStringFormatNameOrPattern));
+ }
+ this.titleStringFormatNameOrPattern = titleStringFormatNameOrPattern;
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // Parsing
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ protected LocalDate doParse(
+ final String entry,
+ final Object context) {
+
+ updateTitleStringFormatterIfOverridden();
+
+ LocalDate contextDate = (LocalDate) context;
+
+ final String dateString = entry.trim().toUpperCase();
+ if (dateString.startsWith("+") && contextDate != null) {
+ return Jdk8LocalDateUtil.relativeDate(contextDate, dateString, true);
+ } else if (dateString.startsWith("-") && contextDate != null) {
+ return Jdk8LocalDateUtil.relativeDate(contextDate, dateString, false);
+ } else {
+ return parseDate(dateString, contextDate);
+ }
+ }
+
+ private void updateTitleStringFormatterIfOverridden() {
+ final String overridePattern = OVERRIDE_TITLE_PATTERN.get();
+ if (overridePattern == null ||
+ titleStringFormatNameOrPattern.equals(overridePattern)) {
+ return;
+ }
+
+ // (re)create format
+ updateTitleStringFormatter(overridePattern);
+ }
+
+ private LocalDate parseDate(final String dateStr, final Object original) {
+ return Jdk8LocalDateUtil.parseDate(dateStr, PARSE_FORMATTERS);
+ }
+
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // TitleProvider
+ // ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String titleString(final Object value) {
+ if (value == null) {
+ return null;
+ }
+ final LocalDate date = (LocalDate) value;
+ //DateTimeFormatter f = titleStringFormatter.withLocale(Locale.getDefault());
+ return Jdk8LocalDateUtil.titleString(titleStringFormatter, date);
+ }
+
+ @Override
+ public String titleStringWithMask(final Object value, final String usingMask) {
+ final LocalDate date = (LocalDate) value;
+ return Jdk8LocalDateUtil.titleString(formatterOf(DateTimeFormatter.ofPattern(usingMask)), date);
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // EncoderDecoder
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ protected String doEncode(final Object object) {
+ final LocalDate date = (LocalDate) object;
+ return encode(date);
+ }
+
+ private synchronized String encode(final LocalDate date) {
+ return encodingFormatter.format(date);
+ }
+
+ @Override
+ protected LocalDate doRestore(final String data) {
+ try {
+ return parse(data);
+ } catch (final IllegalArgumentException e) {
+ throw new EncodingException(e);
+ }
+ }
+
+ private synchronized LocalDate parse(final String data) {
+ return LocalDate.parse(data, encodingFormatter);
+ }
+
+ // //////////////////////////////////////////////////////////////////
+ // Jdk8LocalDateValueFacet
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ public final LocalDate dateValue(final ObjectAdapter object) {
+ return (LocalDate) (object == null ? null : object.getObject());
+ }
+
+ @Override
+ public final ObjectAdapter createValue(final LocalDate date) {
+ return getAdapterManager().adapterFor(date);
+ }
+
+
+ // //////////////////////////////////////
+
+ @Override
+ public String toString() {
+ return "Jdk8LocalDateValueSemanticsProvider: " + titleStringFormatter;
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/TimeFormatter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/TimeFormatter.java
new file mode 100644
index 0000000..0769108
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/TimeFormatter.java
@@ -0,0 +1,27 @@
+/*
+ * 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.core.metamodel.facets.value.datejdk8local;
+
+import java.time.LocalDate;
+import java.util.function.Function;
+
+interface TimeFormatter extends Function<LocalDate, String> {
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/TimeParser.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/TimeParser.java
new file mode 100644
index 0000000..b8d945a
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datejdk8local/TimeParser.java
@@ -0,0 +1,27 @@
+/*
+ * 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.core.metamodel.facets.value.datejdk8local;
+
+import java.time.LocalDate;
+import java.util.function.Function;
+
+interface TimeParser extends Function<String, LocalDate> {
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeUtil.java
new file mode 100644
index 0000000..951440c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeUtil.java
@@ -0,0 +1,157 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8local;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
+
+final class Jdk8LocalDateTimeUtil {
+
+ private Jdk8LocalDateTimeUtil(){}
+
+ // -- CONVERSION (LEGACY OF JODA TIME LIBRARY)
+
+ private final static ZoneId zId = ZoneId.systemDefault();
+
+ static TimeParser parserOf(org.joda.time.format.DateTimeFormatter jodaFormatter) {
+ return t->
+ toJava8(jodaFormatter.withLocale(Locale.getDefault()).parseLocalDateTime(t));
+ }
+
+ private static LocalDateTime toJava8(org.joda.time.LocalDateTime x){
+ if(x==null)
+ return null;
+ return toLocalDateTime(x.toDate().getTime());
+ }
+
+ private static LocalDateTime toLocalDateTime(long epochMilli) {
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli),zId);
+ }
+
+ static TimeFormatter formatterOf(org.joda.time.format.DateTimeFormatter jodaFormatter) {
+ return t->
+ jodaFormatter.withLocale(Locale.getDefault()).print(toJoda(t));
+
+ }
+
+ private static org.joda.time.LocalDateTime toJoda(LocalDateTime x){
+ if(x==null)
+ return null;
+ return org.joda.time.LocalDateTime.fromDateFields(new Date(toEpochMilli(x)));
+ }
+
+ private static long toEpochMilli(LocalDateTime localDateTime){
+ return localDateTime.atZone(zId).toInstant().toEpochMilli();
+ }
+
+ // //////////////////////////////////////
+
+ static LocalDateTime parseDate(
+ final String dateStr,
+ List<TimeParser> parseFormatters) {
+ return parseDateTime(dateStr, parseFormatters);
+ }
+
+ private static LocalDateTime parseDateTime(String dateStr, Iterable<TimeParser> parsers) {
+ for(TimeParser parser: parsers) {
+ try {
+ return parser.apply(dateStr);
+ } catch (final IllegalArgumentException e) {
+ // continue to next
+ }
+ }
+ throw new TextEntryParseException("Not recognised as a date: " + dateStr);
+ }
+
+ // //////////////////////////////////////
+
+
+ static LocalDateTime relativeDateTime(final LocalDateTime contextDate, final String str, final boolean add) {
+ LocalDateTime relativeDate = contextDate;
+ if (str.equals("")) {
+ return contextDate;
+ }
+
+ try {
+ final StringTokenizer st = new StringTokenizer(str.substring(1), " ");
+ while (st.hasMoreTokens()) {
+ final String token = st.nextToken();
+ relativeDate = adjustDateTime(relativeDate, token, add);
+ }
+ return relativeDate;
+ } catch (final Exception e) {
+ return contextDate;
+ }
+ }
+
+ private static LocalDateTime adjustDateTime(final LocalDateTime contextDateTime, String str, final boolean add) {
+ int hours = 0;
+ int minutes = 0;
+ int days = 0;
+ int months = 0;
+ int years = 0;
+
+ if (str.endsWith("H")) {
+ str = str.substring(0, str.length() - 1);
+ hours = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("M")) {
+ str = str.substring(0, str.length() - 1);
+ minutes = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("w")) {
+ str = str.substring(0, str.length() - 1);
+ days = 7 * Integer.valueOf(str).intValue();
+ } else if (str.endsWith("y")) {
+ str = str.substring(0, str.length() - 1);
+ years = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("m")) {
+ str = str.substring(0, str.length() - 1);
+ months = Integer.valueOf(str).intValue();
+ } else if (str.endsWith("d")) {
+ str = str.substring(0, str.length() - 1);
+ days = Integer.valueOf(str).intValue();
+ } else {
+ days = Integer.valueOf(str).intValue();
+ }
+
+ if (add) {
+ return add(contextDateTime, years, months, days, hours, minutes);
+ } else {
+ return add(contextDateTime, -years, -months, -days, -hours, -minutes);
+ }
+ }
+
+ private static LocalDateTime add(final LocalDateTime original, final int years, final int months, final int days, final int hours, final int minutes) {
+ return original.plusYears(years).plusMonths(months).plusDays(days).plusHours(hours).plusMinutes(minutes);
+ }
+
+ // //////////////////////////////////////
+
+ static String titleString(TimeFormatter titleFormatter, LocalDateTime dateTime) {
+ return dateTime == null ? "" : titleFormatter.apply(dateTime);
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueFacet.java
new file mode 100644
index 0000000..4276129
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueFacet.java
@@ -0,0 +1,33 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8local;
+
+import java.time.LocalDateTime;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+
+public interface Jdk8LocalDateTimeValueFacet extends Facet {
+
+ LocalDateTime dateValue(ObjectAdapter object);
+
+ ObjectAdapter createValue(LocalDateTime date);
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory.java
new file mode 100644
index 0000000..4f17b73
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory.java
@@ -0,0 +1,45 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8local;
+
+import java.time.LocalDateTime;
+
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.value.vsp.ValueFacetUsingSemanticsProviderFactory;
+
+public class Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory extends ValueFacetUsingSemanticsProviderFactory<LocalDateTime> {
+
+ public Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory() {
+ // as per inherited DateTimeValueSemanticsProvider#facetType
+ super();
+ }
+
+ @Override
+ public void process(final ProcessClassContext processClassContext) {
+ final Class<?> type = processClassContext.getCls();
+ final FacetHolder holder = processClassContext.getFacetHolder();
+
+ if (type != LocalDateTime.class) {
+ return;
+ }
+ addFacets(new Jdk8LocalDateTimeValueSemanticsProvider(holder, getContext()));
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueSemanticsProvider.java
new file mode 100644
index 0000000..fd04f37
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/Jdk8LocalDateTimeValueSemanticsProvider.java
@@ -0,0 +1,275 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8local;
+
+import static org.apache.isis.core.metamodel.facets.value.datetimejdk8local.Jdk8LocalDateTimeUtil.formatterOf;
+import static org.apache.isis.core.metamodel.facets.value.datetimejdk8local.Jdk8LocalDateTimeUtil.parserOf;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.isis.applib.adapters.EncoderDecoder;
+import org.apache.isis.applib.adapters.EncodingException;
+import org.apache.isis.core.commons.config.ConfigurationConstants;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.value.vsp.ValueSemanticsProviderAndFacetAbstract;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.ISODateTimeFormat;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+
+public class Jdk8LocalDateTimeValueSemanticsProvider extends ValueSemanticsProviderAndFacetAbstract<LocalDateTime> implements Jdk8LocalDateTimeValueFacet {
+
+ public static final int MAX_LENGTH = 36;
+ public static final int TYPICAL_LENGTH = 22;
+
+ /**
+ * Introduced to allow BDD tests to provide a different format string "mid-flight".
+ *
+ * <p>
+ * REVIEW: This seems only to have any effect if 'propertyType' is set to 'date'.
+ *
+ * @see #setTitlePatternOverride(String)
+ * @deprecated - because 'propertyType' parameter is never used
+ */
+ @Deprecated
+ public static void setFormat(final String propertyType, final String pattern) {
+ setTitlePatternOverride(pattern);
+ }
+ /**
+ * A replacement for {@link #setFormat(String, String)}.
+ */
+ public static void setTitlePatternOverride(final String pattern) {
+ OVERRIDE_TITLE_PATTERN.set(pattern);
+ }
+
+ /**
+ * Key to indicate how LocalDateTime should be parsed/rendered.
+ *
+ * <p>
+ * eg:
+ * <pre>
+ * isis.value.format.datetime=iso
+ * </pre>
+ *
+ * <p>
+ * A pre-determined list of values is available, specifically 'iso_encoding', 'iso' and 'medium' (see
+ * {@link #NAMED_TITLE_FORMATTERS}). Alternatively, can also specify a mask, eg <tt>dd-MMM-yyyy</tt>.
+ *
+ * @see #NAMED_TITLE_FORMATTERS
+ */
+ public final static String CFG_FORMAT_KEY = ConfigurationConstants.ROOT + "value.format.datetime";
+
+
+ /**
+ * Keys represent the values which can be configured, and which are used for the rendering of dates.
+ *
+ */
+ private static Map<String, TimeFormatter> NAMED_TITLE_FORMATTERS = Maps.newHashMap();
+ static {
+ NAMED_TITLE_FORMATTERS.put("iso_encoding", formatterOf(ISODateTimeFormat.basicDateTime()));
+ NAMED_TITLE_FORMATTERS.put("iso", formatterOf(ISODateTimeFormat.basicDateTimeNoMillis()));
+ NAMED_TITLE_FORMATTERS.put("long", formatterOf(DateTimeFormat.forStyle("LL")));
+ NAMED_TITLE_FORMATTERS.put("medium", formatterOf(DateTimeFormat.forStyle("MM")));
+ NAMED_TITLE_FORMATTERS.put("short", formatterOf(DateTimeFormat.forStyle("SS")));
+ }
+
+ private final static ThreadLocal<String> OVERRIDE_TITLE_PATTERN = new ThreadLocal<String>() {
+ @Override
+ protected String initialValue() {
+ return null;
+ }
+ };
+
+
+ private final static List<TimeParser> PARSE_FORMATTERS = Lists.newArrayList();
+ static {
+ PARSE_FORMATTERS.add(parserOf(DateTimeFormat.forStyle("LL")));
+ PARSE_FORMATTERS.add(parserOf(DateTimeFormat.forStyle("MM")));
+ PARSE_FORMATTERS.add(parserOf(DateTimeFormat.forStyle("SS")));
+ PARSE_FORMATTERS.add(parserOf(ISODateTimeFormat.basicDateTimeNoMillis()));
+ PARSE_FORMATTERS.add(parserOf(ISODateTimeFormat.basicDateTime()));
+ }
+
+ public static Class<? extends Facet> type() {
+ return Jdk8LocalDateTimeValueFacet.class;
+ }
+
+ // no default
+ private static final LocalDateTime DEFAULT_VALUE = null;
+
+ private final TimeParser encodingParser = Jdk8LocalDateTimeUtil.parserOf(ISODateTimeFormat.dateHourMinuteSecondMillis());
+ private final TimeFormatter encodingFormatter = Jdk8LocalDateTimeUtil.formatterOf(ISODateTimeFormat.dateHourMinuteSecondMillis());
+
+ private TimeFormatter titleStringFormatter;
+ private String titleStringFormatNameOrPattern;
+
+
+ // //////////////////////////////////////
+ // constructor
+ // //////////////////////////////////////
+
+ /**
+ * Required because implementation of {@link TimeParser} and
+ * {@link EncoderDecoder}.
+ */
+ public Jdk8LocalDateTimeValueSemanticsProvider() {
+ this(null, null);
+ }
+
+ /**
+ * Uses {@link #type()} as the facet type.
+ */
+ public Jdk8LocalDateTimeValueSemanticsProvider(final FacetHolder holder, final ServicesInjector context) {
+ super(type(), holder, LocalDateTime.class, TYPICAL_LENGTH, MAX_LENGTH, Immutability.IMMUTABLE, EqualByContent.HONOURED, DEFAULT_VALUE, context);
+
+ String configuredNameOrPattern = getConfiguration().getString(CFG_FORMAT_KEY, "medium").toLowerCase().trim();
+ updateTitleStringFormatter(configuredNameOrPattern);
+ }
+
+
+ private void updateTitleStringFormatter(String titleStringFormatNameOrPattern) {
+ titleStringFormatter = NAMED_TITLE_FORMATTERS.get(titleStringFormatNameOrPattern);
+ if (titleStringFormatter == null) {
+ titleStringFormatter =
+ DateTimeFormatter.ofPattern(titleStringFormatNameOrPattern)::format;
+ }
+ this.titleStringFormatNameOrPattern = titleStringFormatNameOrPattern;
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // Parsing
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ protected LocalDateTime doParse(
+ final String entry,
+ final Object context) {
+
+ updateTitleStringFormatterIfOverridden();
+
+ LocalDateTime contextDateTime = (LocalDateTime) context;
+
+ final String dateString = entry.trim().toUpperCase();
+ if (dateString.startsWith("+") && contextDateTime != null) {
+ return Jdk8LocalDateTimeUtil.relativeDateTime(contextDateTime, dateString, true);
+ } else if (dateString.startsWith("-") && contextDateTime != null) {
+ return Jdk8LocalDateTimeUtil.relativeDateTime(contextDateTime, dateString, false);
+ } else {
+ return parseDateTime(dateString, contextDateTime);
+ }
+ }
+
+ private void updateTitleStringFormatterIfOverridden() {
+ final String overridePattern = OVERRIDE_TITLE_PATTERN.get();
+ if (overridePattern == null ||
+ titleStringFormatNameOrPattern.equals(overridePattern)) {
+ return;
+ }
+
+ // (re)create format
+ updateTitleStringFormatter(overridePattern);
+ }
+
+ private LocalDateTime parseDateTime(final String dateStr, final Object original) {
+ return Jdk8LocalDateTimeUtil.parseDate(dateStr, PARSE_FORMATTERS);
+ }
+
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // TitleProvider
+ // ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String titleString(final Object value) {
+ if (value == null) {
+ return null;
+ }
+ final LocalDateTime dateTime = (LocalDateTime) value;
+ return Jdk8LocalDateTimeUtil.titleString(titleStringFormatter, dateTime);
+ }
+
+ @Override
+ public String titleStringWithMask(final Object value, final String usingMask) {
+ final LocalDateTime dateTime = (LocalDateTime) value;
+ return Jdk8LocalDateTimeUtil.titleString(
+ DateTimeFormatter.ofPattern(usingMask)::format,
+ dateTime);
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // EncoderDecoder
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ protected String doEncode(final Object object) {
+ final LocalDateTime date = (LocalDateTime) object;
+ return encode(date);
+ }
+
+ private synchronized String encode(final LocalDateTime date) {
+ return encodingFormatter.apply(date);
+ }
+
+ @Override
+ protected LocalDateTime doRestore(final String data) {
+ try {
+ return parse(data);
+ } catch (final IllegalArgumentException e) {
+ throw new EncodingException(e);
+ }
+ }
+
+ private synchronized LocalDateTime parse(final String data) {
+ return encodingParser.apply(data);
+ }
+
+ // //////////////////////////////////////////////////////////////////
+ // Jdk8LocalDateValueFacet
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ public final LocalDateTime dateValue(final ObjectAdapter object) {
+ return (LocalDateTime) (object == null ? null : object.getObject());
+ }
+
+ @Override
+ public final ObjectAdapter createValue(final LocalDateTime date) {
+ return getAdapterManager().adapterFor(date);
+ }
+
+
+ // //////////////////////////////////////
+
+ @Override
+ public String toString() {
+ return "Jdk8LocalDateTimeValueSemanticsProvider: " + titleStringFormatter;
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/TimeFormatter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/TimeFormatter.java
new file mode 100644
index 0000000..4911dfc
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/TimeFormatter.java
@@ -0,0 +1,27 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8local;
+
+import java.time.LocalDateTime;
+import java.util.function.Function;
+
+interface TimeFormatter extends Function<LocalDateTime, String> {
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/TimeParser.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/TimeParser.java
new file mode 100644
index 0000000..2417cfd
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8local/TimeParser.java
@@ -0,0 +1,27 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8local;
+
+import java.time.LocalDateTime;
+import java.util.function.Function;
+
+interface TimeParser extends Function<String, LocalDateTime> {
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueFacet.java
new file mode 100644
index 0000000..27e1cde
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueFacet.java
@@ -0,0 +1,33 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8offset;
+
+import java.time.OffsetDateTime;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+
+public interface Jdk8OffsetDateTimeValueFacet extends Facet {
+
+ OffsetDateTime dateValue(ObjectAdapter object);
+
+ ObjectAdapter createValue(OffsetDateTime date);
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory.java
new file mode 100644
index 0000000..7916dfd
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory.java
@@ -0,0 +1,45 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8offset;
+
+import java.time.OffsetDateTime;
+
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.value.vsp.ValueFacetUsingSemanticsProviderFactory;
+
+public class Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory extends ValueFacetUsingSemanticsProviderFactory<OffsetDateTime> {
+
+ public Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory() {
+ // as per inherited DateTimeValueSemanticsProvider#facetType
+ super();
+ }
+
+ @Override
+ public void process(final ProcessClassContext processClassContext) {
+ final Class<?> type = processClassContext.getCls();
+ final FacetHolder holder = processClassContext.getFacetHolder();
+
+ if (type != OffsetDateTime.class) {
+ return;
+ }
+ addFacets(new Jdk8OffsetDateTimeValueSemanticsProvider(holder, getContext()));
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueSemanticsProvider.java
new file mode 100644
index 0000000..2952aed
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueSemanticsProvider.java
@@ -0,0 +1,104 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8offset;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+import org.apache.isis.applib.adapters.EncoderDecoder;
+import org.apache.isis.applib.adapters.EncodingException;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.value.datetimejoda.JodaDateTimeValueSemanticsProviderAbstract;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+
+public class Jdk8OffsetDateTimeValueSemanticsProvider extends JodaDateTimeValueSemanticsProviderAbstract<OffsetDateTime> {
+
+ // no default
+ private static final OffsetDateTime DEFAULT_VALUE = null;
+
+
+ /**
+ * Required because implementation of {@link TimeParser} and
+ * {@link EncoderDecoder}.
+ */
+ public Jdk8OffsetDateTimeValueSemanticsProvider() {
+ this(null, null);
+ }
+
+ public Jdk8OffsetDateTimeValueSemanticsProvider(final FacetHolder holder, final ServicesInjector context) {
+ super(holder, OffsetDateTime.class, DEFAULT_VALUE, context);
+ }
+
+ @Override
+ protected OffsetDateTime add(final OffsetDateTime original, final int years, final int months, final int days, final int hours, final int minutes) {
+ if(hours != 0 || minutes != 0) {
+ throw new IllegalArgumentException("cannot add non-zero hours or minutes to a DateTime");
+ }
+ return original.plusYears(years).plusMonths(months).plusDays(days);
+ }
+
+ @Override
+ protected OffsetDateTime now() {
+ return OffsetDateTime.now();
+ }
+
+ @Override
+ protected Date dateValue(final Object value) {
+ long epochMilli = ((OffsetDateTime) value).toInstant().toEpochMilli();
+ return new Date(epochMilli);
+ }
+
+ @Override
+ protected OffsetDateTime setDate(final Date date) {
+ return OffsetDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);
+ }
+
+ // //////////////////////////////////////////////////////////////////
+ // EncoderDecoder
+ // //////////////////////////////////////////////////////////////////
+
+ private final DateTimeFormatter encodingFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSZ");
+
+ @Override
+ protected String doEncode(final Object object) {
+ final OffsetDateTime date = (OffsetDateTime) object;
+ return encode(date);
+ }
+
+ private synchronized String encode(final OffsetDateTime date) {
+ return encodingFormatter.format(date);
+ }
+
+ @Override
+ protected OffsetDateTime doRestore(final String data) {
+ try {
+ return parse(data);
+ } catch (final IllegalArgumentException e) {
+ throw new EncodingException(e);
+ }
+ }
+
+ private synchronized OffsetDateTime parse(final String data) {
+ return OffsetDateTime.parse(data, encodingFormatter);
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueSemanticsProviderAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueSemanticsProviderAbstract.java
new file mode 100644
index 0000000..e532bcb
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datetimejdk8offset/Jdk8OffsetDateTimeValueSemanticsProviderAbstract.java
@@ -0,0 +1,120 @@
+/*
+ * 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.core.metamodel.facets.value.datetimejdk8offset;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+import org.apache.isis.core.commons.config.ConfigurationConstants;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.value.ValueSemanticsProviderAbstractTemporal;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+
+public abstract class Jdk8OffsetDateTimeValueSemanticsProviderAbstract<T> extends ValueSemanticsProviderAbstractTemporal<T> {
+
+ private static final Map<String, DateFormat> FORMATS = Maps.newHashMap();
+
+ static {
+ FORMATS.put(ISO_ENCODING_FORMAT, createDateEncodingFormat("yyyyMMdd"));
+ FORMATS.put("iso", createDateFormat("yyyy-MM-dd"));
+ FORMATS.put("medium", DateFormat.getDateInstance(DateFormat.MEDIUM));
+ }
+
+ public Jdk8OffsetDateTimeValueSemanticsProviderAbstract(final FacetHolder holder, final Class<T> adaptedClass, final T defaultValue, final ServicesInjector context) {
+ super("date", holder, adaptedClass, 12, Immutability.IMMUTABLE, EqualByContent.HONOURED, defaultValue, context);
+
+ final String formatRequired = getConfiguration().getString(ConfigurationConstants.ROOT + "value.format.date");
+ if (formatRequired == null) {
+ format = formats().get(defaultFormat());
+ } else {
+ setMask(formatRequired);
+ }
+ }
+
+
+ // //////////////////////////////////////////////////////////////////
+ // temporal-specific stuff
+ // //////////////////////////////////////////////////////////////////
+
+ @Override
+ protected void clearFields(final Calendar cal) {
+ cal.set(Calendar.HOUR, 0);
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.AM_PM, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ }
+
+ @Override
+ protected String defaultFormat() {
+ return "medium";
+ }
+
+ @Override
+ protected boolean ignoreTimeZone() {
+ return true;
+ }
+
+ @Override
+ protected Map<String, DateFormat> formats() {
+ return FORMATS;
+ }
+
+ @Override
+ public String toString() {
+ return "DateValueSemanticsProvider: " + format;
+ }
+
+ @Override
+ protected DateFormat format() {
+ final Locale locale = Locale.getDefault();
+
+ final DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
+ dateFormat.setTimeZone(UTC_TIME_ZONE);
+ return dateFormat;
+ }
+
+ protected List<DateFormat> formatsToTry() {
+
+ final Locale locale = Locale.getDefault();
+
+ List<DateFormat> formats = new ArrayList<>();
+
+ formats.add(DateFormat.getDateInstance(DateFormat.LONG, locale));
+ formats.add(DateFormat.getDateInstance(DateFormat.MEDIUM, locale));
+ formats.add(DateFormat.getDateInstance(DateFormat.SHORT, locale));
+ formats.add(createDateFormat("yyyy-MM-dd"));
+ formats.add(createDateFormat("yyyyMMdd"));
+
+ for (DateFormat format : formats) {
+ format.setTimeZone(UTC_TIME_ZONE);
+ }
+
+ return formats;
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index 4ac5d5e..b786d42 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -130,9 +130,12 @@ import org.apache.isis.core.metamodel.facets.value.chars.CharWrapperValueFacetUs
import org.apache.isis.core.metamodel.facets.value.clobs.ClobValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.color.ColorValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.date.DateValueFacetUsingSemanticsProviderFactory;
+import org.apache.isis.core.metamodel.facets.value.datejdk8local.Jdk8LocalDateValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.datejodalocal.JodaLocalDateValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.datesql.JavaSqlDateValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.datetime.DateTimeValueFacetUsingSemanticsProviderFactory;
+import org.apache.isis.core.metamodel.facets.value.datetimejdk8local.Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory;
+import org.apache.isis.core.metamodel.facets.value.datetimejdk8offset.Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.datetimejoda.JodaDateTimeValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.datetimejodalocal.JodaLocalDateTimeValueFacetUsingSemanticsProviderFactory;
import org.apache.isis.core.metamodel.facets.value.dateutil.JavaUtilDateValueFacetUsingSemanticsProviderFactory;
@@ -275,7 +278,6 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
addFactory(new NotInServiceMenuFacetDerivedFromDomainServiceFacetFactory());
-
// must come after CssClassFacetOnMemberFactory
addFactory(new CssClassFacetOnActionFromConfiguredRegexFactory());
@@ -292,7 +294,6 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
addFactory(new MixinFacetForMixinAnnotationFactory());
-
// must come after RecreatableObjectFacetFactory
addFactory(new DomainObjectAnnotationFacetFactory());
@@ -387,6 +388,11 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
addFactory(new JodaLocalDateTimeValueFacetUsingSemanticsProviderFactory());
addFactory(new JodaDateTimeValueFacetUsingSemanticsProviderFactory());
+ // java 8 time values
+ addFactory(new Jdk8LocalDateValueFacetUsingSemanticsProviderFactory());
+ addFactory(new Jdk8OffsetDateTimeValueFacetUsingSemanticsProviderFactory());
+ addFactory(new Jdk8LocalDateTimeValueFacetUsingSemanticsProviderFactory());
+
// written to not trample over TypeOf if already installed
addFactory(new CollectionFacetFactory());
// must come after CollectionFacetFactory
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index ec9e27d..a350367 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@ -46,6 +46,9 @@ import org.apache.isis.viewer.wicket.ui.components.header.HeaderPanelFactory;
import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditFormPanelFactory;
import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditPanelFactory;
import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.*;
+import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.Jdk8LocalDatePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.Jdk8LocalDateTimePanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.Jdk8OffsetDateTimePanelFactory;
import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlDatePanelFactory;
import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlTimePanelFactory;
import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlTimestampPanelFactory;
@@ -217,6 +220,10 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
componentFactories.add(new JodaLocalDatePanelFactory());
componentFactories.add(new JodaLocalDateTimePanelFactory());
componentFactories.add(new JodaDateTimePanelFactory());
+
+ componentFactories.add(new Jdk8OffsetDateTimePanelFactory());
+ componentFactories.add(new Jdk8LocalDatePanelFactory());
+ componentFactories.add(new Jdk8LocalDateTimePanelFactory());
componentFactories.add(new ValuePanelFactory());
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8Abstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8Abstract.java
new file mode 100644
index 0000000..a2c817b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8Abstract.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import org.apache.wicket.util.convert.ConversionException;
+import org.apache.isis.viewer.wicket.ui.components.scalars.DateConverterAbstract;
+
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+abstract class DateConverterForJdk8Abstract<T> extends DateConverterAbstract<T> {
+
+ private static final long serialVersionUID = 1L;
+
+ DateConverterForJdk8Abstract(Class<T> cls, String datePattern, String dateTimePattern, int adjustBy) {
+ super(cls, datePattern, dateTimePattern, adjustBy);
+ }
+
+ @Override
+ protected final T doConvertToObject(String value, Locale locale) {
+ T dateTime = convert(value);
+ return minusDays(dateTime, adjustBy);
+ }
+
+ @Override
+ protected String doConvertToString(T value, Locale locale) {
+ // for JodaLocalDate, the date time pattern is same as date pattern, so can use either to convert to string.
+ T t = plusDays(value, adjustBy);
+ return toString(t, DateTimeFormatter.ofPattern(dateTimePattern));
+ }
+
+ protected DateTimeFormatter getFormatterForDatePattern8() {
+ return DateTimeFormatter.ofPattern(datePattern);
+ }
+
+ protected DateTimeFormatter getFormatterForDateTimePattern8() {
+ return DateTimeFormatter.ofPattern(dateTimePattern);
+ }
+
+ protected abstract T minusDays(T value, int adjustBy);
+ protected abstract T plusDays(T value, int adjustBy);
+
+ protected abstract T convert(String value) throws ConversionException;
+ protected abstract String toString(T value, DateTimeFormatter dateTimeFormatter);
+
+}
\ No newline at end of file
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8LocalDate.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8LocalDate.java
new file mode 100644
index 0000000..799d21a
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8LocalDate.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.wicket.util.convert.ConversionException;
+
+/**
+ * Uses the same pattern for both date and date/time. The only real consequence of this is that when converting a
+ * string value to the date value, only a single pattern is used.
+ */
+public class DateConverterForJdk8LocalDate extends DateConverterForJdk8Abstract<LocalDate> {
+
+ private static final long serialVersionUID = 1L;
+
+ public DateConverterForJdk8LocalDate(WicketViewerSettings settings, int adjustBy) {
+ super(LocalDate.class, settings.getDatePattern(), settings.getDatePattern(), adjustBy);
+ }
+
+ @Override
+ protected LocalDate minusDays(LocalDate value, int adjustBy) {
+ return value.minusDays(adjustBy);
+ }
+
+ @Override
+ protected LocalDate plusDays(LocalDate value, int adjustBy) {
+ return value.plusDays(adjustBy);
+ }
+
+ @Override
+ protected LocalDate convert(String value) throws ConversionException {
+ try {
+ return getFormatterForDateTimePattern8().parse(value, LocalDate::from);
+ } catch(Exception ex) {
+ throw new ConversionException(String.format("Cannot convert '%s' into a date/time", value), ex);
+ }
+ }
+
+
+
+ @Override
+ protected String toString(LocalDate value, DateTimeFormatter dateTimeFormatter) {
+ return value.format(dateTimeFormatter);
+ }
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8LocalDateTime.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8LocalDateTime.java
new file mode 100644
index 0000000..99e6ed2
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8LocalDateTime.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.wicket.util.convert.ConversionException;
+
+public class DateConverterForJdk8LocalDateTime extends DateConverterForJdk8Abstract<LocalDateTime> {
+
+ private static final long serialVersionUID = 1L;
+
+ public DateConverterForJdk8LocalDateTime(WicketViewerSettings settings, int adjustBy) {
+ super(LocalDateTime.class, settings.getDatePattern(), settings.getDateTimePattern(), adjustBy);
+ }
+
+
+ @Override
+ protected LocalDateTime minusDays(LocalDateTime value, int adjustBy) {
+ return value.minusDays(adjustBy);
+ }
+
+ @Override
+ protected LocalDateTime plusDays(LocalDateTime value, int adjustBy) {
+ return value.plusDays(adjustBy);
+ }
+
+
+ @Override
+ protected LocalDateTime convert(String value) throws ConversionException {
+ try {
+ return getFormatterForDateTimePattern8().parse(value, LocalDateTime::from);
+ } catch(Exception ex) {
+
+ try {
+
+ return LocalDateTime.of(
+ getFormatterForDatePattern8().parse(value, LocalDate::from),
+ LocalTime.of(0, 0) );
+
+ } catch(Exception ex2) {
+
+ throw new ConversionException(
+ String.format(
+ "Cannot convert '%s' into a date/time using pattern '%s' or '%s'",
+ value, dateTimePattern, datePattern),
+ ex2 );
+ }
+ }
+ }
+
+ @Override
+ protected String toString(LocalDateTime value, DateTimeFormatter dateTimeFormatter) {
+ return value.format(dateTimeFormatter);
+ }
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8OffsetDateTime.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8OffsetDateTime.java
new file mode 100644
index 0000000..5d324b4
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/DateConverterForJdk8OffsetDateTime.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.wicket.util.convert.ConversionException;
+
+public class DateConverterForJdk8OffsetDateTime extends DateConverterForJdk8Abstract<OffsetDateTime> {
+
+ private static final long serialVersionUID = 1L;
+
+ public DateConverterForJdk8OffsetDateTime(WicketViewerSettings settings, int adjustBy) {
+ super(OffsetDateTime.class, settings.getDatePattern(), settings.getDateTimePattern(), adjustBy);
+ }
+
+ @Override
+ protected OffsetDateTime minusDays(OffsetDateTime value, int adjustBy) {
+ return value.minusDays(adjustBy);
+ }
+
+ @Override
+ protected OffsetDateTime plusDays(OffsetDateTime value, int adjustBy) {
+ return value.plusDays(adjustBy);
+ }
+
+ @Override
+ protected OffsetDateTime convert(String value) throws ConversionException {
+
+ return OffsetDateTime.of(
+ convertToLocal(value),
+ defaultOffset()
+ );
+
+ }
+
+ @Override
+ protected String toString(OffsetDateTime value, DateTimeFormatter dateTimeFormatter) {
+ return value.format(dateTimeFormatter);
+ }
+
+ // -- HELPER
+
+ private LocalDateTime convertToLocal(String value) throws ConversionException {
+ try {
+ return getFormatterForDateTimePattern8().parse(value, LocalDateTime::from);
+ } catch(Exception ex) {
+
+ try {
+
+ return LocalDateTime.of(
+ getFormatterForDatePattern8().parse(value, LocalDate::from),
+ LocalTime.of(0, 0) );
+
+ } catch(Exception ex2) {
+
+ throw new ConversionException(
+ String.format(
+ "Cannot convert '%s' into a date/time using pattern '%s' or '%s'",
+ value, dateTimePattern, datePattern),
+ ex2 );
+ }
+ }
+ }
+
+ private ZoneOffset defaultOffset() {
+ return OffsetDateTime.now().getOffset();
+
+ }
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDatePanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDatePanel.java
new file mode 100644
index 0000000..8a448d6
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDatePanel.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.LocalDate;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldDatePickerAbstract;
+/**
+ * Panel for rendering scalars of type {@link LocalDate}.
+ */
+public class Jdk8LocalDatePanel extends ScalarPanelTextFieldDatePickerAbstract<LocalDate> {
+
+ private static final long serialVersionUID = 1L;
+
+ public Jdk8LocalDatePanel(final String id, final ScalarModel scalarModel) {
+ super(id, scalarModel, LocalDate.class);
+ init(new DateConverterForJdk8LocalDate(getSettings(), getAdjustBy()));
+ }
+
+ @Override
+ protected String getScalarPanelType() {
+ return "jdk8DateTimePanel";
+ }
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDatePanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDatePanelFactory.java
new file mode 100644
index 0000000..7194e4b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDatePanelFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import org.apache.wicket.Component;
+
+import java.time.LocalDate;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract;
+
+
+/**
+ * {@link ComponentFactory} for {@link Jdk8LocalDatePanel}.
+ */
+public class Jdk8LocalDatePanelFactory extends ComponentFactoryScalarAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ public Jdk8LocalDatePanelFactory() {
+ super(Jdk8LocalDatePanel.class, LocalDate.class);
+ }
+
+ @Override
+ public Component createComponent(final String id, final ScalarModel scalarModel) {
+ return new Jdk8LocalDatePanel(id, scalarModel);
+ }
+
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDateTimePanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDateTimePanel.java
new file mode 100644
index 0000000..a90beb3
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDateTimePanel.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.LocalDateTime;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldDatePickerAbstract;
+import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.datepicker.TextFieldWithDateTimePicker;
+import org.apache.wicket.markup.html.form.AbstractTextComponent;
+
+/**
+ * Panel for rendering scalars of type {@link LocalDateTime}.
+ */
+public class Jdk8LocalDateTimePanel extends ScalarPanelTextFieldDatePickerAbstract<LocalDateTime> {
+
+ private static final long serialVersionUID = 1L;
+
+ public Jdk8LocalDateTimePanel(final String id, final ScalarModel scalarModel) {
+ super(id, scalarModel, LocalDateTime.class);
+ init(new DateConverterForJdk8LocalDateTime(getSettings(), getAdjustBy()));
+ }
+
+ protected AbstractTextComponent<LocalDateTime> createTextFieldForRegular(final String id) {
+ final TextFieldValueModel<LocalDateTime> textFieldValueModel = new TextFieldValueModel<>(this);
+ return new TextFieldWithDateTimePicker<>(id, textFieldValueModel, cls, converter);
+ }
+
+ @Override
+ protected String getScalarPanelType() {
+ return "jdk8LocalDateTimePanel";
+ }
+
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDateTimePanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDateTimePanelFactory.java
new file mode 100644
index 0000000..475ea31
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8LocalDateTimePanelFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.LocalDateTime;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract;
+import org.apache.wicket.Component;
+
+/**
+ * {@link ComponentFactory} for {@link Jdk8LocalDatePanel}.
+ */
+public class Jdk8LocalDateTimePanelFactory extends ComponentFactoryScalarAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ public Jdk8LocalDateTimePanelFactory() {
+ super(Jdk8LocalDateTimePanel.class, LocalDateTime.class);
+ }
+
+ @Override
+ public Component createComponent(final String id, final ScalarModel scalarModel) {
+ return new Jdk8LocalDateTimePanel(id, scalarModel);
+ }
+
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8OffsetDateTimePanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8OffsetDateTimePanel.java
new file mode 100644
index 0000000..c3b291f
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8OffsetDateTimePanel.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.OffsetDateTime;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldDatePickerAbstract;
+import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.datepicker.TextFieldWithDateTimePicker;
+import org.apache.wicket.markup.html.form.AbstractTextComponent;
+
+/**
+ * Panel for rendering scalars of type {@link OffsetDateTime}.
+ */
+public class Jdk8OffsetDateTimePanel extends ScalarPanelTextFieldDatePickerAbstract<OffsetDateTime> {
+
+ private static final long serialVersionUID = 1L;
+
+ public Jdk8OffsetDateTimePanel(final String id, final ScalarModel scalarModel) {
+ super(id, scalarModel, OffsetDateTime.class);
+ init(new DateConverterForJdk8OffsetDateTime(getSettings(), getAdjustBy()));
+ }
+
+ protected AbstractTextComponent<OffsetDateTime> createTextFieldForRegular(final String id) {
+ final TextFieldValueModel<OffsetDateTime> textFieldValueModel = new TextFieldValueModel<>(this);
+ return new TextFieldWithDateTimePicker<>(id, textFieldValueModel, cls, converter);
+ }
+
+ @Override
+ protected String getScalarPanelType() {
+ return "jdk8DateTimePanel";
+ }
+}
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8OffsetDateTimePanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8OffsetDateTimePanelFactory.java
new file mode 100644
index 0000000..7afab85
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/jdk8time/Jdk8OffsetDateTimePanelFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time;
+
+import java.time.OffsetDateTime;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.ComponentFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract;
+import org.apache.wicket.Component;
+
+/**
+ * {@link ComponentFactory} for {@link Jdk8LocalDatePanel}.
+ */
+public class Jdk8OffsetDateTimePanelFactory extends ComponentFactoryScalarAbstract {
+
+ private static final long serialVersionUID = 1L;
+
+ public Jdk8OffsetDateTimePanelFactory() {
+ super(Jdk8OffsetDateTimePanel.class, OffsetDateTime.class);
+ }
+
+ @Override
+ public Component createComponent(final String id, final ScalarModel scalarModel) {
+ return new Jdk8OffsetDateTimePanel(id, scalarModel);
+ }
+
+}
diff --git a/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8LocalDateTest.java b/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8LocalDateTest.java
new file mode 100644
index 0000000..aecfe24
--- /dev/null
+++ b/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8LocalDateTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.jdk8time;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.time.LocalDate;
+
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.DateConverterForJdk8LocalDate;
+
+public class DateConverterForJdk8LocalDateTest {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private WicketViewerSettings settings;
+
+ @Before
+ public void setUp() throws Exception {
+ context.checking(new Expectations() {
+ {
+ allowing(settings).getDatePattern();
+ will(returnValue("yyyy-MM-dd"));
+ }
+ });
+ }
+
+ @Test
+ public void roundtrip() {
+ final DateConverterForJdk8LocalDate converter = new DateConverterForJdk8LocalDate(settings, 0);
+ final LocalDate dt = converter.convertToObject("2013-05-11", null);
+ assertThat(dt, is(LocalDate.of(2013, 05, 11)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11"));
+ }
+
+ @Test
+ public void roundtripWithAdjustBy() {
+ final DateConverterForJdk8LocalDate converter = new DateConverterForJdk8LocalDate(settings, -1);
+ final LocalDate dt = converter.convertToObject("2013-05-11", null);
+ assertThat(dt, is(LocalDate.of(2013, 05, 12)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11"));
+ }
+
+}
diff --git a/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8LocalDateTimeTest.java b/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8LocalDateTimeTest.java
new file mode 100644
index 0000000..0105d30
--- /dev/null
+++ b/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8LocalDateTimeTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.jdk8time;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import java.time.LocalDateTime;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.DateConverterForJdk8LocalDateTime;
+
+public class DateConverterForJdk8LocalDateTimeTest {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private WicketViewerSettings settings;
+
+ @Before
+ public void setUp() throws Exception {
+ context.checking(new Expectations() {
+ {
+ allowing(settings).getDatePattern();
+ will(returnValue("yyyy-MM-dd"));
+ allowing(settings).getDateTimePattern();
+ will(returnValue("yyyy-MM-dd HH:mm"));
+ }
+ });
+ }
+
+ @Test
+ public void roundtripWhenParsingDateFormat() {
+ final DateConverterForJdk8LocalDateTime converter = new DateConverterForJdk8LocalDateTime(settings, 0);
+ final LocalDateTime dt = converter.convertToObject("2013-05-11", null);
+ assertThat(dt, is(LocalDateTime.of(2013, 05, 11, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+ @Test
+ public void roundtripWhenParsingDateTimeFormat() {
+ final DateConverterForJdk8LocalDateTime converter = new DateConverterForJdk8LocalDateTime(settings, 0);
+ final LocalDateTime dt = converter.convertToObject("2013-05-11 00:00", null);
+ assertThat(dt, is(LocalDateTime.of(2013, 05, 11, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+ @Test
+ public void roundtripWhenParsingDateFormatWithAdjustBy() {
+ final DateConverterForJdk8LocalDateTime converter = new DateConverterForJdk8LocalDateTime(settings, -1);
+ final LocalDateTime dt = converter.convertToObject("2013-05-11", null);
+ assertThat(dt, is(LocalDateTime.of(2013, 05, 12, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+ @Test
+ public void roundtripWhenParsingDateTimeFormatWithAdjustBy() {
+ final DateConverterForJdk8LocalDateTime converter = new DateConverterForJdk8LocalDateTime(settings, -1);
+ final LocalDateTime dt = converter.convertToObject("2013-05-11 00:00", null);
+ assertThat(dt, is(LocalDateTime.of(2013, 05, 12, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+
+}
diff --git a/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8OffsetDateTimeTest.java b/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8OffsetDateTimeTest.java
new file mode 100644
index 0000000..4d1874c
--- /dev/null
+++ b/core/viewer-wicket-ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/scalars/jodatime/jdk8time/DateConverterForJdk8OffsetDateTimeTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.jdk8time;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.time.OffsetDateTime;
+
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
+import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.DateConverterForJdk8OffsetDateTime;
+import org.jmock.Expectations;
+import org.jmock.auto.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class DateConverterForJdk8OffsetDateTimeTest {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private WicketViewerSettings settings;
+
+ @Before
+ public void setUp() throws Exception {
+ context.checking(new Expectations() {
+ {
+ allowing(settings).getDatePattern();
+ will(returnValue("yyyy-MM-dd"));
+ allowing(settings).getDateTimePattern();
+ will(returnValue("yyyy-MM-dd HH:mm"));
+ }
+ });
+ }
+
+
+ @Test
+ public void roundtripWhenParsingDateFormat() {
+ final DateConverterForJdk8OffsetDateTime converter = new DateConverterForJdk8OffsetDateTime(settings, 0);
+ final OffsetDateTime dt = converter.convertToObject("2013-05-11", null);
+ assertThat(dt, is(sample(2013, 05, 11, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+ @Test
+ public void roundtripWhenParsingDateTimeFormat() {
+ final DateConverterForJdk8OffsetDateTime converter = new DateConverterForJdk8OffsetDateTime(settings, 0);
+ final OffsetDateTime dt = converter.convertToObject("2013-05-11 00:00", null);
+ assertThat(dt, is(sample(2013, 05, 11, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+ @Test
+ public void roundtripWhenParsingDateFormatWithAdjustBy() {
+ final DateConverterForJdk8OffsetDateTime converter = new DateConverterForJdk8OffsetDateTime(settings, -1);
+ final OffsetDateTime dt = converter.convertToObject("2013-05-11", null);
+ assertThat(dt, is(sample(2013, 05, 12, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+ @Test
+ public void roundtripWhenParsingDateTimeFormatWithAdjustBy() {
+ final DateConverterForJdk8OffsetDateTime converter = new DateConverterForJdk8OffsetDateTime(settings, -1);
+ final OffsetDateTime dt = converter.convertToObject("2013-05-11 00:00", null);
+ assertThat(dt, is(sample(2013, 05, 12, 0, 0)));
+
+ final String str = converter.convertToString(dt, null);
+ assertThat(str, is("2013-05-11 00:00"));
+ }
+
+
+ private static OffsetDateTime sample( int year, int month, int dayOfMonth,
+ int hour, int minute) {
+ return OffsetDateTime.of(year, month, dayOfMonth, hour, minute, 0, 0,
+ OffsetDateTime.now().getOffset());
+ }
+
+
+
+
+}
--
To stop receiving notification emails like this one, please contact
"commits@isis.apache.org" <co...@isis.apache.org>.