Skip to content
Permalink
Browse files
CXF-8659: Can't filter when attribute type is LocalDate or LocalDateT…
…ime (#911)
  • Loading branch information
reta committed Feb 22, 2022
1 parent 57d9eb9 commit e0df5b52626680967c05a65ac3a8305270e99891
Showing 3 changed files with 350 additions and 3 deletions.
@@ -25,11 +25,22 @@
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.Temporal;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
@@ -111,6 +122,7 @@ protected String getSetter(String setter) {
return setter;
}

@SuppressWarnings("unchecked")
protected Object parseType(String originalPropName,
Object ownerBean,
Object lastCastedValue,
@@ -126,6 +138,8 @@ protected Object parseType(String originalPropName,
Object castedValue = value;
if (Date.class.isAssignableFrom(valueType)) {
castedValue = convertToDate(valueType, value);
} else if (Temporal.class.isAssignableFrom(valueType)) {
castedValue = convertToTemporal((Class<? extends Temporal>)valueType, value);
} else {
boolean isPrimitive = InjectionUtils.isPrimitive(valueType);
boolean isPrimitiveOrEnum = isPrimitive || valueType.isEnum();
@@ -309,6 +323,47 @@ private Object convertToDate(Class<?> valueType, String value) throws SearchPars
}
}
}

private Temporal convertToTemporal(Class<? extends Temporal> valueType, String value) throws SearchParseException {

Message m = JAXRSUtils.getCurrentMessage();
Temporal obj = InjectionUtils.createFromParameterHandler(value, valueType, valueType,
new Annotation[]{}, m);
if (obj != null) {
return obj;
}

try {
if (LocalTime.class.isAssignableFrom(valueType)) {
return LocalTime.parse(value);
} else if (LocalDate.class.isAssignableFrom(valueType)) {
return LocalDate.from(convertToDefaultDate(value).toInstant().atZone(ZoneId.systemDefault()));
} else if (LocalDateTime.class.isAssignableFrom(valueType)) {
return convertTo(value, SearchUtils.DEFAULT_DATETIME_FORMAT, Boolean.FALSE, LocalDateTime::parse);
} else if (OffsetTime.class.isAssignableFrom(valueType)) {
return OffsetTime.parse(value);
} else if (OffsetDateTime.class.isAssignableFrom(valueType)) {
return convertTo(value, SearchUtils.DEFAULT_OFFSET_DATETIME_FORMAT,
Boolean.TRUE, OffsetDateTime::parse);
} else if (ZonedDateTime.class.isAssignableFrom(valueType)) {
return convertTo(value, SearchUtils.DEFAULT_ZONE_DATETIME_FORMAT,
Boolean.TRUE, ZonedDateTime::parse);
} else {
return convertToDefaultDate(value).toInstant();
}
} catch (ParseException | DateTimeParseException e) {
// is that duration?
try {
Date now = new Date();
DatatypeFactory.newInstance().newDuration(value).addTo(now);
return LocalDateTime.from(now.toInstant().atZone(ZoneId.systemDefault()));
} catch (DatatypeConfigurationException e1) {
throw new SearchParseException(e1);
} catch (IllegalArgumentException e1) {
throw new SearchParseException("Can parse " + value + " neither as date nor duration", e);
}
}
}

private Timestamp convertToTimestamp(String value) throws ParseException {
Date date = convertToDefaultDate(value);
@@ -322,15 +377,33 @@ private Time convertToTime(String value) throws ParseException {

private Date convertToDefaultDate(String value) throws ParseException {
DateFormat df = SearchUtils.getDateFormat(contextProperties);
String dateValue = normalizeTimeZone(value);
return df.parse(dateValue);
}

private <S extends Temporal> S convertTo(String value, String pattern, Boolean timezoneSupported,
BiFunction<String, DateTimeFormatter, S> parser) throws ParseException {
final DateTimeFormatter df = DateTimeFormatter.ofPattern(SearchUtils
.getDateFormatOrDefault(contextProperties, pattern)
.toPattern());
final String dateValue = normalizeTimeZone(value, timezoneSupported);
return parser.apply(dateValue, df);
}

private String normalizeTimeZone(String value) {
return normalizeTimeZone(value, Boolean.FALSE);
}

private String normalizeTimeZone(String value, Boolean timezoneSupported) {
String dateValue = value;
if (SearchUtils.isTimeZoneSupported(contextProperties, Boolean.FALSE)) {
if (SearchUtils.isTimeZoneSupported(contextProperties, timezoneSupported)) {
// zone in XML is "+01:00" in Java is "+0100"; stripping semicolon
int idx = value.lastIndexOf(':');
if (idx != -1) {
dateValue = value.substring(0, idx) + value.substring(idx + 1);
}
}
return df.parse(dateValue);
return dateValue;
}

private static String getMethodNameSuffix(String name) {
@@ -36,6 +36,9 @@ public final class SearchUtils {
public static final String TIMESTAMP_NO_TIMEZONE = "yyyy-MM-dd'T'HH:mm:ss";
public static final String TIMESTAMP_WITH_TIMEZONE_Z = "yyyy-MM-dd'T'HH:mm:ssZ";
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATETIME_FORMAT = TIMESTAMP_NO_TIMEZONE;
public static final String DEFAULT_OFFSET_DATETIME_FORMAT = TIMESTAMP_WITH_TIMEZONE_Z;
public static final String DEFAULT_ZONE_DATETIME_FORMAT = TIMESTAMP_WITH_TIMEZONE_Z + "'['z']'";
public static final String DATE_FORMAT_PROPERTY = "search.date-format";
public static final String TIMEZONE_SUPPORT_PROPERTY = "search.timezone.support";
public static final String LAX_PROPERTY_MATCH = "search.lax.property.match";
@@ -85,11 +88,20 @@ public static Date dateFromStringWithContextProperties(String value) {
return dateFromStringWithDefaultFormats(value);
}

public static SimpleDateFormat getDateFormatOrDefault(Map<String, String> properties, String pattern) {
return getDateFormatOrDefault(properties.get(DATE_FORMAT_PROPERTY), pattern);
}

public static SimpleDateFormat getDateFormat(Map<String, String> properties) {
return getDateFormat(properties.get(DATE_FORMAT_PROPERTY));
}

public static SimpleDateFormat getDateFormatOrDefault(String dfProperty, String pattern) {
return new SimpleDateFormat(dfProperty == null ? pattern : dfProperty);
}

public static SimpleDateFormat getDateFormat(String dfProperty) {
return new SimpleDateFormat(dfProperty == null ? DEFAULT_DATE_FORMAT : dfProperty);
return getDateFormatOrDefault(dfProperty, DEFAULT_DATE_FORMAT);
}

public static boolean isTimeZoneSupported(Map<String, String> properties, Boolean defaultValue) {

0 comments on commit e0df5b5

Please sign in to comment.