You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2020/12/05 21:54:46 UTC
[tapestry-5] branch master updated: TAP5-2645: Java Time API type
coercers (by Ben Weidig)
This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push:
new 0d7f097 TAP5-2645: Java Time API type coercers (by Ben Weidig)
0d7f097 is described below
commit 0d7f097a4a5197228314419807c45a72130c3ae3
Author: Thiago H. de Paula Figueiredo <th...@arsmachina.com.br>
AuthorDate: Sat Dec 5 18:54:26 2020 -0300
TAP5-2645: Java Time API type coercers (by Ben Weidig)
---
.../beanmodel/BeanModelSourceBuilder.java | 1 +
.../commons/internal/BasicTypeCoercions.java | 144 +++++++++++++++++++++
.../test/groovy/ioc/specs/TypeCoercerSpec.groovy | 79 ++++++++++-
3 files changed, 223 insertions(+), 1 deletion(-)
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/BeanModelSourceBuilder.java b/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/BeanModelSourceBuilder.java
index 1691f99..92a54e5 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/BeanModelSourceBuilder.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beanmodel/BeanModelSourceBuilder.java
@@ -170,6 +170,7 @@ public class BeanModelSourceBuilder {
{
CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
BasicTypeCoercions.provideBasicTypeCoercions(configuration);
+ BasicTypeCoercions.provideJSR310TypeCoercions(configuration);
typeCoercer = new TypeCoercerImpl(configuration.getTuples());
}
diff --git a/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java b/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java
index 6e7b1d8..ea5c7ed 100644
--- a/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java
+++ b/commons/src/main/java/org/apache/tapestry5/commons/internal/BasicTypeCoercions.java
@@ -17,15 +17,34 @@ import java.io.File;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.time.DayOfWeek;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
+import org.apache.tapestry5.commons.Configuration;
import org.apache.tapestry5.commons.MappedConfiguration;
import org.apache.tapestry5.commons.services.Coercion;
import org.apache.tapestry5.commons.services.CoercionTuple;
import org.apache.tapestry5.commons.services.TypeCoercer;
+import org.apache.tapestry5.commons.util.StringToEnumCoercion;
import org.apache.tapestry5.commons.util.TimeInterval;
import org.apache.tapestry5.func.Flow;
@@ -108,6 +127,8 @@ public class BasicTypeCoercions
}
});
+ add(configuration, String.class, Integer.class, Integer::valueOf);
+
add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
{
@Override
@@ -320,6 +341,129 @@ public class BasicTypeCoercions
}
+ /**
+ * Provides the basic type coercions for JSR310 (java.time.*) to a {@link Configuration}
+ * instance.
+ * TAP5-2645
+ */
+ public static void provideJSR310TypeCoercions(
+ MappedConfiguration<CoercionTuple.Key, CoercionTuple> configuration)
+ {
+ {
+ add(configuration, Year.class, Integer.class, Year::getValue);
+ add(configuration, Integer.class, Year.class, Year::of);
+ }
+
+ {
+ add(configuration, Month.class, Integer.class, Month::getValue);
+ add(configuration, Integer.class, Month.class, Month::of);
+
+ add(configuration, String.class, Month.class, StringToEnumCoercion.create(Month.class));
+ }
+
+ {
+ add(configuration, String.class, YearMonth.class, YearMonth::parse);
+
+ add(configuration, YearMonth.class, Year.class, input -> Year.of(input.getYear()));
+ add(configuration, YearMonth.class, Month.class, YearMonth::getMonth);
+ }
+
+ {
+ add(configuration, String.class, MonthDay.class, MonthDay::parse);
+
+ add(configuration, MonthDay.class, Month.class, MonthDay::getMonth);
+ }
+
+ {
+ add(configuration, DayOfWeek.class, Integer.class, DayOfWeek::getValue);
+ add(configuration, Integer.class, DayOfWeek.class, DayOfWeek::of);
+
+ add(configuration, String.class, DayOfWeek.class,
+ StringToEnumCoercion.create(DayOfWeek.class));
+ }
+
+ {
+ add(configuration, LocalDate.class, Instant.class, input -> {
+ return input.atStartOfDay(ZoneId.systemDefault()).toInstant();
+ });
+ add(configuration, Instant.class, LocalDate.class, input -> {
+ return input.atZone(ZoneId.systemDefault()).toLocalDate();
+ });
+
+ add(configuration, String.class, LocalDate.class, LocalDate::parse);
+
+ add(configuration, LocalDate.class, YearMonth.class, input -> {
+ return YearMonth.of(input.getYear(), input.getMonth());
+ });
+
+ add(configuration, LocalDate.class, MonthDay.class, input -> {
+ return MonthDay.of(input.getMonth(), input.getDayOfMonth());
+ });
+ }
+
+ {
+ add(configuration, LocalTime.class, Long.class, LocalTime::toNanoOfDay);
+ add(configuration, Long.class, LocalTime.class, LocalTime::ofNanoOfDay);
+
+ add(configuration, String.class, LocalTime.class, LocalTime::parse);
+ }
+
+ {
+ add(configuration, String.class, LocalDateTime.class, LocalDateTime::parse);
+
+ add(configuration, LocalDateTime.class, Instant.class, input -> {
+ return input.atZone(ZoneId.systemDefault()).toInstant();
+ });
+ add(configuration, Instant.class, LocalDateTime.class, input -> {
+ return LocalDateTime.ofInstant(input, ZoneId.systemDefault());
+ });
+
+ add(configuration, LocalDateTime.class, LocalDate.class, LocalDateTime::toLocalDate);
+ }
+
+ {
+ add(configuration, String.class, OffsetDateTime.class, OffsetDateTime::parse);
+
+ add(configuration, OffsetDateTime.class, Instant.class, OffsetDateTime::toInstant);
+
+ add(configuration, OffsetDateTime.class, OffsetTime.class,
+ OffsetDateTime::toOffsetTime);
+ }
+
+ {
+ add(configuration, String.class, ZoneId.class, ZoneId::of);
+ }
+
+ {
+ add(configuration, String.class, ZoneOffset.class, ZoneOffset::of);
+ }
+
+ {
+ add(configuration, String.class, ZonedDateTime.class, ZonedDateTime::parse);
+
+ add(configuration, ZonedDateTime.class, Instant.class, ZonedDateTime::toInstant);
+
+ add(configuration, ZonedDateTime.class, ZoneId.class, ZonedDateTime::getZone);
+ }
+
+ {
+ add(configuration, Instant.class, Long.class, Instant::toEpochMilli);
+ add(configuration, Long.class, Instant.class, Instant::ofEpochMilli);
+
+ add(configuration, Instant.class, Date.class, Date::from);
+ add(configuration, Date.class, Instant.class, Date::toInstant);
+ }
+
+ {
+ add(configuration, Duration.class, Long.class, Duration::toNanos);
+ add(configuration, Long.class, Duration.class, Duration::ofNanos);
+ }
+
+ {
+ add(configuration, String.class, Period.class, Period::parse);
+ }
+ }
+
private static <S, T> void add(MappedConfiguration<CoercionTuple.Key, CoercionTuple> configuration, Class<S> sourceType,
Class<T> targetType, Coercion<S, T> coercion)
{
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy
index a804cc0..c9e3583 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/TypeCoercerSpec.groovy
@@ -1,5 +1,22 @@
package ioc.specs
+import java.time.DayOfWeek
+import java.time.Duration
+import java.time.Instant
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.LocalTime
+import java.time.Month
+import java.time.MonthDay
+import java.time.OffsetDateTime
+import java.time.OffsetTime
+import java.time.Period
+import java.time.Year
+import java.time.YearMonth
+import java.time.ZoneId
+import java.time.ZoneOffset
+import java.time.ZonedDateTime
+
import org.apache.tapestry5.commons.services.TypeCoercer
import org.apache.tapestry5.commons.util.TimeInterval
import org.apache.tapestry5.func.F
@@ -104,6 +121,66 @@ class TypeCoercerSpec extends AbstractSharedRegistrySpecification {
Animal.DOG | String | 'DOG'
'CAT' | Animal | Animal.CAT
+ // TAP5-2645
+ 2020 | Year | Year.of(2020)
+ Year.of(2020) | Integer | 2020
+ 2020 | Year | Year.of(2020)
+ Month.OCTOBER | Integer | 10
+ 10 | Month | Month.OCTOBER
+ Month.OCTOBER | String | "OCTOBER"
+ "oCTobER" | Month | Month.OCTOBER
+ "--10-04" | MonthDay | MonthDay.of(10, 4)
+ MonthDay.of(10, 4) | String | "--10-04"
+ "2020-10" | YearMonth | YearMonth.of(2020, 10)
+ YearMonth.of(2020, 10) | String | "2020-10"
+ "2020-10-04" | LocalDate | LocalDate.of(2020, 10, 4)
+ LocalDate.of(2020, 10, 4) | Long | ZonedDateTime.of(LocalDate.of(2020, 10, 4), LocalTime.of(0, 0), ZoneId.systemDefault()).toEpochSecond() * 1_000
+ LocalDate.of(2020, 10, 4) | String | "2020-10-04"
+ LocalDate.of(2020, 10, 4) | YearMonth | YearMonth.of(2020, 10)
+ LocalDate.of(2020, 10, 4) | MonthDay | MonthDay.of( 10, 4)
+ YearMonth.of(2020, 10) | Month | Month.OCTOBER
+ YearMonth.of(2020, 10) | Year | Year.of(2020)
+ DayOfWeek.THURSDAY | Integer | 4
+ 4 | DayOfWeek | DayOfWeek.THURSDAY
+ DayOfWeek.THURSDAY | String | "THURSDAY"
+ "THURSdaY" | DayOfWeek | DayOfWeek.THURSDAY
+ LocalDate.of(2020, 10, 4) | String | "2020-10-04"
+ "2020-10-04" | LocalDate | LocalDate.of(2020, 10, 4)
+ 34862776991000L | LocalTime | LocalTime.of(9, 41, 2, 776991000)
+ LocalTime.of(9, 41, 2, 776991000) | Long | 34862776991000L
+ "09:41:02.776991" | LocalTime | LocalTime.of(9, 41, 2, 776991000)
+ LocalTime.of(9, 41, 2, 776991000) | String | "09:41:02.776991"
+
+ "2020-10-04T16:59:51.713909" | LocalDateTime | LocalDateTime.of(2020, 10, 4, 16, 59, 51, 713909000)
+ LocalDateTime.of(2020, 10, 4, 16, 59, 51, 713909000) | String | "2020-10-04T16:59:51.713909"
+ LocalDateTime.of(2020, 10, 4, 16, 59, 51, 713909000) | LocalDate | LocalDate.of(2020, 10, 4)
+ LocalDateTime.of(2020, 10, 4, 16, 59, 51, 0) | Long | ZonedDateTime.of(LocalDate.of(2020, 10, 4), LocalTime.of(16, 59, 51, 0), ZoneId.systemDefault()).toEpochSecond() * 1_000
+
+
+ "2020-10-04T16:59:51.713909+02:00" | OffsetDateTime | OffsetDateTime.of(2020, 10, 4, 16, 59, 51, 713909000, ZoneOffset.ofHours(2))
+ OffsetDateTime.of(2020, 10, 4, 16, 59, 51, 713909000, ZoneOffset.ofHours(2)) | String | "2020-10-04T16:59:51.713909+02:00"
+ OffsetDateTime.of(2020, 10, 4, 16, 59, 51, 713909000, ZoneOffset.ofHours(2)) | OffsetTime | OffsetTime.of(16, 59, 51, 713909000, ZoneOffset.ofHours(2))
+
+ "Europe/Berlin" | ZoneId | ZoneId.of("Europe/Berlin")
+ ZoneId.of("Europe/Berlin") | String | "Europe/Berlin"
+ "+02:00" | ZoneOffset | ZoneOffset.ofHours(2)
+ ZoneOffset.ofHoursMinutes(-2, -30) | String | "-02:30"
+
+ "2020-10-04T16:59:51.713909+02:00[Europe/Berlin]" | ZonedDateTime | ZonedDateTime.of(2020, 10, 4, 16, 59, 51, 713909000, ZoneId.of("Europe/Berlin"))
+ ZonedDateTime.of(2020, 10, 4, 16, 59, 51, 713909000, ZoneId.of("Europe/Berlin")) | String | "2020-10-04T16:59:51.713909+02:00[Europe/Berlin]"
+ ZonedDateTime.of(2020, 10, 4, 16, 59, 51, 713909000, ZoneId.of("Europe/Berlin")) | ZoneId | ZoneId.of("Europe/Berlin")
+
+ -1234L | Instant | Instant.ofEpochMilli(-1234L)
+ Instant.ofEpochMilli(-1234L) | Long | -1234L
+ new Date(1606653132000L) | Instant | Instant.ofEpochMilli(1606653132000L)
+ Instant.ofEpochMilli(-1234L) | Long | -1234L
+ 97200000000000L | Duration | Duration.ofHours(27L)
+ Duration.ofMinutes(90L) | Long | 5400000000000L
+ Period.of(12, 1, 7) | String | "P12Y1M7D"
+ "P12Y1M7D" | Period | Period.of(12, 1, 7)
+
+ ZonedDateTime.of(LocalDate.of(2020, 11, 29), LocalTime.of(13, 32, 12, 0), ZoneId.of("Europe/Berlin")).toEpochSecond() * 1_000 | Date | new Date(1606653132000L)
+
inputTypeName = PlasticUtils.toTypeName(input.getClass())
typeName = PlasticUtils.toTypeName(type)
}
@@ -118,7 +195,7 @@ class TypeCoercerSpec extends AbstractSharedRegistrySpecification {
where:
from | to | expected
- StringBuffer | Integer | "Object --> String, String --> Long, Long --> Integer"
+ StringBuffer | Integer | "Object --> String, String --> Integer"
void | Map | "null --> null"
void | Boolean | "null --> Boolean"
Object[] | Boolean | "Object[] --> Boolean"