Skip to content

Commit

Permalink
feat: updated existing converters
Browse files Browse the repository at this point in the history
  • Loading branch information
SethFalco committed Oct 1, 2021
1 parent d121047 commit f31a69c
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 234 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -57,6 +58,7 @@
import org.apache.commons.beanutils2.converters.DurationConverter;
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;
Expand Down Expand Up @@ -488,6 +490,7 @@ private void registerStandard(final boolean throwException, final boolean defaul
* <li>{@code java.util.Date.class} - {@link DateConverter}</li>
* <li>{@code java.util.Calendar.class} - {@link CalendarConverter}</li>
* <li>{@code File.class} - {@link FileConverter}</li>
* <li>{@code Instant.class} - {@link InstantConverter}</li>
* <li>{@code Path.class} - {@link PathConverter}</li>
* <li>{@code java.sql.Date.class} - {@link SqlDateConverter}</li>
* <li>{@code java.sql.Time.class} - {@link SqlTimeConverter}</li>
Expand Down Expand Up @@ -520,6 +523,7 @@ private void registerOther(final boolean throwException) {
register(java.util.Date.class, throwException ? new DateConverter() : new DateConverter(null));
register(Calendar.class, throwException ? new CalendarConverter() : new CalendarConverter(null));
register(File.class, throwException ? new FileConverter() : new FileConverter(null));
register(Instant.class, throwException ? new InstantConverter() : new InstantConverter(null));
register(Path.class, throwException ? new PathConverter() : new PathConverter(null));
register(java.sql.Date.class, throwException ? new SqlDateConverter() : new SqlDateConverter(null));
register(java.sql.Time.class, throwException ? new SqlTimeConverter() : new SqlTimeConverter(null));
Expand Down Expand Up @@ -586,6 +590,7 @@ private void registerArrays(final boolean throwException, final int defaultArray
registerArrayConverter(java.util.Date.class, new DateConverter(), throwException, defaultArraySize);
registerArrayConverter(Calendar.class, new DateConverter(), throwException, defaultArraySize);
registerArrayConverter(File.class, new FileConverter(), throwException, defaultArraySize);
registerArrayConverter(Instant.class, new InstantConverter(), throwException, defaultArraySize);
registerArrayConverter(Path.class, new PathConverter(), throwException, defaultArraySize);
registerArrayConverter(java.sql.Date.class, new SqlDateConverter(), throwException, defaultArraySize);
registerArrayConverter(java.sql.Time.class, new SqlTimeConverter(), throwException, defaultArraySize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,21 @@
* Can be configured to either return a <i>default value</i> or throw a
* {@code ConversionException} if a conversion error occurs.
*
* <p>
* This converter accept hexadecimal {@link String}s if obtaining a
* character from it's numeric value is desired.
*
* Intended for cases where there are concerns regarding the environment,
* such as system/file encodings between clients, applications, and servers.
* </p>
*
* @since 1.3
*/
public final class CharacterConverter extends AbstractConverter {

/** Determines if an input is a hexadecimal {@link String}. */
private static final String HEX_PREFIX = "0x";

/**
* Constructs a <b>java.lang.Character</b> <i>Converter</i> that throws
* a {@code ConversionException} if an error occurs.
Expand Down Expand Up @@ -83,7 +94,19 @@ protected String convertToString(final Object value) {
@Override
protected <T> T convertToType(final Class<T> type, final Object value) throws Exception {
if (Character.class.equals(type) || Character.TYPE.equals(type)) {
return type.cast(Character.valueOf(value.toString().charAt(0)));
final String stringValue = toString(value);

if (stringValue.isEmpty()) {
throw new IllegalArgumentException("Value must not be empty");
}

if (stringValue.length() > 2 && stringValue.substring(0, 2).equalsIgnoreCase(HEX_PREFIX)) {
final String substring = stringValue.substring(HEX_PREFIX.length());
final int hex = Integer.parseInt(substring, 16);
return type.cast((char) hex);
}

return type.cast(stringValue.charAt(0));
}

throw conversionException(type, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package org.apache.commons.beanutils2.converters;

import org.apache.commons.beanutils2.ConversionException;

import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
Expand All @@ -25,13 +27,12 @@
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.commons.beanutils2.ConversionException;

/**
* {@link org.apache.commons.beanutils2.Converter} implementation
* that handles conversion to and from <b>date/time</b> objects.
Expand All @@ -44,6 +45,7 @@
* <li>{@code java.time.LocalDate}</li>
* <li>{@code java.time.LocalDateTime}</li>
* <li>{@code java.time.OffsetDateTime}</li>
* <li>{@code java.time.Instant}</li>
* <li>{@code java.time.ZonedDateTime}</li>
* <li>{@code java.sql.Date}</li>
* <li>{@code java.sql.Time}</li>
Expand Down Expand Up @@ -228,19 +230,21 @@ protected String convertToString(final Object value) throws Throwable {

Date date = null;
if (value instanceof Date) {
date = (Date)value;
date = (Date) value;
} else if (value instanceof Calendar) {
date = ((Calendar)value).getTime();
date = ((Calendar) value).getTime();
} else if (value instanceof Long) {
date = new Date(((Long)value).longValue());
date = new Date(((Long) value).longValue());
} else if (value instanceof LocalDateTime) {
date = java.sql.Timestamp.valueOf(((LocalDateTime)value));
date = java.sql.Timestamp.valueOf(((LocalDateTime) value));
} else if (value instanceof LocalDate) {
date = java.sql.Date.valueOf(((LocalDate)value));
date = java.sql.Date.valueOf(((LocalDate) value));
} else if (value instanceof ZonedDateTime) {
date = Date.from(((ZonedDateTime)value).toInstant());
date = Date.from(((ZonedDateTime) value).toInstant());
} else if (value instanceof OffsetDateTime) {
date = Date.from(((OffsetDateTime)value).toInstant());
date = Date.from(((OffsetDateTime) value).toInstant());
} else if (value instanceof Instant) {
date = Date.from(((Instant) value));
}

String result = null;
Expand All @@ -260,7 +264,7 @@ protected String convertToString(final Object value) throws Throwable {
result = value.toString();
if (log().isDebugEnabled()) {
log().debug(" Converted to String using toString() '" + result + "'");
}
}
}
return result;
}
Expand All @@ -277,6 +281,7 @@ protected String convertToString(final Object value) throws Throwable {
* <li>{@code java.time.LocalDate}</li>
* <li>{@code java.time.LocalDateTime}</li>
* <li>{@code java.time.OffsetDateTime}</li>
* <li>{@code java.time.Instant}</li>
* <li>{@code java.time.ZonedDateTime}</li>
* <li>{@code java.sql.Date}</li>
* <li>{@code java.sql.Time}</li>
Expand Down Expand Up @@ -320,46 +325,51 @@ protected <T> T convertToType(final Class<T> targetType, final Object value) thr

// Handle Date (includes java.sql.Date & java.sql.Time)
if (value instanceof Date) {
final Date date = (Date)value;
final Date date = (Date) value;
return toDate(targetType, date.getTime());
}

// Handle Calendar
if (value instanceof Calendar) {
final Calendar calendar = (Calendar)value;
final Calendar calendar = (Calendar) value;
return toDate(targetType, calendar.getTime().getTime());
}

// Handle Long
if (value instanceof Long) {
final Long longObj = (Long)value;
final Long longObj = (Long) value;
return toDate(targetType, longObj.longValue());
}

// Handle LocalDate
if (value instanceof LocalDate) {
final LocalDate date = (LocalDate)value;
final LocalDate date = (LocalDate) value;
return toDate(targetType, date.atStartOfDay(getZoneId()).toInstant().toEpochMilli());
}

// Handle LocalDateTime
if (value instanceof LocalDateTime) {
final LocalDateTime date = (LocalDateTime)value;
final LocalDateTime date = (LocalDateTime) value;
return toDate(targetType, date.atZone(getZoneId()).toInstant().toEpochMilli());
}

// Handle ZonedDateTime
if (value instanceof ZonedDateTime) {
final ZonedDateTime date = (ZonedDateTime)value;
final ZonedDateTime date = (ZonedDateTime) value;
return toDate(targetType, date.toInstant().toEpochMilli());
}

// Handle OffsetDateTime
if (value instanceof OffsetDateTime) {
final OffsetDateTime date = (OffsetDateTime)value;
final OffsetDateTime date = (OffsetDateTime) value;
return toDate(targetType, date.toInstant().toEpochMilli());
}

if (value instanceof Instant) {
final Instant date = (Instant) value;
return toDate(targetType, date.toEpochMilli());
}

// Convert all other types to String & handle
final String stringValue = toTrim(value);
if (stringValue.isEmpty()) {
Expand Down Expand Up @@ -454,6 +464,10 @@ private <T> T toDate(final Class<T> type, final long value) {
return type.cast(offsetDateTime);
}

if (type.equals(Instant.class)) {
return type.cast(Instant.ofEpochMilli(value));
}

// java.util.Calendar
if (type.equals(Calendar.class)) {
Calendar calendar = null;
Expand Down Expand Up @@ -487,6 +501,7 @@ private <T> T toDate(final Class<T> type, final long value) {
* <li>{@code java.sql.Date}</li>
* <li>{@code java.sql.Time}</li>
* <li>{@code java.sql.Timestamp}</li>
* <li>{@code java.time.Instant}</li>
* </ul>
* <p>
* <strong>N.B.</strong> No default String conversion
Expand Down Expand Up @@ -530,6 +545,14 @@ private <T> T toDate(final Class<T> type, final String value) {
}
}

if (type.equals(Instant.class)) {
try {
return type.cast(Instant.parse(value));
} catch (final DateTimeParseException ex) {
throw new ConversionException("String must be in ISO-8601 format to create a java.time.Instant");
}
}

final String msg = toString(getClass()) + " does not support default String to '"
+ toString(type) + "' conversion.";
if (log().isWarnEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ protected Class<?> getDefaultType() {
@Override
protected <T> T convertToType(final Class<T> type, final Object value) throws Throwable {
if (Duration.class.equals(type)) {
return type.cast(Duration.parse((String.valueOf(value))));
final String stringValue = toString(value);
return type.cast(Duration.parse(stringValue));
}

throw conversionException(type, value);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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 <b>java.lang.Enum</b> objects.
Expand All @@ -29,6 +32,11 @@
*/
public final class EnumConverter extends AbstractConverter {

/** Matches if a given input is an enum string. */
private static final Pattern ENUM_PATTERN = Pattern.compile(
"((?:[a-z\\d.]+)*)\\.([A-Za-z\\d]+)[#.]([A-Z\\d_]+)"
);

/**
* Constructs a <b>java.lang.Enum</b> <i>Converter</i> that throws
* a {@code ConversionException} if an error occurs.
Expand Down Expand Up @@ -71,21 +79,42 @@ protected Class<?> getDefaultType() {
*/
@SuppressWarnings({ "rawtypes" })
@Override
protected <T> T convertToType(final Class<T> type, final Object value) throws Throwable {
protected <T> T convertToType(final Class<T> type, final Object value) throws Throwable {
if (Enum.class.isAssignableFrom(type)) {
final String enumValue = String.valueOf(value);
final T[] constants = type.getEnumConstants();
if (constants == null) {
throw conversionException(type, value);
final String stringValue = toString(value);

try {
return type.cast((Enum) Enum.valueOf((Class) type, stringValue));
} catch (IllegalArgumentException ex) {
// Continue to check fully qualified name.
}
for (final T candidate : constants) {
if (((Enum)candidate).name().equalsIgnoreCase(enumValue)) {
return candidate;

Matcher matcher = ENUM_PATTERN.matcher(stringValue);

if (!matcher.matches()) {
throw new IllegalArgumentException(
"Value doesn't follow Java naming conventions, expecting input like: java.time.DayOfWeek.MONDAY");
}

String className = matcher.group(1) + "." + matcher.group(2);

try {
Class classForName = Class.forName(className);

if (!classForName.isEnum()) {
throw new IllegalArgumentException("Value isn't an enumerated type.");
}

if (!type.isAssignableFrom(classForName)) {
throw new IllegalArgumentException("Class is not the required type.");
}

return type.cast((Enum) Enum.valueOf(classForName, matcher.group(3)));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Class \"" + className + "\" doesn't exist.", ex);
}
}

throw conversionException(type, value);
}

}
Loading

0 comments on commit f31a69c

Please sign in to comment.