nbbrd.io.text.Parser Maven / Gradle / Ivy
/*
* Copyright 2013 National Bank of Belgium
*
* Licensed under the EUPL, Version 1.1 or – as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package nbbrd.io.text;
import internal.io.text.InternalParser;
import lombok.NonNull;
import nbbrd.design.StaticFactoryMethod;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalQuery;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.stream.Stream;
/**
* Defines a class that creates an object from a {@link CharSequence}.
For
* example, you could use it to parse a String into a Date. Note that it can
* also be used to convert a String to a new one.
The parser must not throw
* Exceptions; it must swallow it and return {@code null}. This means that
* {@code null} is not considered has a value (same as Collection API). To
* create a "null value" from a parser, you should use the NullObject pattern.
*
* @param The type of the object to be created
* @author Philippe Charles
* @see Formatter
*/
@FunctionalInterface
public interface Parser {
/**
* Parse a CharSequence to create an object.
*
* @param input the input used to create the object
* @return a new object if possible, {@code null} otherwise
*/
@Nullable T parse(@Nullable CharSequence input);
/**
* Returns an {@link Optional} containing the object that has been created
* by the parsing if this parsing was possible.
* Use this instead of {@link #parse(java.lang.CharSequence)} to increase
* readability and prevent NullPointerExceptions.
*
* @param input the input used to create the object
* @return a never-null {@link Optional}
*/
default @NonNull Optional parseValue(@Nullable CharSequence input) {
return Optional.ofNullable(parse(input));
}
/**
* @param other
* @return
*/
default @NonNull Parser orElse(@NonNull Parser other) {
return o -> {
T result = parse(o);
return result != null ? result : other.parse(o);
};
}
default @NonNull Parser andThen(@NonNull Function super T, ? extends X> after) {
return o -> after.apply(parse(o));
}
@SuppressWarnings("unchecked")
@StaticFactoryMethod
static @NonNull Parser onDateTimeFormatter(@NonNull DateTimeFormatter formatter, @NonNull TemporalQuery... queries) {
return o -> InternalParser.parseTemporalAccessor(formatter, queries, o);
}
@StaticFactoryMethod
static @NonNull Parser onDateFormat(@NonNull DateFormat dateFormat) {
return o -> InternalParser.parseDate(dateFormat, o);
}
@StaticFactoryMethod
static @NonNull Parser onNumberFormat(@NonNull NumberFormat numberFormat) {
return o -> InternalParser.parseNumber(numberFormat, o);
}
@StaticFactoryMethod
static @NonNull Parser onConstant(@Nullable T instance) {
return o -> InternalParser.parseConstant(instance, o);
}
@StaticFactoryMethod
static @NonNull Parser onNull() {
return InternalParser::parseNull;
}
@StaticFactoryMethod
static @NonNull Parser onFile() {
return InternalParser::parseFile;
}
/**
* Create a {@link Parser} that delegates its parsing to
* {@link Integer#valueOf(java.lang.String)}.
*
* @return a non-null parser
*/
@StaticFactoryMethod
static @NonNull Parser onInteger() {
return InternalParser::parseInteger;
}
@StaticFactoryMethod
static @NonNull Parser onLong() {
return InternalParser::parseLong;
}
/**
* Create a {@link Parser} that delegates its parsing to
* {@link Double#valueOf(java.lang.String)}.
*
* @return a non-null parser
*/
@StaticFactoryMethod
static @NonNull Parser onDouble() {
return InternalParser::parseDouble;
}
@StaticFactoryMethod
static @NonNull Parser onBoolean() {
return InternalParser::parseBoolean;
}
@StaticFactoryMethod
static @NonNull Parser onCharacter() {
return InternalParser::parseCharacter;
}
@StaticFactoryMethod
static @NonNull Parser onCharset() {
return InternalParser::parseCharset;
}
@StaticFactoryMethod
static > @NonNull Parser onEnum(@NonNull Class type) {
return o -> InternalParser.parseEnum(type, o);
}
@StaticFactoryMethod
static > @NonNull Parser onEnum(@NonNull Class type, @NonNull ToIntFunction function) {
final T[] values = type.getEnumConstants();
return onInteger().andThen(code -> InternalParser.parse(values, function, code));
}
@StaticFactoryMethod
static @NonNull Parser onString() {
return InternalParser::parseString;
}
@StaticFactoryMethod
static @NonNull Parser onDoubleArray() {
return InternalParser::parseDoubleArray;
}
@StaticFactoryMethod
static @NonNull Parser onStringArray() {
return InternalParser::parseStringArray;
}
@StaticFactoryMethod
static @NonNull Parser> onStringList(@NonNull Function> splitter) {
return o -> InternalParser.parseStringList(splitter, o);
}
@StaticFactoryMethod
static @NonNull Parser onLocale() {
return InternalParser::parseLocale;
}
@StaticFactoryMethod
static @NonNull Parser onURL() {
return InternalParser::parseURL;
}
@StaticFactoryMethod
static @NonNull Parser onURI() {
return InternalParser::parseURI;
}
@StaticFactoryMethod
static @NonNull Parser of(@NonNull Function super CharSequence, ? extends T> parser, @NonNull Consumer super Throwable> onError) {
return o -> InternalParser.parseFailsafe(parser, onError, o);
}
@StaticFactoryMethod
static @NonNull Parser of(@NonNull Function super CharSequence, ? extends T> parser) {
return of(parser, InternalParser::doNothing);
}
}