Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.convert;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
/**
* A standard set of {@link Period} units.
*
* @author Eddú Meléndez
* @author Edson Chávez
* @author Valentine Wu
* @since 2.3.0
* @see Period
*/
public enum PeriodStyle {
/**
* Simple formatting, for example '1d'.
*/
SIMPLE("^" + "(?:([-+]?[0-9]+)Y)?" + "(?:([-+]?[0-9]+)M)?" + "(?:([-+]?[0-9]+)W)?" + "(?:([-+]?[0-9]+)D)?" + "$",
Pattern.CASE_INSENSITIVE) {
@Override
public Period parse(String value, ChronoUnit unit) {
try {
if (NUMERIC.matcher(value).matches()) {
return Unit.fromChronoUnit(unit).parse(value);
}
Matcher matcher = matcher(value);
Assert.state(matcher.matches(), "Does not match simple period pattern");
Assert.isTrue(hasAtLeastOneGroupValue(matcher), () -> "'" + value + "' is not a valid simple period");
int years = parseInt(matcher, 1);
int months = parseInt(matcher, 2);
int weeks = parseInt(matcher, 3);
int days = parseInt(matcher, 4);
return Period.of(years, months, Math.addExact(Math.multiplyExact(weeks, 7), days));
}
catch (Exception ex) {
throw new IllegalArgumentException("'" + value + "' is not a valid simple period", ex);
}
}
boolean hasAtLeastOneGroupValue(Matcher matcher) {
for (int i = 0; i < matcher.groupCount(); i++) {
if (matcher.group(i + 1) != null) {
return true;
}
}
return false;
}
private int parseInt(Matcher matcher, int group) {
String value = matcher.group(group);
return (value != null) ? Integer.parseInt(value) : 0;
}
@Override
protected boolean matches(String value) {
return NUMERIC.matcher(value).matches() || matcher(value).matches();
}
@Override
public String print(Period value, ChronoUnit unit) {
if (value.isZero()) {
return Unit.fromChronoUnit(unit).print(value);
}
StringBuilder result = new StringBuilder();
append(result, value, Unit.YEARS);
append(result, value, Unit.MONTHS);
append(result, value, Unit.DAYS);
return result.toString();
}
private void append(StringBuilder result, Period value, Unit unit) {
if (!unit.isZero(value)) {
result.append(unit.print(value));
}
}
},
/**
* ISO-8601 formatting.
*/
ISO8601("^[+-]?P.*$", Pattern.CASE_INSENSITIVE) {
@Override
public Period parse(String value, ChronoUnit unit) {
try {
return Period.parse(value);
}
catch (Exception ex) {
throw new IllegalArgumentException("'" + value + "' is not a valid ISO-8601 period", ex);
}
}
@Override
public String print(Period value, ChronoUnit unit) {
return value.toString();
}
};
private static final Pattern NUMERIC = Pattern.compile("^[-+]?[0-9]+$");
private final Pattern pattern;
PeriodStyle(String pattern, int flags) {
this.pattern = Pattern.compile(pattern, flags);
}
protected boolean matches(String value) {
return this.pattern.matcher(value).matches();
}
protected final Matcher matcher(String value) {
return this.pattern.matcher(value);
}
/**
* Parse the given value to a Period.
* @param value the value to parse
* @return a period
*/
public Period parse(String value) {
return parse(value, null);
}
/**
* Parse the given value to a period.
* @param value the value to parse
* @param unit the period unit to use if the value doesn't specify one ({@code null}
* will default to d)
* @return a period
*/
public abstract Period parse(String value, ChronoUnit unit);
/**
* Print the specified period.
* @param value the value to print
* @return the printed result
*/
public String print(Period value) {
return print(value, null);
}
/**
* Print the specified period using the given unit.
* @param value the value to print
* @param unit the value to use for printing
* @return the printed result
*/
public abstract String print(Period value, ChronoUnit unit);
/**
* Detect the style then parse the value to return a period.
* @param value the value to parse
* @return the parsed period
* @throws IllegalArgumentException if the value is not a known style or cannot be
* parsed
*/
public static Period detectAndParse(String value) {
return detectAndParse(value, null);
}
/**
* Detect the style then parse the value to return a period.
* @param value the value to parse
* @param unit the period unit to use if the value doesn't specify one ({@code null}
* will default to ms)
* @return the parsed period
* @throws IllegalArgumentException if the value is not a known style or cannot be
* parsed
*/
public static Period detectAndParse(String value, ChronoUnit unit) {
return detect(value).parse(value, unit);
}
/**
* Detect the style from the given source value.
* @param value the source value
* @return the period style
* @throws IllegalArgumentException if the value is not a known style
*/
public static PeriodStyle detect(String value) {
Assert.notNull(value, "Value must not be null");
for (PeriodStyle candidate : values()) {
if (candidate.matches(value)) {
return candidate;
}
}
throw new IllegalArgumentException("'" + value + "' is not a valid period");
}
private enum Unit {
/**
* Days, represented by suffix {@code d}.
*/
DAYS(ChronoUnit.DAYS, "d", Period::getDays, Period::ofDays),
/**
* Weeks, represented by suffix {@code w}.
*/
WEEKS(ChronoUnit.WEEKS, "w", null, Period::ofWeeks),
/**
* Months, represented by suffix {@code m}.
*/
MONTHS(ChronoUnit.MONTHS, "m", Period::getMonths, Period::ofMonths),
/**
* Years, represented by suffix {@code y}.
*/
YEARS(ChronoUnit.YEARS, "y", Period::getYears, Period::ofYears);
private final ChronoUnit chronoUnit;
private final String suffix;
private final Function intValue;
private final Function factory;
Unit(ChronoUnit chronoUnit, String suffix, Function intValue,
Function factory) {
this.chronoUnit = chronoUnit;
this.suffix = suffix;
this.intValue = intValue;
this.factory = factory;
}
private Period parse(String value) {
return this.factory.apply(Integer.parseInt(value));
}
private String print(Period value) {
return intValue(value) + this.suffix;
}
private boolean isZero(Period value) {
return intValue(value) == 0;
}
private int intValue(Period value) {
Assert.notNull(this.intValue, () -> "intValue cannot be extracted from " + this.name());
return this.intValue.apply(value);
}
private static Unit fromChronoUnit(ChronoUnit chronoUnit) {
if (chronoUnit == null) {
return Unit.DAYS;
}
for (Unit candidate : values()) {
if (candidate.chronoUnit == chronoUnit) {
return candidate;
}
}
throw new IllegalArgumentException("Unsupported unit " + chronoUnit);
}
}
}