diff --git a/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java index 6dc463128..3728fe824 100644 --- a/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java +++ b/src/main/java/org/apache/commons/beanutils2/ConvertUtilsBean.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.sql.Timestamp; import java.time.Duration; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -53,10 +54,11 @@ import org.apache.commons.beanutils2.converters.ConverterFacade; import org.apache.commons.beanutils2.converters.DateConverter; import org.apache.commons.beanutils2.converters.DoubleConverter; -import org.apache.commons.beanutils2.converters.EnumConverter; import org.apache.commons.beanutils2.converters.DurationConverter; +import org.apache.commons.beanutils2.converters.EnumConverter; import org.apache.commons.beanutils2.converters.FileConverter; import org.apache.commons.beanutils2.converters.FloatConverter; +import org.apache.commons.beanutils2.converters.InstantConverter; import org.apache.commons.beanutils2.converters.IntegerConverter; import org.apache.commons.beanutils2.converters.LocalDateConverter; import org.apache.commons.beanutils2.converters.LocalDateTimeConverter; @@ -112,6 +114,7 @@ *
  • java.sql.Date (no default value)
  • *
  • java.sql.Time (no default value)
  • *
  • java.sql.Timestamp (no default value)
  • + *
  • java.time.Instant (no default value)
  • *
  • java.time.LocalDate (no default value)
  • *
  • java.time.LocalDateTime (no default value)
  • *
  • java.time.LocalTime (no default value)
  • @@ -243,11 +246,17 @@ public String convert(Object value) { * * @throws ConversionException if thrown by an underlying Converter */ + @SuppressWarnings({ "unchecked", "rawtypes" }) public Object convert(final String value, final Class clazz) { if (log.isDebugEnabled()) { log.debug("Convert string '" + value + "' to class '" + clazz.getName() + "'"); } Converter converter = lookup(clazz); + //Enum Converter + if (converter == null && clazz.isEnum()) { + converter = (Converter)lookup(Enum.class); + } + if (converter == null) { Converter sConverter = lookup(String.class); if (log.isTraceEnabled()) { @@ -324,6 +333,12 @@ public Object convert(final Object value, final Class targetType) { Object converted = value; Converter converter = lookup(sourceType, targetType); + + //Enum Converter + if ((sourceType !=null && sourceType.isEnum()) || targetType.isEnum()) { + converter = (Converter)lookup(Enum.class); + } + if (converter != null) { if (log.isTraceEnabled()) { log.trace(" Using converter " + converter); @@ -484,6 +499,7 @@ private void registerStandard(final boolean throwException, final boolean defaul *
  • {@code URL.class} - {@link URLConverter}
  • *
  • {@code URI.class} - {@link URIConverter}
  • *
  • {@code UUID.class} - {@link UUIDConverter}
  • + *
  • {@code Instant.class} - {@link InstantConverter}
  • *
  • {@code LocalDate.class} - {@link LocalDateConverter}
  • *
  • {@code LocalDateTime.class} - {@link LocalDateTimeConverter}
  • *
  • {@code LocalTime.class} - {@link LocalTimeConverter}
  • @@ -516,6 +532,7 @@ private void registerOther(final boolean throwException) { register(URL.class, throwException ? new URLConverter() : new URLConverter(null)); register(URI.class, throwException ? new URIConverter() : new URIConverter(null)); register(UUID.class, throwException ? new UUIDConverter() : new UUIDConverter(null)); + register(Instant.class, throwException ? new InstantConverter() : new InstantConverter(null)); register(LocalDate.class, throwException ? new LocalDateConverter() : new LocalDateConverter(null)); register(LocalDateTime.class, throwException ? new LocalDateTimeConverter() : new LocalDateTimeConverter(null)); register(LocalTime.class, throwException ? new LocalTimeConverter() : new LocalTimeConverter(null)); @@ -582,6 +599,7 @@ private void registerArrays(final boolean throwException, final int defaultArray registerArrayConverter(URL.class, new URLConverter(), throwException, defaultArraySize); registerArrayConverter(URI.class, new URIConverter(), throwException, defaultArraySize); registerArrayConverter(UUID.class, new UUIDConverter(), throwException, defaultArraySize); + registerArrayConverter(Instant.class, new InstantConverter(), throwException, defaultArraySize); registerArrayConverter(LocalDate.class, new LocalDateConverter(), throwException, defaultArraySize); registerArrayConverter(LocalDateTime.class, new LocalDateTimeConverter(), throwException, defaultArraySize); registerArrayConverter(LocalTime.class, new LocalTimeConverter(), throwException, defaultArraySize); diff --git a/src/main/java/org/apache/commons/beanutils2/converters/DateTimeConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/DateTimeConverter.java index 70611bf13..3cf92799c 100644 --- a/src/main/java/org/apache/commons/beanutils2/converters/DateTimeConverter.java +++ b/src/main/java/org/apache/commons/beanutils2/converters/DateTimeConverter.java @@ -16,16 +16,25 @@ */ package org.apache.commons.beanutils2.converters; -import java.text.DateFormat; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; + import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; import java.util.Calendar; import java.util.Date; import java.util.Locale; @@ -40,12 +49,15 @@ * This implementation handles conversion for the following * date/time types. *
      - *
    • {@code java.util.Date}
    • - *
    • {@code java.util.Calendar}
    • + + *
    • {@code java.time.Instant}
    • *
    • {@code java.time.LocalDate}
    • + *
    • {@code java.time.LocalTime}
    • *
    • {@code java.time.LocalDateTime}
    • *
    • {@code java.time.OffsetDateTime}
    • *
    • {@code java.time.ZonedDateTime}
    • + *
    • {@code java.util.Date}
    • + *
    • {@code java.util.Calendar}
    • *
    • {@code java.sql.Date}
    • *
    • {@code java.sql.Time}
    • *
    • {@code java.sql.Timestamp}
    • @@ -97,7 +109,7 @@ public abstract class DateTimeConverter extends AbstractConverter { private String[] patterns; private String displayPatterns; private Locale locale; - private TimeZone timeZone; + private ZoneId zoneId; private boolean useLocaleFormat; /** @@ -136,7 +148,10 @@ public void setUseLocaleFormat(final boolean useLocaleFormat) { * @return The Time Zone. */ public TimeZone getTimeZone() { - return timeZone; + if(zoneId!=null) { + return TimeZone.getTimeZone(zoneId); + } + return null; } /** @@ -145,7 +160,7 @@ public TimeZone getTimeZone() { * @param timeZone The Time Zone. */ public void setTimeZone(final TimeZone timeZone) { - this.timeZone = timeZone; + this.zoneId = timeZone.toZoneId(); } /** @@ -221,33 +236,28 @@ public void setPatterns(final String[] patterns) { */ @Override protected String convertToString(final Object value) { - Date date = null; - if (value instanceof Date) { - date = (Date) value; - } else if (value instanceof Calendar) { - date = ((Calendar) value).getTime(); - } else if (value instanceof Long) { - date = new Date(((Long) value).longValue()); - } else if (value instanceof LocalDateTime) { - date = java.sql.Timestamp.valueOf(((LocalDateTime) value)); - } else if (value instanceof LocalDate) { - date = java.sql.Date.valueOf(((LocalDate) value)); - } else if (value instanceof ZonedDateTime) { - date = Date.from(((ZonedDateTime) value).toInstant()); - } else if (value instanceof OffsetDateTime) { - date = Date.from(((OffsetDateTime) value).toInstant()); - } else if (value instanceof TemporalAccessor) { - // Backstop for other TemporalAccessor implementations. - date = Date.from(Instant.from(((TemporalAccessor) value))); + TemporalAccessor date = null; + + if(value instanceof Instant) { + date = ((Instant)value).atZone(getZoneId()); + }else if (value instanceof TemporalAccessor) { + //LocalDateTime、LocalDate、LocalTime、ZonedDateTime、OffsetDateTime + date = (TemporalAccessor) value; + } else { + try { + date= convertToType(LocalDateTime.class,value); + }catch(Exception e) { + log().debug(value+" to LocalDateTime Error : ",e); + } } - + String result = null; if (useLocaleFormat && date != null) { - DateFormat format = null; + DateTimeFormatter format = null; if (patterns != null && patterns.length > 0) { format = getFormat(patterns[0]); } else { - format = getFormat(locale, timeZone); + format = getFormat(locale, getZoneId(),0); } logFormat("Formatting", format); result = format.format(date); @@ -273,9 +283,11 @@ protected String convertToString(final Object value) { *
    • {@code java.util.Date}
    • *
    • {@code java.util.Calendar}
    • *
    • {@code java.time.LocalDate}
    • + *
    • {@code java.time.LocalTime}
    • *
    • {@code java.time.LocalDateTime}
    • *
    • {@code java.time.OffsetDateTime}
    • *
    • {@code java.time.ZonedDateTime}
    • + *
    • {@code java.time.Instant}
    • *
    • {@code java.sql.Date}
    • *
    • {@code java.sql.Time}
    • *
    • {@code java.sql.Timestamp}
    • @@ -309,10 +321,8 @@ protected T convertToType(final Class targetType, final Object value) thr // didn't include the milliseconds. The following code // ensures it works consistently across JDK versions final java.sql.Timestamp timestamp = (java.sql.Timestamp)value; - long timeInMillis = ((timestamp.getTime() / 1000) * 1000); - timeInMillis += timestamp.getNanos() / 1000000; - - return toDate(targetType, timeInMillis); + return toDate(targetType, timestamp.getTime() / 1000, + timestamp.getNanos()); } // Handle Date (includes java.sql.Date & java.sql.Time) @@ -336,25 +346,42 @@ protected T convertToType(final Class targetType, final Object value) thr // Handle LocalDate if (value instanceof LocalDate) { final LocalDate date = (LocalDate)value; - return toDate(targetType, date.atStartOfDay(getZoneId()).toInstant().toEpochMilli()); + final Instant temp = date.atStartOfDay(getZoneId()).toInstant(); + return toDate(targetType, temp.getEpochSecond(), temp.getNano()); + } + + // Handle LocalTime + if (value instanceof LocalTime) { + final LocalTime date = (LocalTime)value; + final Instant temp = date.atDate(LocalDate.of(1970, 1, 1)).atZone(getZoneId()).toInstant(); + return toDate(targetType, temp.getEpochSecond(), temp.getNano()); } // Handle LocalDateTime if (value instanceof LocalDateTime) { final LocalDateTime date = (LocalDateTime)value; - return toDate(targetType, date.atZone(getZoneId()).toInstant().toEpochMilli()); + final Instant temp = date.atZone(getZoneId()).toInstant(); + return toDate(targetType, temp.getEpochSecond(), temp.getNano()); } // Handle ZonedDateTime if (value instanceof ZonedDateTime) { final ZonedDateTime date = (ZonedDateTime)value; - return toDate(targetType, date.toInstant().toEpochMilli()); + final Instant temp = date.toInstant(); + return toDate(targetType, temp.getEpochSecond(), temp.getNano()); } // Handle OffsetDateTime if (value instanceof OffsetDateTime) { final OffsetDateTime date = (OffsetDateTime)value; - return toDate(targetType, date.toInstant().toEpochMilli()); + final Instant temp = date.toInstant(); + return toDate(targetType, temp.getEpochSecond(), temp.getNano()); + } + + //Handle Instant and other TemporalAccessor implementations. + if (value instanceof TemporalAccessor) { + final Instant temp = Instant.from(((TemporalAccessor) value)); + return toDate(targetType, temp.getEpochSecond(), temp.getNano()); } // Convert all other types to String & handle @@ -365,17 +392,14 @@ protected T convertToType(final Class targetType, final Object value) thr // Parse the Date/Time if (useLocaleFormat) { - Calendar calendar = null; + TemporalAccessor temporalAccessor = null; if (patterns != null && patterns.length > 0) { - calendar = parse(sourceType, targetType, stringValue); + temporalAccessor = parse(sourceType, targetType, stringValue); } else { - final DateFormat format = getFormat(locale, timeZone); - calendar = parse(sourceType, targetType, stringValue, format); - } - if (Calendar.class.isAssignableFrom(targetType)) { - return targetType.cast(calendar); + final DateTimeFormatter format = getFormat(locale, getZoneId(),stringValue); + temporalAccessor = parse(sourceType, targetType, stringValue, format); } - return toDate(targetType, calendar.getTime().getTime()); + return convertToType(targetType, temporalAccessor); } // Default String conversion @@ -383,7 +407,7 @@ protected T convertToType(final Class targetType, final Object value) thr } /** - * Convert a long value to the specified Date type for this + * Convert a milliseconds long value to the specified Date type for this * Converter. *

      * @@ -392,8 +416,10 @@ protected T convertToType(final Class targetType, final Object value) thr *

    • {@code java.util.Date}
    • *
    • {@code java.util.Calendar}
    • *
    • {@code java.time.LocalDate}
    • + *
    • {@code java.time.LocalTime}
    • *
    • {@code java.time.LocalDateTime}
    • *
    • {@code java.time.ZonedDateTime}
    • + *
    • {@code java.time.Instant}
    • *
    • {@code java.sql.Date}
    • *
    • {@code java.sql.Time}
    • *
    • {@code java.sql.Timestamp}
    • @@ -401,10 +427,51 @@ protected T convertToType(final Class targetType, final Object value) thr * * @param The target type * @param type The Date type to convert to - * @param value The long value to convert. + * @param milliSeconds The milliseconds long value to convert. * @return The converted date value. */ - private T toDate(final Class type, final long value) { + private T toDate(final Class type, final long milliSeconds) { + return toDate(type, milliSeconds / 1000, + Long.valueOf(milliSeconds % 1000).intValue() * 1000000); + } + + /** + * Convert a seconds value and a nanos value to the specified + * Date type for this Converter. + *

      + * + * This method handles conversion to the following types: + *

        + *
      • {@code java.util.Date}
      • + *
      • {@code java.util.Calendar}
      • + *
      • {@code java.time.LocalDate}
      • + *
      • {@code java.time.LocalTime}
      • + *
      • {@code java.time.LocalDateTime}
      • + *
      • {@code java.time.ZonedDateTime}
      • + *
      • {@code java.time.Instant}
      • + *
      • {@code java.sql.Date}
      • + *
      • {@code java.sql.Time}
      • + *
      • {@code java.sql.Timestamp}
      • + *
      + * + * @param The target type + * @param type The Date type to convert to + * @param seconds Represents seconds of UTC time since Unix epoch + * 1970-01-01T00:00:00Z. Must be from + * 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z + * inclusive. + * @param nanos Non-negative fractions of a second at + * nanosecond resolution. Negative second values + * with fractions must still have non-negative + * nanos values that count forward in time. Must + * be from 0 to 999,999,999 inclusive. + * @return The converted date value. + */ + private T toDate(final Class type, final long seconds, + final int nanos) { + // milliseconds + long value = seconds * 1000 + nanos / 1000000; + // java.util.Date if (type.equals(Date.class)) { return type.cast(new Date(value)); @@ -422,58 +489,78 @@ private T toDate(final Class type, final long value) { // java.sql.Timestamp if (type.equals(java.sql.Timestamp.class)) { - return type.cast(new java.sql.Timestamp(value)); + java.sql.Timestamp stamp = new java.sql.Timestamp(value); + stamp.setNanos(nanos); + return type.cast(stamp); } - // java.time.LocalDateTime + // java.time.LocalDate if (type.equals(LocalDate.class)) { - final LocalDate localDate = Instant.ofEpochMilli(value).atZone(getZoneId()).toLocalDate(); + final LocalDate localDate = Instant.ofEpochSecond(seconds, nanos) + .atZone(getZoneId()).toLocalDate(); return type.cast(localDate); } + + // java.time.LocalTime + if (type.equals(LocalTime.class)) { + final LocalTime localTime = Instant.ofEpochSecond(seconds, nanos) + .atZone(getZoneId()).toLocalTime(); + return type.cast(localTime); + } // java.time.LocalDateTime if (type.equals(LocalDateTime.class)) { - final LocalDateTime localDateTime = Instant.ofEpochMilli(value).atZone(getZoneId()).toLocalDateTime(); + final LocalDateTime localDateTime = Instant + .ofEpochSecond(seconds, nanos).atZone(getZoneId()) + .toLocalDateTime(); return type.cast(localDateTime); } // java.time.ZonedDateTime if (type.equals(ZonedDateTime.class)) { - final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value), getZoneId()); + final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant( + Instant.ofEpochSecond(seconds, nanos), getZoneId()); return type.cast(zonedDateTime); } // java.time.OffsetDateTime if (type.equals(OffsetDateTime.class)) { - final OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(value), getZoneId()); + final OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant( + Instant.ofEpochSecond(seconds, nanos), getZoneId()); return type.cast(offsetDateTime); } + + // java.time.Instant + if (type.equals(Instant.class)) { + final Instant instant = Instant.ofEpochSecond(seconds, nanos); + return type.cast(instant); + } // java.util.Calendar if (type.equals(Calendar.class)) { Calendar calendar = null; - if (locale == null && timeZone == null) { + if (locale == null && this.getTimeZone() == null) { calendar = Calendar.getInstance(); } else if (locale == null) { - calendar = Calendar.getInstance(timeZone); - } else if (timeZone == null) { + calendar = Calendar.getInstance(this.getTimeZone()); + } else if (this.getTimeZone() == null) { calendar = Calendar.getInstance(locale); } else { - calendar = Calendar.getInstance(timeZone, locale); + calendar = Calendar.getInstance(this.getTimeZone(), locale); } calendar.setTime(new Date(value)); calendar.setLenient(false); return type.cast(calendar); } - final String msg = toString(getClass()) + " cannot handle conversion to '" - + toString(type) + "'"; + final String msg = toString(getClass()) + + " cannot handle conversion to '" + toString(type) + "'"; if (log().isWarnEnabled()) { log().warn(" " + msg); } throw new ConversionException(msg); } - + /** * Default String to Date conversion. *

      @@ -535,35 +622,59 @@ private T toDate(final Class type, final String value) { } /** - * Gets a {@code DateFormat} for the Locale. + * Gets a {@code DateTimeFormatter} for the Locale. * @param locale The Locale to create the Format with (may be null) - * @param timeZone The Time Zone create the Format with (may be null) + * @param zoneId The Time Zone create the Format with (may be null) + * @param value format Value * * @return A Date Format. */ - protected DateFormat getFormat(final Locale locale, final TimeZone timeZone) { - DateFormat format = null; - if (locale == null) { - format = DateFormat.getDateInstance(DateFormat.SHORT); - } else { - format = DateFormat.getDateInstance(DateFormat.SHORT, locale); + protected DateTimeFormatter getFormat(final Locale locale, final ZoneId zoneId,String value) { + if (value.length()>10) { + return getFormat(locale,zoneId,0); + }else { + return getFormat(locale,zoneId,1); } - if (timeZone != null) { - format.setTimeZone(timeZone); - } - return format; + } + + /** + * Gets a {@code DateTimeFormatter} for the Locale. + * @param locale The Locale to create the Format with (may be null) + * @param zoneId The Time Zone create the Format with (may be null) + * @param type 0:LocalizedDateTime、1:LocalizedDate、2:LocalizedTime + * @return + */ + protected DateTimeFormatter getFormat(final Locale locale, final ZoneId zoneId,final int type) { + DateTimeFormatter format = null; + //DateTime + if (type==0) { + format = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); + }else if (type==1){ + format = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); + }else if (type==2) { + //CaseSensitive 10:36 am. + format = new DateTimeFormatterBuilder().parseCaseInsensitive() + .appendLocalized(null, FormatStyle.SHORT).toFormatter().withChronology(IsoChronology.INSTANCE); + } + if (locale != null) { + format = format.withLocale(locale); + } + if (zoneId != null ) { + format = format.withZone(zoneId); + } + return format; } /** * Create a date format for the specified pattern. * * @param pattern The date pattern - * @return The DateFormat + * @return The DateTimeFormatter */ - private DateFormat getFormat(final String pattern) { - final DateFormat format = new SimpleDateFormat(pattern); - if (timeZone != null) { - format.setTimeZone(timeZone); + private DateTimeFormatter getFormat(final String pattern) { + final DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern); + if (zoneId != null ) { + return format.withZone(getZoneId()); } return format; } @@ -578,13 +689,13 @@ private DateFormat getFormat(final String pattern) { * @return The converted Date object. * @throws Exception if an error occurs parsing the date. */ - private Calendar parse(final Class sourceType, final Class targetType, final String value) throws Exception { + private TemporalAccessor parse(final Class sourceType, final Class targetType, final String value) throws Exception { Exception firstEx = null; for (final String pattern : patterns) { try { - final DateFormat format = getFormat(pattern); - final Calendar calendar = parse(sourceType, targetType, value, format); - return calendar; + final DateTimeFormatter format = getFormat(pattern); + final TemporalAccessor temporalAccessor = parse(sourceType, targetType, value, format); + return temporalAccessor; } catch (final Exception ex) { if (firstEx == null) { firstEx = ex; @@ -610,24 +721,125 @@ private Calendar parse(final Class sourceType, final Class targetType, fin * @return The converted Calendar object. * @throws ConversionException if the String cannot be converted. */ - private Calendar parse(final Class sourceType, final Class targetType, final String value, - final DateFormat format) { + private TemporalAccessor parse(final Class sourceType, final Class targetType, final String value, + DateTimeFormatter format) { logFormat("Parsing", format); - format.setLenient(false); final ParsePosition pos = new ParsePosition(0); - final Date parsedDate = format.parse(value, pos); // ignore the result (use the Calendar) + final TemporalAccessor parsedDate = format.parse(value, pos); // ignore the result (use the Calendar) if (pos.getErrorIndex() >= 0 || pos.getIndex() != value.length() || parsedDate == null) { String msg = "Error converting '" + toString(sourceType) + "' to '" + toString(targetType) + "'"; - if (format instanceof SimpleDateFormat) { - msg += " using pattern '" + ((SimpleDateFormat)format).toPattern() + "'"; + if (format instanceof DateTimeFormatter) { + //msg += " using pattern '" + ((SimpleDateFormat)format).toPattern() + "'"; + msg += " using pattern '" + ((DateTimeFormatter)format).toString() + "'"; } if (log().isDebugEnabled()) { log().debug(" " + msg); } throw new ConversionException(msg); } - final Calendar calendar = format.getCalendar(); - return calendar; + + if (checkZonedDateTime(parsedDate)) { + return ZonedDateTime.from(parsedDate); + } else if(checkOffsetDateTime(parsedDate)) { + return OffsetDateTime.from(parsedDate); + } else if (checkLocalDateTime(parsedDate)) { + return LocalDateTime.from(parsedDate); + } else if (checkLocalDate(parsedDate)) { + return LocalDate.from(parsedDate); + } else if (checkLocalTime(parsedDate)) { + return LocalTime.from(parsedDate); + } else if (parsedDate.isSupported(INSTANT_SECONDS)){ + return Instant.from(parsedDate); + } else { + LocalDateTime ldt=LocalDateTime.of(1970, 1, 1, 0, 0); + if (parsedDate.isSupported(ChronoField.YEAR)) { + ldt=ldt.withYear(parsedDate.get(ChronoField.YEAR)); + } + if (parsedDate.isSupported(ChronoField.MONTH_OF_YEAR)) { + ldt=ldt.withMonth(parsedDate.get(ChronoField.MONTH_OF_YEAR)); + } + return ldt; + } + } + + /** + * Check ZonedDateTime from TemporalAccessor. + */ + public boolean checkZonedDateTime(TemporalAccessor temporal) { + if (temporal instanceof ZonedDateTime) { + return true; + } + if (temporal.query(TemporalQueries.offset())!=null) { + return false; + } + if (temporal.query(TemporalQueries.zone())==null) { + return false; + } + if (temporal.isSupported(INSTANT_SECONDS)) { + return true; + } + return checkLocalDateTime(temporal); + } + /** + * Check LocalDateTime from TemporalAccessor. + */ + public boolean checkLocalDateTime(TemporalAccessor temporal) { + if (temporal instanceof LocalDateTime) { + return true; + } + if (temporal.query(TemporalQueries.localDate())==null) { + return false; + } + if (temporal.query(TemporalQueries.localTime())==null) { + return false; + } + return true; + } + /** + * Check LocalDate from TemporalAccessor. + */ + public boolean checkLocalDate(TemporalAccessor temporal) { + if (temporal instanceof LocalDate) { + return true; + } + if (temporal.query(TemporalQueries.localDate())==null) { + return false; + } + if (temporal.query(TemporalQueries.localTime())!=null) { + return false; + } + return true; + } + + /** + * Check LocalTime from TemporalAccessor. + */ + public boolean checkLocalTime(TemporalAccessor temporal) { + if (temporal instanceof LocalTime) { + return true; + } + if (temporal.query(TemporalQueries.localDate())!=null) { + return false; + } + if (temporal.query(TemporalQueries.localTime())==null) { + return false; + } + return true; + } + /** + * Check OffsetDateTime from TemporalAccessor. + */ + public boolean checkOffsetDateTime(TemporalAccessor temporal) { + if (temporal instanceof OffsetDateTime) { + return true; + } + if (temporal.query(TemporalQueries.offset())==null) { + return false; + } + if (temporal.isSupported(INSTANT_SECONDS)) { + return true; + } + return checkLocalDateTime(temporal); } /** @@ -652,9 +864,9 @@ public String toString() { buffer.append(", Locale="); buffer.append(locale); } - if (timeZone != null) { - buffer.append(", TimeZone="); - buffer.append(timeZone); + if (zoneId != null) { + buffer.append(", ZoneId="); + buffer.append(zoneId); } buffer.append(']'); return buffer.toString(); @@ -665,15 +877,16 @@ public String toString() { * @param action The action the format is being used for * @param format The Date format */ - private void logFormat(final String action, final DateFormat format) { + private void logFormat(final String action, final DateTimeFormatter format) { if (log().isDebugEnabled()) { final StringBuilder buffer = new StringBuilder(45); buffer.append(" "); buffer.append(action); buffer.append(" with Format"); - if (format instanceof SimpleDateFormat) { + if (format instanceof DateTimeFormatter) { buffer.append("["); - buffer.append(((SimpleDateFormat)format).toPattern()); + buffer.append(((DateTimeFormatter)format).toString()); + //buffer.append(((SimpleDateFormat)format).toPattern()); buffer.append("]"); } buffer.append(" for "); @@ -684,21 +897,31 @@ private void logFormat(final String action, final DateFormat format) { buffer.append(locale); buffer.append("]"); } - if (timeZone != null) { - buffer.append(", TimeZone["); - buffer.append(timeZone); + if (zoneId != null) { + buffer.append(", ZoneId["); + buffer.append(zoneId); buffer.append("]"); } log().debug(buffer.toString()); } } + + + /** + * Sets the {@code java.time.ZoneId from the java.util.Timezone}. + * + * @param zoneId The ZoneId. + */ + public void setZoneId(ZoneId zoneId) { + this.zoneId = zoneId; + } /** * Gets the {@code java.time.ZoneId from the java.util.Timezone} * set or use the system default if no time zone is set. * @return the {@code ZoneId} */ - private ZoneId getZoneId() { - return timeZone == null ? ZoneId.systemDefault() : timeZone.toZoneId(); + public ZoneId getZoneId() { + return zoneId == null ? ZoneId.systemDefault() : zoneId; } } diff --git a/src/main/java/org/apache/commons/beanutils2/converters/DurationConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/DurationConverter.java index f54fe4570..83f168694 100644 --- a/src/main/java/org/apache/commons/beanutils2/converters/DurationConverter.java +++ b/src/main/java/org/apache/commons/beanutils2/converters/DurationConverter.java @@ -76,7 +76,6 @@ protected T convertToType(final Class type, final Object value) throws Th if (Duration.class.equals(type)) { return type.cast(Duration.parse((String.valueOf(value)))); } - throw conversionException(type, value); } diff --git a/src/main/java/org/apache/commons/beanutils2/converters/EnumConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/EnumConverter.java index ce0035f20..4134301c7 100644 --- a/src/main/java/org/apache/commons/beanutils2/converters/EnumConverter.java +++ b/src/main/java/org/apache/commons/beanutils2/converters/EnumConverter.java @@ -16,6 +16,9 @@ */ package org.apache.commons.beanutils2.converters; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * {@link org.apache.commons.beanutils2.Converter} implementation that handles conversion * to and from java.lang.Enum objects. @@ -80,14 +83,41 @@ protected R convertToType(final Class type, final Object value) throws Th if (constants == null) { throw conversionException(type, value); } + //Enum number + if (isNumeric(enumValue)) { + Integer enumNumber= Integer.valueOf(enumValue); + if (enumNumber>=0 && enumNumber < constants.length) { + return constants[enumNumber]; + } + throw conversionException(type, value); + } + //Enum String for (final R candidate : constants) { if (((Enum)candidate).name().equalsIgnoreCase(enumValue)) { return candidate; } } } + //Enum to Integer Enum Ordinal + if (value instanceof Enum && type.equals(Integer.class)) { + return type.cast(((Enum)value).ordinal()); + } throw conversionException(type, value); } + + /** + * String is digit ? + * @param str String + * @return true/false + */ + public boolean isNumeric(String str){ + Pattern pattern = Pattern.compile("[0-9]*"); + Matcher isNum = pattern.matcher(str); + if( !isNum.matches() ){ + return false; + } + return true; + } } diff --git a/src/main/java/org/apache/commons/beanutils2/converters/InstantConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/InstantConverter.java new file mode 100644 index 000000000..3690919de --- /dev/null +++ b/src/main/java/org/apache/commons/beanutils2/converters/InstantConverter.java @@ -0,0 +1,69 @@ +/* + * 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.commons.beanutils2.converters; + +import java.time.Instant; + +/** + * {@link DateTimeConverter} implementation that handles conversion to + * and from java.time.Instant objects. + *

      + * This implementation can be configured to handle conversion either + * by using a Locale's default format or by specifying a set of format + * patterns (note, there is no default String conversion for Calendar). + * See the {@link DateTimeConverter} documentation for further details. + *

      + *

      + * Can be configured to either return a default value or throw a + * {@code ConversionException} if a conversion error occurs. + *

      + * + * @since 2.0 + * @see java.time.Instant + */ +public final class InstantConverter extends DateTimeConverter { + + /** + * Constructs a java.time.Instant Converter that throws + * a {@code ConversionException} if an error occurs. + */ + public InstantConverter() { + } + + /** + * Constructs a java.time.Instant Converter that returns + * a default value if an error occurs. + * + * @param defaultValue The default value to be returned + * if the value to be converted is missing or an error + * occurs converting the value. + */ + public InstantConverter(final Instant defaultValue) { + super(defaultValue); + } + + /** + * Gets the default type this {@code Converter} handles. + * + * @return The default type this {@code Converter} handles. + */ + @Override + protected Class getDefaultType() { + return Instant.class; + } + +} diff --git a/src/main/java/org/apache/commons/beanutils2/converters/SqlTimeConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/SqlTimeConverter.java index 93d7bbb40..59eb6331a 100644 --- a/src/main/java/org/apache/commons/beanutils2/converters/SqlTimeConverter.java +++ b/src/main/java/org/apache/commons/beanutils2/converters/SqlTimeConverter.java @@ -17,9 +17,9 @@ package org.apache.commons.beanutils2.converters; import java.sql.Time; -import java.text.DateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Locale; -import java.util.TimeZone; /** * {@link DateTimeConverter} implementation that handles conversion to @@ -68,25 +68,17 @@ protected Class