
ru.progrm_jarvis.javacommons.object.ValueContainer Maven / Gradle / Ivy
package ru.progrm_jarvis.javacommons.object;
import lombok.*;
import lombok.experimental.Delegate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
/**
* A value which may be present (which includes {@code null}) or not-present.
*
* This differs from {@link java.util.Optional} as presence of a {@code null} value
* does not make this value container empty.
*
* @param type of stored value
*/
@SuppressWarnings("PublicInnerClass")
public interface ValueContainer extends Supplier {
/**
* Gets a value container being empty.
*
* @param type of stored value
* @return empty value container
*/
@SuppressWarnings("unchecked")
static @NotNull ValueContainer empty() {
return (ValueContainer) Empty.INSTANCE;
}
/**
* Gets a non-empty value container containing {@code null}.
*
* @param type of stored value
* @return value container containing {@code null}
*/
@SuppressWarnings("unchecked")
static @NotNull ValueContainer ofNull() {
return (ValueContainer) OfNull.INSTANCE;
}
/**
* Gets a non-empty value container containing the specified value.
*
* @param value nullable value stored in the container
* @param type of stored value
* @return non-empty value container containing the specified value
*/
@SuppressWarnings("unchecked")
static @NotNull ValueContainer of(final @Nullable T value) {
return value == null ? (ValueContainer) OfNull.INSTANCE : new Containing<>(value);
}
/**
* Gets a value container containing the specified value or an empty one if the values is {@code null}.
*
* @param value value stored in the container
* @param type of stored value
* @return non-empty value container containing the specified value
* if it is not {@code null} and an empty one otherwise
*/
@SuppressWarnings("unchecked")
static @NotNull ValueContainer nonnullOrEmpty(final @Nullable T value) {
return value == null ? (ValueContainer) Empty.INSTANCE : new Containing<>(value);
}
/**
* Gets the value stored in this value container.
*
* @return stored value if it is {@link #isPresent() present}
*
* @throws EmptyValueException if this value container is empty
*/
@Override
T get();
/**
* Checks whether the object is present ot not.
*
* @return {@code true} if the value is present (might be {@code null}) and {@code false} otherwise
*/
boolean isPresent();
/**
* Gets the value if it is present otherwise using the specified one.
*
* @param value value to use if this value container is empty
* @return this value container's value if it is not empty or the specified value otherwise
*/
@Nullable T orElse(@Nullable T value);
/**
* Gets the value if it is present otherwise using the one got from the specified supplier.
*
* @param defaultValueSupplier supplier to be used for getting the value if this value container is empty
* @return this value container's value if it is not empty or the one got from the supplier otherwise
*/
@Nullable T orElseGet(@NonNull Supplier defaultValueSupplier);
/**
* Gets the value if it is present otherwise throwing an exception.
*
* @param exceptionSupplier supplier to be used for getting the exception if this value container is empty
* @param type of an exception thrown if this value container is empty
* @return this value container's value if it is not empty
*
* @throws X if this value container is empty
*/
@Nullable T orElseThrow(final @NonNull Supplier exceptionSupplier) throws X;
/**
* Gets the value if it is present otherwise throwing an exception.
* Throws {@code X} if this value container is empty.
*
* @param exceptionSupplier supplier to be used for getting the exception if this value container is empty
* @param type of an exception thrown if this value container is empty
* @return this value container's value if it is not empty
*/
@SneakyThrows
default @Nullable T orElseSneakyThrow(final @NonNull Supplier exceptionSupplier) {
return orElseThrow(exceptionSupplier);
}
/**
* Converts this value container into a {@link Result#nullError() null-error result}.
*
* @param type of the result error
* @return {@link Result#success(Object) successful result} containing the value contained by this value container
* if is is {@link #isPresent() present} or a {@link Result#nullError() null-error result} otherwise
*
* @see #asResult(Supplier) alternative with customizable error value
*/
@NotNull Result asResult();
/**
* Converts this value container into a {@link Result}.
*
* @param errorSupplier supplier of the error in case of this value container being empty
* @param type of the result error
* @return {@link Result#success(Object) successful result} containing the value contained by this value container
* if is is {@link #isPresent() present} or an {@link Result#error(Object) error result}
* with the error got by using the specified supplier
*
* @see #asResult() alternative with default (i.e. null) error
*/
@NotNull Result asResult(Supplier errorSupplier);
/**
* Empty value-container.
*
* @param type of stored value
*/
// use identity equals and hashCode
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class Empty implements ValueContainer {
/**
* Singleton instance of this empty {@link ValueContainer value-container}
*/
private static final ValueContainer> INSTANCE = new Empty<>();
@Override
public boolean isPresent() {
return false;
}
@Override
public T get() {
throw new EmptyValueException("There is no value associated with this value container");
}
@Override
public @Nullable T orElse(final @Nullable T value) {
return value;
}
@Override
public @Nullable T orElseGet(final @NonNull Supplier defaultValueSupplier) {
return defaultValueSupplier.get();
}
@Override
public @Nullable T orElseThrow(final @NonNull Supplier exceptionSupplier) throws X {
throw exceptionSupplier.get();
}
@Override
public @NotNull Result asResult() {
return Result.nullError();
}
@Override
public @NotNull Result asResult(final Supplier errorSupplier) {
return Result.error(errorSupplier.get());
}
@Override
public String toString() {
return "Empty ValueContainer";
}
}
/**
* Non-empty value-container containing {@code null}.
*
* @param type of stored value
*/
// use identity equals and hashCode
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class OfNull implements ValueContainer {
/**
* Singleton instance of this {@link ValueContainer value-container} containing {@code null}
*/
private static final ValueContainer> INSTANCE = new OfNull<>();
@Override
public boolean isPresent() {
return true;
}
@Override
public T get() {
return null;
}
@Override
public @Nullable T orElse(final @Nullable T value) {
return null;
}
@Override
public @Nullable T orElseGet(final @NonNull Supplier defaultValueSupplier) {
return null;
}
@Override
public @Nullable T orElseThrow(final @NonNull Supplier exceptionSupplier) {
return null;
}
@Override
public @NotNull Result asResult() {
return Result.nullSuccess();
}
@Override
public @NotNull Result asResult(final Supplier errorSupplier) {
return Result.nullSuccess();
}
@Override
public String toString() {
return "ValueContainer{null}";
}
}
/**
* A simple value-container which is meant to keep one unchanged value.
*
* @param type of stored value
*/
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Containing implements ValueContainer {
/**
* Value stored by this value container
*/
@NonNull T value;
@Override
public boolean isPresent() {
return true;
}
@Override
public T get() {
return value;
}
@Override
public @Nullable T orElse(final @Nullable T value) {
return value;
}
@Override
public @Nullable T orElseGet(final @NonNull Supplier defaultValueSupplier) {
return value;
}
@Override
public @Nullable T orElseThrow(final @NonNull Supplier exceptionSupplier) {
return value;
}
@Override
public @NotNull Result asResult() {
return Result.success(value);
}
@Override
public @NotNull Result asResult(final Supplier errorSupplier) {
return Result.success(value);
}
}
/**
* Value-container which provides new values for each request.
*
* @param type of stored value
*/
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Supplying implements ValueContainer {
/**
* Supplier responsible for supplying new values on each value request
*/
@Getter(AccessLevel.NONE) @Delegate @NotNull Supplier valueSupplier;
@Override
public boolean isPresent() {
return true;
}
@Override
public @Nullable T orElse(final @Nullable T value) {
return valueSupplier.get();
}
@Override
public @Nullable T orElseGet(final @NonNull Supplier defaultValueSupplier) {
return valueSupplier.get();
}
@Override
public @Nullable T orElseThrow(final @NonNull Supplier exceptionSupplier) {
return valueSupplier.get();
}
@Override
public @NotNull Result asResult() {
return Result.success(valueSupplier.get());
}
@Override
public @NotNull Result asResult(final Supplier errorSupplier) {
return Result.success(valueSupplier.get());
}
}
/**
* An exception thrown whenever {@link #get()} is called on an empty value container.
*/
@NoArgsConstructor
@SuppressWarnings("PublicConstructor")
class EmptyValueException extends RuntimeException {
//
/**
* Constructs a new exception with the specified message.
*
* @param message message describing the exception cause
*/
public EmptyValueException(final String message) {
super(message);
}
/**
* Constructs a new exception with the specified message and cause.
*
* @param message message describing the exception cause
* @param cause cause of this exception
*/
public EmptyValueException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause cause of this exception
*/
public EmptyValueException(final Throwable cause) {
super(cause);
}
/**
* Constructs a new exception with the specified message and cause.
*
* @param message message describing the exception cause
* @param cause cause of this exception
* @param enableSuppression flag indicating whether or not suppression
* is enabled or disabled for this exception
* @param writableStackTrace flag indicating whether or not not the stack trace
* should be writable for this exception
*/
public EmptyValueException(final String message, final Throwable cause, final boolean enableSuppression,
final boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
//
}
}