[FINERACT-1965] Change date resolvement from SMART to STRICT
This commit is contained in:
+42
@@ -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.fineract.infrastructure.core.api;
|
||||
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Locale;
|
||||
import org.apache.fineract.infrastructure.core.data.DateFormat;
|
||||
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
||||
|
||||
/**
|
||||
* Class for parsing dates sent as query parameters
|
||||
*/
|
||||
public class DateParam {
|
||||
|
||||
private final String dateAsString;
|
||||
|
||||
public DateParam(final String dateStr) throws WebApplicationException {
|
||||
this.dateAsString = dateStr;
|
||||
}
|
||||
|
||||
public LocalDate getDate(final String parameterName, final DateFormat dateFormat, final String localeAsString) {
|
||||
final Locale locale = JsonParserHelper.localeFromString(localeAsString);
|
||||
return JsonParserHelper.convertFrom(this.dateAsString, parameterName, dateFormat, locale);
|
||||
}
|
||||
}
|
||||
-4
@@ -418,10 +418,6 @@ public final class JsonCommand {
|
||||
return this.fromApiJsonHelper.extractLocalTimeNamed(parameterName, this.parsedCommand);
|
||||
}
|
||||
|
||||
public LocalDateTime localDateTimeValueOfParameterNamed(final String parameterName) {
|
||||
return this.fromApiJsonHelper.extractLocalDateTimeNamed(parameterName, this.parsedCommand);
|
||||
}
|
||||
|
||||
public MonthDay extractMonthDayNamed(final String parameterName) {
|
||||
return this.fromApiJsonHelper.extractMonthDayNamed(parameterName, this.parsedCommand);
|
||||
}
|
||||
|
||||
+62
@@ -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.fineract.infrastructure.core.data;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
|
||||
public class DateFormat {
|
||||
|
||||
@Getter
|
||||
private final String dateFormat;
|
||||
|
||||
public DateFormat(String rawDateFormat) {
|
||||
if (StringUtils.isBlank(rawDateFormat)) {
|
||||
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.dateFormat.format",
|
||||
"Dateformat is null", rawDateFormat);
|
||||
throw new PlatformApiDataValidationException("validation.msg.invalid.dateFormat.format", "Validation errors exist.",
|
||||
List.of(error));
|
||||
} else {
|
||||
String compatibleDateFormat = rawDateFormat.replace("yyyy", "uuuu");
|
||||
validate(compatibleDateFormat);
|
||||
dateFormat = compatibleDateFormat;
|
||||
}
|
||||
}
|
||||
|
||||
private void validate(String dateTimeFormat) {
|
||||
try {
|
||||
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient().appendPattern(dateTimeFormat)
|
||||
.optionalStart().appendPattern(" HH:mm:ss").optionalEnd().parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
|
||||
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0).parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter()
|
||||
.withResolverStyle(ResolverStyle.STRICT);
|
||||
} catch (final IllegalArgumentException | DateTimeParseException e) {
|
||||
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.dateFormat.format",
|
||||
"Invalid dateFormat: `" + dateTimeFormat, dateTimeFormat);
|
||||
throw new PlatformApiDataValidationException("validation.msg.invalid.dateFormat.format", "Validation errors exist.",
|
||||
List.of(error), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
-17
@@ -27,6 +27,7 @@ import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
@@ -34,14 +35,17 @@ import java.time.MonthDay;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DateFormat;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.springframework.format.number.NumberStyleFormatter;
|
||||
|
||||
@@ -329,7 +333,7 @@ public class JsonParserHelper {
|
||||
return value;
|
||||
}
|
||||
|
||||
public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject element, final String dateFormat,
|
||||
public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject element, String dateFormat,
|
||||
final Locale clientApplicationLocale) {
|
||||
MonthDay value = null;
|
||||
if (element.isJsonObject()) {
|
||||
@@ -342,9 +346,9 @@ public class JsonParserHelper {
|
||||
if (StringUtils.isNotBlank(valueAsString)) {
|
||||
try {
|
||||
final DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient()
|
||||
.appendPattern(dateFormat).toFormatter(clientApplicationLocale);
|
||||
.appendPattern(dateFormat).toFormatter(clientApplicationLocale).withResolverStyle(ResolverStyle.STRICT);
|
||||
value = MonthDay.parse(valueAsString, formatter);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
} catch (final IllegalArgumentException | DateTimeException e) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.month.day",
|
||||
"The parameter `" + parameterName + "` is invalid based on the monthDayFormat: `" + dateFormat
|
||||
@@ -396,7 +400,7 @@ public class JsonParserHelper {
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject object = element.getAsJsonObject();
|
||||
value = extractLocalDateTimeNamed(parameterName, element, extractTimeFormatParameter(object), parametersPassedInCommand);
|
||||
value = extractLocalDateTimeNamed(parameterName, element, extractDateFormatParameter(object), parametersPassedInCommand);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -437,11 +441,11 @@ public class JsonParserHelper {
|
||||
parametersPassedInCommand.add(parameterName);
|
||||
|
||||
try {
|
||||
DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat);
|
||||
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(timeFormat);
|
||||
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
|
||||
timeValueAsString = primitive.getAsString();
|
||||
if (StringUtils.isNotBlank(timeValueAsString)) {
|
||||
value = LocalTime.parse(timeValueAsString, timeFormtter);
|
||||
value = LocalTime.parse(timeValueAsString, timeFormatter);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
@@ -459,28 +463,31 @@ public class JsonParserHelper {
|
||||
return value;
|
||||
}
|
||||
|
||||
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, final String timeFormat,
|
||||
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, String timeFormat,
|
||||
final Locale clientApplicationLocale, final Set<String> parametersPassedInCommand) {
|
||||
LocalDateTime value = null;
|
||||
String timeValueAsString = null;
|
||||
String timeValueAsString;
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject object = element.getAsJsonObject();
|
||||
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
|
||||
parametersPassedInCommand.add(parameterName);
|
||||
|
||||
try {
|
||||
DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat);
|
||||
timeFormat = timeFormat.replace("y", "u");
|
||||
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
|
||||
timeValueAsString = primitive.getAsString();
|
||||
DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient()
|
||||
.appendPattern(timeFormat).toFormatter(clientApplicationLocale).withResolverStyle(ResolverStyle.STRICT);
|
||||
if (StringUtils.isNotBlank(timeValueAsString)) {
|
||||
value = LocalDateTime.parse(timeValueAsString, timeFormtter);
|
||||
value = LocalDateTime.parse(timeValueAsString, timeFormatter);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (IllegalArgumentException | DateTimeParseException e) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final String defaultMessage = new StringBuilder("The parameter `" + timeValueAsString + "` is not in correct format.")
|
||||
.toString();
|
||||
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.TimeFormat", defaultMessage,
|
||||
parameterName);
|
||||
final ApiParameterError error = ApiParameterError
|
||||
.parameterError("validation.msg.invalid.dateFormat.format",
|
||||
"The parameter `" + parameterName + "` is invalid based on the dateFormat: `" + timeFormat
|
||||
+ "` and locale: `" + clientApplicationLocale + "` provided:",
|
||||
parameterName, value, timeFormat);
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors, e);
|
||||
@@ -518,17 +525,27 @@ public class JsonParserHelper {
|
||||
return convertDateTimeFrom(dateAsString, parameterName, dateFormat, clientApplicationLocale).toLocalDate();
|
||||
}
|
||||
|
||||
public static LocalDateTime convertDateTimeFrom(final String dateTimeAsString, final String parameterName, final String dateTimeFormat,
|
||||
public static LocalDate convertFrom(final String dateAsString, final String parameterName, final DateFormat dateFormat,
|
||||
final Locale clientApplicationLocale) {
|
||||
|
||||
String rawDateFormat = Objects.isNull(dateFormat) ? null : dateFormat.getDateFormat();
|
||||
|
||||
return convertDateTimeFrom(dateAsString, parameterName, rawDateFormat, clientApplicationLocale).toLocalDate();
|
||||
}
|
||||
|
||||
public static LocalDateTime convertDateTimeFrom(final String dateTimeAsString, final String parameterName, String dateTimeFormat,
|
||||
final Locale clientApplicationLocale) {
|
||||
|
||||
validateDateFormatAndLocale(parameterName, dateTimeFormat, clientApplicationLocale);
|
||||
LocalDateTime eventLocalDateTime = null;
|
||||
if (StringUtils.isNotBlank(dateTimeAsString)) {
|
||||
try {
|
||||
dateTimeFormat = dateTimeFormat.replace("y", "u");
|
||||
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient()
|
||||
.appendPattern(dateTimeFormat).optionalStart().appendPattern(" HH:mm:ss").optionalEnd()
|
||||
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
|
||||
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter(clientApplicationLocale);
|
||||
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter(clientApplicationLocale)
|
||||
.withResolverStyle(ResolverStyle.STRICT);
|
||||
eventLocalDateTime = LocalDateTime.parse(dateTimeAsString, formatter);
|
||||
} catch (final IllegalArgumentException | DateTimeParseException e) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
|
||||
Reference in New Issue
Block a user